git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Torsten Bögershausen" <tboegi@web.de>
To: Junio C Hamano <gitster@pobox.com>,
	Yiannis Marangos <yiannis.marangos@gmail.com>
Cc: git@vger.kernel.org, "Torsten Bögershausen" <tboegi@web.de>
Subject: Re: [PATCH v7 2/2] Verify index file before we opportunistically update it
Date: Fri, 11 Apr 2014 09:47:09 +0200	[thread overview]
Message-ID: <53479DFD.4020702@web.de> (raw)
In-Reply-To: <xmqqppkpvv9m.fsf@gitster.dls.corp.google.com>

On 2014-04-10 21.28, Junio C Hamano wrote:
> Yiannis Marangos <yiannis.marangos@gmail.com> writes:
> 
>> +	n = xpread(fd, sha1, 20, st.st_size - 20);
>> +	if (n != 20)
>> +		goto out;
> 
> I think it is possible for pread(2) to give you a short-read.
> 
> The existing callers of emulated mmap and index-pack are prepared to
> handle a short-read correctly, but I do not think this code does.
> 
> I'll queue this instead in the meantime.
> 
> -- >8 --
> From: Yiannis Marangos <yiannis.marangos@gmail.com>
> Date: Thu, 10 Apr 2014 21:31:21 +0300
> Subject: [PATCH] read-cache.c: verify index file before we opportunistically update it
> 
> Before we proceed to opportunistically update the index (often done
> by an otherwise read-only operation like "git status" and "git diff"
> that internally refreshes the index), we must verify that the
> current index file is the same as the one that we read earlier
> before we took the lock on it, in order to avoid a possible race.
> 
> In the example below git-status does "opportunistic update" and
> git-rebase updates the index, but the race can happen in general.
I'm not sure if we need the second or third commit of process A at all.
My understanding is that the simplified version will have problems as well:

  1. process A calls git-rebase (or does anything that updates the index)
  2. process change
  3. process B calls git-status (or does anything that updates the index)
  4. process B reads the index file into memory
  5. process change
  6. process A applies a commit:
      - read the index into memory
      - take the lock
      - update the index file on disc
      - release the lock
  7. process change
  8. process B applies a commit:
      - take the lock
      - update the index in memory and write the index file to disc
      - release the lock

   Now process B has overwritten the commit from process A, which is wrong.

The new code works like this:

  8. process B applies a commit:
      - take the lock
      - verifies tha the index file on disc has the same sha as the one read before
      # And if not: What do we do? die() or retry() ?
      - update the index file on disc
      - release the lock
[]
> 
> +static int verify_index_from(const struct index_state *istate, const char *path)
> +{
> +	int fd;
> +	ssize_t n;
> +	struct stat st;
> +	unsigned char sha1[20];
> +
> +	if (!istate->initialized)
> +		return 0;
> +
> +	fd = open(path, O_RDONLY);
> +	if (fd < 0)
> +		return 0;
> +
> +	if (fstat(fd, &st))
> +		goto out;
> +
> +	if (st.st_size < sizeof(struct cache_header) + 20)
> +		goto out;
> +
> +	n = pread_in_full(fd, sha1, 20, st.st_size - 20);
Minor :
What is the advantage of pread() against a lseek()/read_in_full() combo?
fd is opened and used only in one thread.
Introducing pread()/ pread_in_full() could be done in an other commit,
or do I miss something ?
> +	if (n != 20)
> +		goto out;

> +static int verify_index(const struct index_state *istate)
> +{
> +	return verify_index_from(istate, get_index_file());
> +}
> +
Minor:
Do we really need the wrapper function verify_index_from()?
It seems as if the whole code from verify_index_from() could go into
verify_index(), which will call get_index_file()
  
 
>  static int has_racy_timestamp(struct index_state *istate)
>  {
>  	int entries = istate->cache_nr;
> @@ -1766,7 +1811,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);
> diff --git a/wrapper.c b/wrapper.c
> index 5b3c7fc..bc1bfb8 100644
> --- a/wrapper.c
> +++ b/wrapper.c
> @@ -232,6 +232,26 @@ ssize_t write_in_full(int fd, const void *buf, size_t count)
>  	return total;
>  }
>  
> +ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset)
> +{
> +	char *p = buf;
> +	ssize_t total = 0;
> +
> +	while (count > 0) {
> +		ssize_t loaded = xpread(fd, p, count, offset);
> +		if (loaded < 0)
> +			return -1;
> +		if (loaded == 0)
> +			return total;
> +		count -= loaded;
> +		p += loaded;
> +		total += loaded;
> +		offset += loaded;
> +	}
> +
> +	return total;
> +}
> +
>  int xdup(int fd)
>  {
>  	int ret = dup(fd);
> 

  parent reply	other threads:[~2014-04-11  7:47 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-04-09 22:06 [PATCH] Verify index file before we opportunistically update it Yiannis Marangos
2014-04-09 22:06 ` Yiannis Marangos
2014-04-09 22:34 ` [PATCH v2] " Yiannis Marangos
2014-04-09 23:05   ` Junio C Hamano
2014-04-09 22:52 ` [PATCH v3] " Yiannis Marangos
2014-04-10  5:22 ` [PATCH v4] " Yiannis Marangos
2014-04-10  5:34 ` [PATCH v5] " Yiannis Marangos
2014-04-10 10:40   ` Duy Nguyen
2014-04-10 11:57     ` Yiannis Marangos
2014-04-10 16:57     ` Junio C Hamano
2014-04-10 13:11 ` [PATCH v6] " Yiannis Marangos
2014-04-10 18:31 ` [PATCH v7 1/2] Add xpread() and xpwrite() Yiannis Marangos
2014-04-10 18:31   ` [PATCH v7 2/2] Verify index file before we opportunistically update it Yiannis Marangos
2014-04-10 19:28     ` Junio C Hamano
2014-04-11  2:57       ` Duy Nguyen
2014-04-11 19:24         ` Junio C Hamano
2014-04-11 20:43           ` Junio C Hamano
2014-04-11 23:30             ` Yiannis Marangos
2014-04-12  0:10             ` Duy Nguyen
2014-04-12  4:19               ` Junio C Hamano
2014-04-12  7:05                 ` Junio C Hamano
2014-04-12 10:13                 ` Duy Nguyen
2014-04-14 18:50                   ` Junio C Hamano
2014-04-11  7:47       ` Torsten Bögershausen [this message]
2014-04-11 15:58         ` Yiannis Marangos
2014-04-11 10:36       ` Duy Nguyen
2014-04-10 18:35   ` [PATCH v7 1/2] Add xpread() and xpwrite() Junio C Hamano
2014-04-10 18:44     ` Yiannis Marangos
2014-04-10 18:54 ` [PATCH v8 1/2] Add xpread() Yiannis Marangos
2014-04-10 19:12   ` Johannes Sixt
2014-04-10 19:20     ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=53479DFD.4020702@web.de \
    --to=tboegi@web.de \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=yiannis.marangos@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).