Yiannis Marangos <yiannis.maran...@gmail.com> writes:

> Before we proceed to "opportunistic update" we must verify that the
> current index file is the same as the one that we read before. There
> is a possible race if we don't do this:

Please somehow make it clear that the race is in general, and use of
"git rebase" in this description is merely an example.

>   1. process A calls git-rebase

... or does anything that uses the index.

>   2. process A applies 1st commit
>
>   3. process B calls git-status
>
>   4. process B reads index
>
>   5. process A applies 2nd commit

... or does anything that updates the index.

>   6. process B takes the lock, then overwrites process A's changes.
>
>   7. process A applies 3rd commit
>
> As an end result the 3rd commit will have a revert of the 2nd commit.

And the missing piece is...?  "When process B takes the lock, it
needs to make sure that the index hasn't changed since it read at
step 4."

> Signed-off-by: Yiannis Marangos <yiannis.maran...@gmail.com>
> ---

This is a place for you to describe how this version is different
from the previous round.  I am guessing that the only change is that
you removed the unnecessary printf() from the top of if-able, but I
didn't compare (nor read either versions carefully).

>  cache.h      |  3 +++
>  read-cache.c | 77 
> +++++++++++++++++++++++++++++++++++++++++++++++++++---------
>  2 files changed, 69 insertions(+), 11 deletions(-)
>
> diff --git a/cache.h b/cache.h
> index 107ac61..b0eedad 100644
> --- a/cache.h
> +++ b/cache.h
> @@ -279,6 +279,7 @@ struct index_state {
>                initialized : 1;
>       struct hashmap name_hash;
>       struct hashmap dir_hash;
> +     unsigned char sha1[20];
>  };
>  
>  extern struct index_state the_index;
> @@ -456,6 +457,8 @@ extern int daemonize(void);
>       } while (0)
>  
>  /* Initialize and use the cache information */
> +extern int verify_index_from(const struct index_state *, const char *path);
> +extern int verify_index(struct index_state *);

I do not think these should be extern; they are implementation
details of the opportunistic update, and update-if-able is the only
thing the outside world needs to know about, I think.

>  extern int read_index(struct index_state *);
>  extern int read_index_preload(struct index_state *, const struct pathspec 
> *pathspec);
>  extern int read_index_from(struct index_state *, const char *path);
> diff --git a/read-cache.c b/read-cache.c
> index ba13353..a49a441 100644
> --- a/read-cache.c
> +++ b/read-cache.c
> @@ -14,6 +14,7 @@
>  #include "resolve-undo.h"
>  #include "strbuf.h"
>  #include "varint.h"
> +#include "git-compat-util.h"

An unnecessary change; we include "cache.h" as the very first thing
in this file.

> @@ -1321,6 +1322,59 @@ static int verify_hdr(struct cache_header *hdr, 
> unsigned long size)
>       return 0;
>  }
>  
> +/* This function verifies if index_state has the correct sha1 of an index 
> file.
> + * Don't die if we have any other failure, just return 0. */

        /*
         * Please write multi-line comment
         * like this.
         */

> +int verify_index_from(const struct index_state *istate, const char *path)
> +{

Also, this does not have to be extern.  At least not yet.

> +     int fd;
> +     struct stat st;
> +     struct cache_header *hdr;
> +     void *mmap_addr;
> +     size_t mmap_size;
> +
> +     if (!istate->initialized)
> +             return 0;
> +
> +     fd = open(path, O_RDONLY);
> +     if (fd < 0)
> +             return 0;
> +
> +     if (fstat(fd, &st))
> +             return 0;
> +
> +     /* file is too big */
> +     if (st.st_size > (size_t)st.st_size)
> +             return 0;
> +
> +     mmap_size = (size_t)st.st_size;
> +     if (mmap_size < sizeof(struct cache_header) + 20)
> +             return 0;
> +
> +     mmap_addr = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, 
> fd, 0);

Why PROT_WRITE?

