git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: "Martin Ågren" <martin.agren@gmail.com>
To: git@vger.kernel.org
Cc: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH 11/11] read-cache: roll back lock on error with `COMMIT_LOCK`
Date: Sun,  1 Oct 2017 16:56:12 +0200	[thread overview]
Message-ID: <26a9c90a6478ec9ddb4ce34923e251ebe9323ab2.1506862824.git.martin.agren@gmail.com> (raw)
In-Reply-To: <cover.1506862824.git.martin.agren@gmail.com>

When `write_locked_index(..., lock, COMMIT_LOCK)` returns, the lockfile
might have been neither committed nor rolled back. This happens if the
call to `do_write_index()` early in `do_write_locked_index()` fails, or
if `write_shared_index()` fails.

Some callers obviously do not expect the lock to remain locked. They
simply kick an error up the call stack without rolling back the lock.
They typically have the lock on the stack, so there is now no way of
releasing it. (Some callers actually do roll back the lock, and many
others simply do not care because they are about to die anyway.) Maybe
we don't try to take the lock again within the same process, so this is
not a problem at the time, but if we ever learn to try, we could
deadlock.

We could teach existing callers to roll back where it matters. That
would introduce some boiler-plate code, and future users might
re-introduce the same mistake. After all, it does seem reasonable to
expect that `COMMIT_LOCK` does what `commit_lockfile()` does: commits or
rolls back.

Teach `write_locked_index(..., COMMIT_LOCK)` to roll back the lock
before returning. If we have already succeeded and committed, it will be
a noop. Simplify the existing callers where we now have a superfluous
call to `rollback_lockfile()`. This should keep future readers from
wondering why the callers are inconsistent.

For the users which `die()` if `write_locked_index()` fails, this change
does not bring any benefit. But it also doesn't hurt -- it simply means
we clean up the lockfile in `do_write_locked_index()` instead of in our
custom `atexit(3)` handler.

Out-of-tree callers will be affected by this change, but they will be
getting the locking-behavior that they almost certainly expect.

For the other flag, `CLOSE_LOCK`, leaving the lock as-is on error is
appropriate, since that is how `close_lockfile_gently()` behaves.
(There are not many in-tree users and they all `die()` on error.)

Signed-off-by: Martin Ågren <martin.agren@gmail.com>
---
 builtin/difftool.c |  1 -
 cache.h            |  1 +
 merge.c            |  4 +---
 read-cache.c       | 13 ++++++++-----
 sequencer.c        |  1 -
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/builtin/difftool.c b/builtin/difftool.c
index b2d3ba753..bcc79d188 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -616,7 +616,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 			if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 ||
 			    write_locked_index(&wtindex, &lock, COMMIT_LOCK)) {
 				ret = error("could not write %s", buf.buf);
-				rollback_lock_file(&lock);
 				goto finish;
 			}
 			changed_files(&wt_modified, buf.buf, workdir);
diff --git a/cache.h b/cache.h
index 4d09da792..0da90a545 100644
--- a/cache.h
+++ b/cache.h
@@ -618,6 +618,7 @@ extern int read_index_unmerged(struct index_state *);
  * split index to the lockfile. If the temporary file for the shared
  * index cannot be created, fall back to the normal case.
  *
+ * With `COMMIT_LOCK`, the lock is always committed or rolled back.
  * With `CLOSE_LOCK`, the lock will be neither committed nor rolled back.
  */
 extern int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags);
diff --git a/merge.c b/merge.c
index a18a452b5..e5d796c9f 100644
--- a/merge.c
+++ b/merge.c
@@ -91,9 +91,7 @@ int checkout_fast_forward(const struct object_id *head,
 	}
 	if (unpack_trees(nr_trees, t, &opts))
 		return -1;
-	if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) {
-		rollback_lock_file(&lock_file);
+	if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
 		return error(_("unable to write new index file"));
-	}
 	return 0;
 }
diff --git a/read-cache.c b/read-cache.c
index 8e498e879..53f1941c9 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -2182,9 +2182,8 @@ 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)) &&
-	    verify_index(istate) &&
-	    write_locked_index(istate, lockfile, COMMIT_LOCK))
-		rollback_lock_file(lockfile);
+	    verify_index(istate))
+		write_locked_index(istate, lockfile, COMMIT_LOCK);
 }
 
 static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
