9dd330e6ca
There's a bug in builtin/am.c in which we take a lock on MERGE_RR recursively. But rather than fix am.c, this patch fixes the confusing interface from rerere.c that caused the bug. Read on for the gory details. The setup_rerere() function both reads the existing MERGE_RR file, and takes MERGE_RR.lock. In the rerere() and rerere_forget() functions, we end up in write_rr(), which will then commit the lock file. But for functions like rerere_clear() that do not write to MERGE_RR, we expect the caller to have handled setup_rerere(). That caller would then need to release the lockfile, but it can't; the lock struct is local to rerere.c. For builtin/rerere.c, this is OK. We run a single rerere operation and then exit immediately, which has the side effect of rolling back the lockfile. But in builtin/am.c, this is actively wrong. If we run "git am -3 --skip", we call setup-rerere twice without releasing the lock: 1. The "--skip" causes us to call am_rerere_clear(), which calls setup_rerere(), but never drops the lock. 2. We then proceed to the next patch. 3. The "--3way" may cause us to call rerere() to handle conflicts in that patch, but we are already holding the lock. The lockfile code dies with: BUG: prepare_tempfile_object called for active object We could fix this by having rerere_clear() call rollback_lock_file(). But it feels a bit odd for it to roll back a lockfile that it did not itself take. So let's simplify the interface further, and handle setup_rerere in the function itself, taking away the question from the caller over whether they need to do so. We can give rerere_gc() the same treatment, as well (even though it doesn't have any callers besides builtin/rerere.c at this point). Note that these functions don't take flags from their callers to pass along to setup_rerere; that's OK, because the flags would not be meaningful for what they are doing. Both of those functions need to hold the lock because even though they do not write to MERGE_RR, they are still writing and should be protected from a simultaneous "rerere" run. But rerere_remaining(), "rerere diff", and "rerere status" are all read-only operations. They want to setup_rerere(), but do not care about taking the lock in the first place. Since our update of MERGE_RR is the usual atomic rename done by commit_lock_file, they can just do a lockless read. For that, we teach setup_rerere a READONLY flag to avoid the lock. As a bonus, this pushes builtin/rerere.c's setup_rerere call closer to the functions that use it. Which means that "git rerere totally-bogus-command" will no longer silently exit(0) in a repository without rerere enabled. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> |
||
---|---|---|
.. | ||
add.c | ||
am.c | ||
annotate.c | ||
apply.c | ||
archive.c | ||
bisect--helper.c | ||
blame.c | ||
branch.c | ||
bundle.c | ||
cat-file.c | ||
check-attr.c | ||
check-ignore.c | ||
check-mailmap.c | ||
check-ref-format.c | ||
checkout-index.c | ||
checkout.c | ||
clean.c | ||
clone.c | ||
column.c | ||
commit-tree.c | ||
commit.c | ||
config.c | ||
count-objects.c | ||
credential.c | ||
describe.c | ||
diff-files.c | ||
diff-index.c | ||
diff-tree.c | ||
diff.c | ||
fast-export.c | ||
fetch-pack.c | ||
fetch.c | ||
fmt-merge-msg.c | ||
for-each-ref.c | ||
fsck.c | ||
gc.c | ||
get-tar-commit-id.c | ||
grep.c | ||
hash-object.c | ||
help.c | ||
index-pack.c | ||
init-db.c | ||
interpret-trailers.c | ||
log.c | ||
ls-files.c | ||
ls-remote.c | ||
ls-tree.c | ||
mailinfo.c | ||
mailsplit.c | ||
merge-base.c | ||
merge-file.c | ||
merge-index.c | ||
merge-ours.c | ||
merge-recursive.c | ||
merge-tree.c | ||
merge.c | ||
mktag.c | ||
mktree.c | ||
mv.c | ||
name-rev.c | ||
notes.c | ||
pack-objects.c | ||
pack-redundant.c | ||
pack-refs.c | ||
patch-id.c | ||
prune-packed.c | ||
prune.c | ||
pull.c | ||
push.c | ||
read-tree.c | ||
receive-pack.c | ||
reflog.c | ||
remote-ext.c | ||
remote-fd.c | ||
remote.c | ||
repack.c | ||
replace.c | ||
rerere.c | ||
reset.c | ||
rev-list.c | ||
rev-parse.c | ||
revert.c | ||
rm.c | ||
send-pack.c | ||
shortlog.c | ||
show-branch.c | ||
show-ref.c | ||
stripspace.c | ||
symbolic-ref.c | ||
tag.c | ||
unpack-file.c | ||
unpack-objects.c | ||
update-index.c | ||
update-ref.c | ||
update-server-info.c | ||
upload-archive.c | ||
var.c | ||
verify-commit.c | ||
verify-pack.c | ||
verify-tag.c | ||
worktree.c | ||
write-tree.c |