> +     close(fd);
> +     if (mmap_addr == MAP_FAILED)
> +             return 0;
> +
> +     hdr = mmap_addr;
> +     if (verify_hdr(hdr, mmap_size) < 0)
> +             goto unmap;
> +
> +     if (hashcmp(istate->sha1, (unsigned char *)hdr + mmap_size - 20))
> +             goto unmap;
> +
> +     munmap(mmap_addr, mmap_size);
> +     return 1;
> +
> +unmap:
> +     munmap(mmap_addr, mmap_size);
> +     return 0;
> +}
> +
> +int verify_index(struct index_state *istate)
> +{
> +     return verify_index_from(istate, get_index_file());
> +}
> +
>  static int read_index_extension(struct index_state *istate,
>                               const char *ext, void *data, unsigned long sz)
>  {
> @@ -1445,7 +1499,7 @@ int read_index_from(struct index_state *istate, const 
> char *path)
>       struct stat st;
>       unsigned long src_offset;
>       struct cache_header *hdr;
> -     void *mmap;
> +     void *mmap_addr;

This introduces noise to the patch to make it harder to review, and
does not look a necessary change.  Am I mistaken?

>       size_t mmap_size;
>       struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
>  
> @@ -1468,15 +1522,16 @@ int read_index_from(struct index_state *istate, const 
> char *path)
>       if (mmap_size < sizeof(struct cache_header) + 20)
>               die("index file smaller than expected");
>  
> -     mmap = xmmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 
> 0);
> -     if (mmap == MAP_FAILED)
> +     mmap_addr = xmmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, 
> fd, 0);
> +     if (mmap_addr == MAP_FAILED)
>               die_errno("unable to map index file");
>       close(fd);
>  
> -     hdr = mmap;
> +     hdr = mmap_addr;
>       if (verify_hdr(hdr, mmap_size) < 0)
>               goto unmap;
>  
> +     hashcpy(istate->sha1, (unsigned char *)hdr + mmap_size - 20);
>       istate->version = ntohl(hdr->hdr_version);
>       istate->cache_nr = ntohl(hdr->hdr_entries);
>       istate->cache_alloc = alloc_nr(istate->cache_nr);
> @@ -1494,7 +1549,7 @@ int read_index_from(struct index_state *istate, const 
> char *path)
>               struct cache_entry *ce;
>               unsigned long consumed;
>  
> -             disk_ce = (struct ondisk_cache_entry *)((char *)mmap + 
> src_offset);
> +             disk_ce = (struct ondisk_cache_entry *)((char *)mmap_addr + 
> src_offset);
>               ce = create_from_disk(disk_ce, &consumed, previous_name);
>               set_index_entry(istate, i, ce);
>  
> @@ -1512,21 +1567,21 @@ int read_index_from(struct index_state *istate, const 
> char *path)
>                * in 4-byte network byte order.
>                */
>               uint32_t extsize;
> -             memcpy(&extsize, (char *)mmap + src_offset + 4, 4);
> +             memcpy(&extsize, (char *)mmap_addr + src_offset + 4, 4);
>               extsize = ntohl(extsize);
>               if (read_index_extension(istate,
> -                                      (const char *) mmap + src_offset,
> -                                      (char *) mmap + src_offset + 8,
> +                                      (const char *) mmap_addr + src_offset,
> +                                      (char *) mmap_addr + src_offset + 8,
>                                        extsize) < 0)
>                       goto unmap;
>               src_offset += 8;
>               src_offset += extsize;
>       }
> -     munmap(mmap, mmap_size);
> +     munmap(mmap_addr, mmap_size);
>       return istate->cache_nr;
>  
>  unmap:
> -     munmap(mmap, mmap_size);
> +     munmap(mmap_addr, mmap_size);
>       die("index file corrupt");
>  }
>  
> @@ -1779,7 +1834,7 @@ static int has_racy_timestamp(struct index_state 
> *istate)
>  void update_index_if_able(struct index_state *istate, struct lock_file 
> *lockfile)
>  {
>       if ((istate->cache_changed || has_racy_timestamp(istate)) &&
> -         !write_index(istate, lockfile->fd))
> +         verify_index(istate) && !write_index(istate, lockfile->fd))
>               commit_locked_index(lockfile);
>       else
>               rollback_lock_file(lockfile);
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to