@@ -2498,7 +2497,8 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
 	    (istate->cache_changed & ~EXTMASK)) {
 		if (si)
 			hashclr(si->base_sha1);
-		return do_write_locked_index(istate, lock, flags);
+		ret = do_write_locked_index(istate, lock, flags);
+		goto out;
 	}
 
 	if (getenv("GIT_TEST_SPLIT_INDEX")) {
@@ -2514,7 +2514,7 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
 	if (new_shared_index) {
 		ret = write_shared_index(istate, lock, flags);
 		if (ret)
-			return ret;
+			goto out;
 	}
 
 	ret = write_split_index(istate, lock, flags);
@@ -2523,6 +2523,9 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
 	if (!ret && !new_shared_index)
 		freshen_shared_index(sha1_to_hex(si->base_sha1), 1);
 
+out:
+	if (flags & COMMIT_LOCK)
+		rollback_lock_file(lock);
 	return ret;
 }
 
diff --git a/sequencer.c b/sequencer.c
index 60636ce54..d56c38081 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1183,7 +1183,6 @@ static int read_and_refresh_cache(struct replay_opts *opts)
 	refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
 	if (the_index.cache_changed && index_fd >= 0) {
 		if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) {
-			rollback_lock_file(&index_lock);
 			return error(_("git %s: failed to refresh the index"),
 				_(action_name(opts)));
 		}
-- 
2.14.1.727.g9ddaf86


  parent reply	other threads:[~2017-10-01 14:57 UTC|newest]

