git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Michael Haggerty <mhagger@alum.mit.edu>
To: Jeff King <peff@peff.net>
Cc: "Junio C Hamano" <gitster@pobox.com>,
	"David Turner" <dturner@twopensource.com>,
	git@vger.kernel.org, "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>,
	"Ramsay Jones" <ramsay@ramsayjones.plus.com>
Subject: Re: [PATCH 19/29] refs: don't dereference on rename
Date: Fri, 29 Apr 2016 15:55:00 +0200	[thread overview]
Message-ID: <572367B4.4050207@alum.mit.edu> (raw)
In-Reply-To: <20160429121228.GA27952@sigill.intra.peff.net>

On 04/29/2016 02:12 PM, Jeff King wrote:
> On Fri, Apr 29, 2016 at 12:57:29PM +0200, Michael Haggerty wrote:
> 
>> Remember, we're talking about rename_ref() only, not reference deletion
>> in general. rename_ref() is not very robust anyway--it doesn't happen in
>> a single transaction, and it is vulnerable to being defeated by
>> simultaneous reference updates by other processes. It *does* wrap the
>> deletion of newrefname in a transaction; the only question is whether an
>> old_sha1 is supplied to that transaction.
>>
>> So, suppose that newrefname starts at value A, and there are two updates
>> running simultaneously:
>>
>> 1. An update of reference newrefname from A -> B
>>
>> 2. A rename of reference oldrefname to newrefname, which includes
>>    a. read_ref_full("newrefname") and
>>    b. delete_ref("newrefname").
> 
> I wondered at first if you meant "oldrefname" in 2b. That is, a rename
> would involve writing to "newrefname" and then deleting "oldrefname",
> and not doing the old_sha1 and normal locking on the deletion of
> oldrefname would be bad (in case somebody else updated it while we were
> operating).
> 
> But reading the patch again, that's not what's going on. You're talking
> just about the case where we force-overwrite an existing newrefname, and
> delete it first to do so. But what I don't understand is:

It's beyond the ambition of this patch to fix this old rename_ref()
code, but...

>   1. Why do we read_ref_full() at all? Since it is not done under lock
>      anyway, it is useless for helping with race conditions, and I think
>      that is what you are arguing (that we should just be deleting
>      regardless). But then why not just call delete_ref(), and handle
>      the ENOENT case as a noop (which closes another race if somebody
>      deletes it between your 2a and 2b).

I thought about that too, and agree it would be an improvement. But it's
not quite so trivial. The ENOENT doesn't make it out of delete_ref()
(which does a full-fledged ref_transaction internally). The error is
only reported via "strbuf *err".

>   2. Why delete it at all? The point is to overwrite, so I guess it is
>      trying to make room. But we could just rename the loose ref file
>      and reflog overtop the old, couldn't we?
>
> Or am I totally misreading the purpose of this code?

I wouldn't want to just rename the files, because (1) I think it is
better to use the existing ref_transaction code, and (2) that wouldn't
work if there is a D/F conflict between the old and new reference names,
which the existing code handles (though honestly I'm skeptical that it
comes up a lot).

It would be more plausible to use ref_transaction_update() to write
oldrefname's *value* on top of newrefname without actually moving the
file. oldrefname could even be deleted in the same transaction, if you
were willing to stop supporting old/new refnames that D/F conflict with
each other. But we also want to move the reflog, and that should be done
while the newrefname lock and (contrary to the current code) also the
oldrefname lock are held. There's currently no way to slip an arbitrary
action like that into the middle of a transaction.

If I had lots of time and interest to work on this, I think the best
approach would be to add a ref_transaction_rename(), which takes an old
and a new reference name as arguments, and adds a whole rename operation
(including of the reflog) to a transaction. This could probably be
implemented by adding one ref_update() and one ref_delete(), and using
the parent_update pointer that is introduced later to link the two so
that ref_transaction_commit() knows to move the reflog too.

If you were willing to punt on D/F conflicts, you would be done. If not,
then it would be better to teach ref_transaction_commit() to deal with
D/F conflicts in the general case rather than using special-purpose code
in rename_ref().

Then rename_ref() could be omitted from the vtable entirely.

