On 2014-09-06 09.50, Michael Haggerty wrote:
> Sorry for the long delay since v3. This version mostly cleans up a
> couple more places where the lockfile object was left in an
> ill-defined state.
No problem with the delay.
The most important question is if we do the lk->active handling right.
Set it to false as seen as possible, and to true as late as possible,
then die() cleanly.
So the ->acive handling looks (more or less, please see below) and
deserves another critical review, may be.
Instead of commenting each patch, I collected a mixture of small questions
and possible suggestions into a diff file.
diff --git a/lockfile.c b/lockfile.c
index e54d260..7f27ea2 100644
--- a/lockfile.c
+++ b/lockfile.c
@@ -18,6 +18,10 @@
* Usually, if $FILENAME is a symlink, then it is resolved, and the
* file ultimately pointed to is the one that is locked and later
* replaced. However, if LOCK_NODEREF is used, then $FILENAME
+LOCK_NODEREF can be read either as
+LOCK_NODE_REF or LOCK_NO_DEREF
+should we change it ?
+
* itself is locked and later replaced, even if it is a symlink.
*
* 2. Write the new file contents to the lockfile.
@@ -46,9 +50,18 @@
* state:
* - the lockfile exists
* - active is set
- * - filename holds the filename of the lockfile
+ * - filename holds the filename of the lockfile in a strbuf
* - fd holds a file descriptor open for writing to the lockfile
* - owner holds the PID of the process that locked the file
+question: Why do we need the PID here ?
+Do we open a lock file and do a fork() ?
+And if yes, the child gets a new PID, what happens when the
+child gets a signal ?
+Who "owns" the lockfile, the parent, the child, both ?
+The child has access to all data, the fd is open and can be used,
+why do we not allow a rollback, when the child dies ?
+
+
*
* - Locked, lockfile closed (after close_lock_file()). Same as the
* previous state, except that the lockfile is closed and fd is -1.
@@ -57,7 +70,7 @@
* rollback_lock_file(), or a failed attempt to lock). In this
* state:
* - active is unset
- * - filename is the empty string (usually, though there are
+ * - filename is an empty string buffer (usually, though there are
* transitory states in which this condition doesn't hold)
* - fd is -1
* - the object is left registered in the lock_file_list, and
@@ -68,7 +81,7 @@
static struct lock_file *volatile lock_file_list;
-static void remove_lock_file(void)
+static void remove_lock_files(void)
{
pid_t me = getpid();
@@ -79,9 +92,9 @@ static void remove_lock_file(void)
}
}
-static void remove_lock_file_on_signal(int signo)
+static void remove_lock_files_on_signal(int signo)
{
- remove_lock_file();
+ remove_lock_files();
sigchain_pop(signo);
raise(signo);
}
@@ -93,7 +106,7 @@ static void remove_lock_file_on_signal(int signo)
* "/", if any). If path is empty or the root directory ("/"), set
* path to the empty string.
*/
-static void trim_last_path_elm(struct strbuf *path)
+static void trim_last_path_elem(struct strbuf *path)
{
int i = path->len;
@@ -143,7 +156,7 @@ static void resolve_symlink(struct strbuf *path)
* link is a relative path, so replace the
* last element of p with it.
*/
- trim_last_path_elm(path);
+ trim_last_path_elem(path);
strbuf_addbuf(path, &link);
}
@@ -153,13 +166,16 @@ static void resolve_symlink(struct strbuf *path)
/* Make sure errno contains a meaningful value on error */
static int lock_file(struct lock_file *lk, const char *path, int flags)
{
+ struct stat st;
+ int mode = 0666;
if (!lock_file_list) {
/* One-time initialization */
- sigchain_push_common(remove_lock_file_on_signal);
- atexit(remove_lock_file);
+ sigchain_push_common(remove_lock_files_on_signal);
+ atexit(remove_lock_files);
}
- assert(!lk->active);
+ if (lk->active)
+ die("lk->active %s", path);
if (!lk->on_list) {
/* Initialize *lk and add it to lock_file_list: */
@@ -167,16 +183,25 @@ static int lock_file(struct lock_file *lk, const char
*path, int flags)
lk->active = 0;
lk->owner = 0;
lk->on_list = 1;
- strbuf_init(&lk->filename, 0);
+ strbuf_init(&lk->filename, strlen(path) + LOCK_SUFFIX_LEN);
lk->next = lock_file_list;
lock_file_list = lk;
}
+ strbuf_reset(&lk->filename); /* Better to be save */
strbuf_addstr(&lk->filename, path);
if (!(flags & LOCK_NODEREF))
resolve_symlink(&lk->filename);
strbuf_addstr(&lk->filename, LOCK_SUFFIX);
- lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, 0666);
+ /*
+ * adjust_shared_perm() will widen permissions if needed,
+ * otherwise keep permissions restrictive
+ *
+ */
+ if (!stat(path, &st))
+ mode = st.st_mode & 07777;
+
+ lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, mode);
if (lk->fd < 0) {
strbuf_reset(&lk->filename);
return -1;
@@ -268,7 +293,7 @@ int close_lock_file(struct lock_file *lk)
return close(fd);
}
-int reopen_lock_file(struct lock_file *lk)
+int reopen_lock_file_UNUSED_CAN_IT_BE_REMOVED(struct lock_file *lk)
{
if (0 <= lk->fd)
die(_("BUG: reopen a lockfile that is still open"));
@@ -283,7 +308,7 @@ int commit_lock_file_to(struct lock_file *lk, const char
*path)
int save_errno;
if (!lk->active)
- die("BUG: attempt to commit unlocked object");
+ die("BUG: attempt to commit unlocked object %s", path);
if (lk->fd >= 0 && close_lock_file(lk))
goto rollback;
@@ -325,10 +350,12 @@ void rollback_lock_file(struct lock_file *lk)
{
if (!lk->active)
return;
+ lk->active = 0; /* We are going to de-activate,
+ so active is no longer valid already here ? */
if (lk->fd >= 0)
close_lock_file(lk);
unlink_or_warn(lk->filename.buf);
- lk->active = 0;
+ //lk->active = 0;
strbuf_reset(&lk->filename);
}
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html