Thread overview: 69+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-01 14:56 [PATCH 00/11] various lockfile-leaks and -fixes Martin Ågren
2017-10-01 14:56 ` [PATCH 01/11] sha1_file: do not leak `lock_file` Martin Ågren
2017-10-02  5:26   ` Jeff King
2017-10-02 10:15     ` Martin Ågren
2017-10-01 14:56 ` [PATCH 02/11] treewide: prefer lockfiles on the stack Martin Ågren
2017-10-02  3:37   ` Junio C Hamano
2017-10-02  4:12     ` Martin Ågren
2017-10-02  5:34   ` Jeff King
2017-10-01 14:56 ` [PATCH 03/11] lockfile: fix documentation on `close_lock_file_gently()` Martin Ågren
2017-10-02  5:35   ` Jeff King
2017-10-01 14:56 ` [PATCH 04/11] tempfile: fix documentation on `delete_tempfile()` Martin Ågren
2017-10-02  5:38   ` Jeff King
2017-10-01 14:56 ` [PATCH 05/11] cache-tree: simplify locking logic Martin Ågren
2017-10-02  3:40   ` Junio C Hamano
2017-10-02  5:41   ` Jeff King
2017-10-01 14:56 ` [PATCH 06/11] apply: move lockfile into `apply_state` Martin Ågren
2017-10-02  5:48   ` Jeff King
2017-10-01 14:56 ` [PATCH 07/11] apply: remove `newfd` from `struct apply_state` Martin Ågren
2017-10-02  5:50   ` Jeff King
2017-10-01 14:56 ` [PATCH 08/11] cache.h: document `write_locked_index()` Martin Ågren
2017-10-01 14:56 ` [PATCH 09/11] read-cache: require flags for `write_locked_index()` Martin Ågren
2017-10-02  3:49   ` Junio C Hamano
2017-10-02  4:14     ` Martin Ågren
2017-10-02 10:16       ` Martin Ågren
2017-10-02  6:00   ` Jeff King
2017-10-01 14:56 ` [PATCH 10/11] read-cache: don't leave dangling pointer in `do_write_index()` Martin Ågren
2017-10-02  6:15   ` Jeff King
2017-10-02  6:20     ` Jeff King
2017-10-01 14:56 ` Martin Ågren [this message]
2017-10-02  4:01   ` [PATCH 11/11] read-cache: roll back lock on error with `COMMIT_LOCK` Junio C Hamano
2017-10-02  2:37 ` [PATCH 00/11] various lockfile-leaks and -fixes Junio C Hamano
2017-10-02  6:22 ` Jeff King
2017-10-02  6:30   ` Junio C Hamano
2017-10-02 10:19     ` Martin Ågren
2017-10-03  6:21       ` Junio C Hamano
2017-10-05 20:32         ` [PATCH v2 00/12] " Martin Ågren
2017-10-05 20:32           ` [PATCH v2 01/12] sha1_file: do not leak `lock_file` Martin Ågren
2017-10-06  1:17             ` Junio C Hamano
2017-10-05 20:32           ` [PATCH v2 02/12] treewide: prefer lockfiles on the stack Martin Ågren
2017-10-05 20:32           ` [PATCH v2 03/12] lockfile: fix documentation on `close_lock_file_gently()` Martin Ågren
2017-10-05 20:32           ` [PATCH v2 04/12] tempfile: fix documentation on `delete_tempfile()` Martin Ågren
2017-10-05 20:32           ` [PATCH v2 05/12] checkout-index: simplify locking logic Martin Ågren
2017-10-06  1:21             ` Junio C Hamano
2017-10-05 20:32           ` [PATCH v2 06/12] cache-tree: " Martin Ågren
2017-10-05 20:32           ` [PATCH v2 07/12] apply: move lockfile into `apply_state` Martin Ågren
2017-10-05 20:32           ` [PATCH v2 08/12] apply: remove `newfd` from `struct apply_state` Martin Ågren
2017-10-05 20:32           ` [PATCH v2 09/12] cache.h: document `write_locked_index()` Martin Ågren
2017-10-05 20:32           ` [PATCH v2 10/12] read-cache: drop explicit `CLOSE_LOCK`-flag Martin Ågren
2017-10-06  1:39             ` Junio C Hamano
2017-10-06 11:02               ` Martin Ågren
2017-10-05 20:32           ` [PATCH v2 11/12] read-cache: leave lock in right state in `write_locked_index()` Martin Ågren
2017-10-06  2:01             ` Junio C Hamano
2017-10-06 11:04               ` Martin Ågren
2017-10-06 12:02                 ` Junio C Hamano
2017-10-06 19:44                   ` Martin Ågren
2017-10-06 20:12                     ` [PATCH v3 00/12] Re: various lockfile-leaks and -fixes Martin Ågren
2017-10-06 20:12                       ` [PATCH v3 01/12] sha1_file: do not leak `lock_file` Martin Ågren
2017-10-06 20:12                       ` [PATCH v3 02/12] treewide: prefer lockfiles on the stack Martin Ågren
2017-10-06 20:12                       ` [PATCH v3 03/12] lockfile: fix documentation on `close_lock_file_gently()` Martin Ågren
2017-10-06 20:12                       ` [PATCH v3 04/12] tempfile: fix documentation on `delete_tempfile()` Martin Ågren
2017-10-06 20:12                       ` [PATCH v3 05/12] checkout-index: simplify locking logic Martin Ågren
2017-10-06 20:12                       ` [PATCH v3 06/12] cache-tree: " Martin Ågren
2017-10-06 20:12                       ` [PATCH v3 07/12] apply: move lockfile into `apply_state` Martin Ågren
2017-10-06 20:12                       ` [PATCH v3 08/12] apply: remove `newfd` from `struct apply_state` Martin Ågren
2017-10-06 20:12                       ` [PATCH v3 09/12] cache.h: document `write_locked_index()` Martin Ågren
2017-10-06 20:12                       ` [PATCH v3 10/12] read-cache: drop explicit `CLOSE_LOCK`-flag Martin Ågren
2017-10-06 20:12                       ` [PATCH v3 11/12] read-cache: leave lock in right state in `write_locked_index()` Martin Ågren
2017-10-06 20:12                       ` [PATCH v3 12/12] read_cache: roll back lock in `update_index_if_able()` Martin Ågren
2017-10-05 20:32           ` [PATCH v2 " Martin Ågren

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

  List information: http://vger.kernel.org/majordomo-info.html

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

  git send-email \
    --in-reply-to=26a9c90a6478ec9ddb4ce34923e251ebe9323ab2.1506862824.git.martin.agren@gmail.com \
    --to=martin.agren@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=pclouds@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.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

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 read-only IMAP folder(s) and NNTP newsgroup(s).