Michael

  reply	other threads:[~2016-04-29 13:55 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-27 16:57 [PATCH 00/29] Yet more preparation for reference backends Michael Haggerty
2016-04-27 16:57 ` [PATCH 01/29] safe_create_leading_directories(): improve docstring Michael Haggerty
2016-04-27 16:57 ` [PATCH 02/29] remove_dir_recursively(): add docstring Michael Haggerty
2016-04-27 16:57 ` [PATCH 03/29] refname_is_safe(): use skip_prefix() Michael Haggerty
2016-04-27 16:57 ` [PATCH 04/29] refname_is_safe(): don't allow the empty string Michael Haggerty
2016-04-27 16:57 ` [PATCH 05/29] refname_is_safe(): insist that the refname already be normalized Michael Haggerty
2016-04-27 17:59   ` Junio C Hamano
2016-04-27 20:10     ` David Turner
2016-04-27 20:15       ` Jeff King
2016-04-27 20:34         ` David Turner
2016-04-27 20:37           ` Jeff King
2016-04-27 22:19             ` Jeff King
2016-04-28 17:44             ` David Turner
2016-04-27 16:57 ` [PATCH 06/29] commit_ref_update(): write error message to *err, not stderr Michael Haggerty
2016-04-27 16:57 ` [PATCH 07/29] rename_ref(): remove unneeded local variable Michael Haggerty
2016-04-27 16:57 ` [PATCH 08/29] ref_transaction_commit(): remove local variable n Michael Haggerty
2016-04-27 18:16   ` Junio C Hamano
2016-04-27 20:45     ` Junio C Hamano
2016-04-27 16:57 ` [PATCH 09/29] read_raw_ref(): rename flags argument to type Michael Haggerty
2016-04-27 16:57 ` [PATCH 10/29] read_raw_ref(): clear *type at start of function Michael Haggerty
2016-04-27 16:57 ` [PATCH 11/29] read_raw_ref(): rename symref argument to referent Michael Haggerty
2016-04-27 16:57 ` [PATCH 12/29] read_raw_ref(): improve docstring Michael Haggerty
2016-04-27 18:31   ` Junio C Hamano
2016-04-27 16:57 ` [PATCH 13/29] lock_ref_sha1_basic(): remove unneeded local variable Michael Haggerty
2016-04-27 16:57 ` [PATCH 14/29] refs: make error messages more consistent Michael Haggerty
2016-04-27 16:57 ` [PATCH 15/29] ref_transaction_create(): disallow recursive pruning Michael Haggerty
2016-04-27 18:47   ` Junio C Hamano
2016-04-27 20:23     ` David Turner
2016-04-27 20:45       ` Junio C Hamano
2016-04-27 21:15         ` Junio C Hamano
2016-04-28 17:48           ` David Turner
2016-04-28 20:15             ` Junio C Hamano
2016-04-29  6:56           ` Michael Haggerty
2016-04-29  8:19             ` Junio C Hamano
2016-04-29  8:41             ` Junio C Hamano
2016-04-29 14:29               ` Michael Haggerty
2016-04-27 16:57 ` [PATCH 16/29] ref_transaction_commit(): correctly report close_ref() failure Michael Haggerty
2016-04-27 16:57 ` [PATCH 17/29] delete_branches(): use resolve_refdup() Michael Haggerty
2016-04-27 16:57 ` [PATCH 18/29] refs: allow log-only updates Michael Haggerty
2016-04-27 16:57 ` [PATCH 19/29] refs: don't dereference on rename Michael Haggerty
2016-04-27 18:55   ` Junio C Hamano
2016-04-29  7:38     ` Michael Haggerty
2016-04-29  8:53       ` Junio C Hamano
2016-04-29 10:57         ` Michael Haggerty
2016-04-29 12:12           ` Jeff King
2016-04-29 13:55             ` Michael Haggerty [this message]
2016-04-29 14:08               ` Jeff King
2016-04-29 15:29               ` Junio C Hamano
2016-04-29 23:21       ` David Turner
2016-04-30  3:48         ` Michael Haggerty
2016-05-02 17:55           ` Junio C Hamano
2016-04-27 16:57 ` [PATCH 20/29] verify_refname_available(): adjust constness in declaration Michael Haggerty
2016-04-27 16:57 ` [PATCH 21/29] add_update(): initialize the whole ref_update Michael Haggerty
2016-04-27 16:57 ` [PATCH 22/29] lock_ref_for_update(): new function Michael Haggerty
2016-04-27 16:57 ` [PATCH 23/29] unlock_ref(): move definition higher in the file Michael Haggerty
2016-04-27 16:57 ` [PATCH 24/29] ref_transaction_update(): check refname_is_safe() at a minimum Michael Haggerty
2016-04-27 20:14   ` Junio C Hamano
2016-04-29  7:42     ` Michael Haggerty
2016-04-29  8:53       ` Junio C Hamano
2016-04-27 16:57 ` [PATCH 25/29] refs: resolve symbolic refs first Michael Haggerty
2016-04-28 23:40   ` David Turner
2016-04-29  9:51     ` Michael Haggerty
2016-04-29 23:14       ` David Turner
2016-05-02 18:06     ` Junio C Hamano
2016-04-27 16:57 ` [PATCH 26/29] lock_ref_for_update(): don't re-read non-symbolic references Michael Haggerty
2016-04-27 16:57 ` [PATCH 27/29] lock_ref_for_update(): don't resolve symrefs Michael Haggerty
2016-04-27 16:57 ` [PATCH 28/29] commit_ref_update(): remove the flags parameter Michael Haggerty
2016-04-27 16:57 ` [PATCH 29/29] lock_ref_sha1_basic(): only handle REF_NODEREF mode Michael Haggerty
2016-04-29 15:43   ` Junio C Hamano
2016-04-29  1:14 ` [PATCH 00/29] Yet more preparation for reference backends David Turner

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=572367B4.4050207@alum.mit.edu \
    --to=mhagger@alum.mit.edu \
    --cc=dturner@twopensource.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=pclouds@gmail.com \
    --cc=peff@peff.net \
    --cc=ramsay@ramsayjones.plus.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).