Skip to content

Commit 3054fbd

Browse files
pks-tgitster
authored andcommitted
reftable/stack: fix stale lock when dying
When starting a transaction via `reftable_stack_init_addition()`, we create a lockfile for the reftable stack itself which we'll write the new list of tables to. But if we terminate abnormally e.g. via a call to `die()`, then we do not remove the lockfile. Subsequent executions of Git which try to modify references will thus fail with an out-of-date error. Fix this bug by registering the lock as a `struct tempfile`, which ensures automatic cleanup for us. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d779996 commit 3054fbd

File tree

1 file changed

+15
-32
lines changed

1 file changed

+15
-32
lines changed

reftable/stack.c

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ license that can be found in the LICENSE file or at
1717
#include "reftable-merged.h"
1818
#include "writer.h"
1919

20+
#include "tempfile.h"
21+
2022
static int stack_try_add(struct reftable_stack *st,
2123
int (*write_table)(struct reftable_writer *wr,
2224
void *arg),
@@ -440,33 +442,27 @@ static void format_name(struct strbuf *dest, uint64_t min, uint64_t max)
440442
}
441443

442444
struct reftable_addition {
443-
int lock_file_fd;
444-
struct strbuf lock_file_name;
445+
struct tempfile *lock_file;
445446
struct reftable_stack *stack;
446447

447448
char **new_tables;
448449
int new_tables_len;
449450
uint64_t next_update_index;
450451
};
451452

452-
#define REFTABLE_ADDITION_INIT \
453-
{ \
454-
.lock_file_name = STRBUF_INIT \
455-
}
453+
#define REFTABLE_ADDITION_INIT {0}
456454

457455
static int reftable_stack_init_addition(struct reftable_addition *add,
458456
struct reftable_stack *st)
459457
{
458+
struct strbuf lock_file_name = STRBUF_INIT;
460459
int err = 0;
461460
add->stack = st;
462461

463-
strbuf_reset(&add->lock_file_name);
464-
strbuf_addstr(&add->lock_file_name, st->list_file);
465-
strbuf_addstr(&add->lock_file_name, ".lock");
462+
strbuf_addf(&lock_file_name, "%s.lock", st->list_file);
466463

467-
add->lock_file_fd = open(add->lock_file_name.buf,
468-
O_EXCL | O_CREAT | O_WRONLY, 0666);
469-
if (add->lock_file_fd < 0) {
464+
add->lock_file = create_tempfile(lock_file_name.buf);
465+
if (!add->lock_file) {
470466
if (errno == EEXIST) {
471467
err = REFTABLE_LOCK_ERROR;
472468
} else {
@@ -475,7 +471,7 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
475471
goto done;
476472
}
477473
if (st->config.default_permissions) {
478-
if (chmod(add->lock_file_name.buf, st->config.default_permissions) < 0) {
474+
if (chmod(add->lock_file->filename.buf, st->config.default_permissions) < 0) {
479475
err = REFTABLE_IO_ERROR;
480476
goto done;
481477
}
@@ -495,6 +491,7 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
495491
if (err) {
496492
reftable_addition_close(add);
497493
}
494+
strbuf_release(&lock_file_name);
498495
return err;
499496
}
500497

@@ -512,15 +509,7 @@ static void reftable_addition_close(struct reftable_addition *add)
512509
add->new_tables = NULL;
513510
add->new_tables_len = 0;
514511

515-
if (add->lock_file_fd > 0) {
516-
close(add->lock_file_fd);
517-
add->lock_file_fd = 0;
518-
}
519-
if (add->lock_file_name.len > 0) {
520-
unlink(add->lock_file_name.buf);
521-
strbuf_release(&add->lock_file_name);
522-
}
523-
512+
delete_tempfile(&add->lock_file);
524513
strbuf_release(&nm);
525514
}
526515

@@ -536,8 +525,10 @@ void reftable_addition_destroy(struct reftable_addition *add)
536525
int reftable_addition_commit(struct reftable_addition *add)
537526
{
538527
struct strbuf table_list = STRBUF_INIT;
528+
int lock_file_fd = get_tempfile_fd(add->lock_file);
539529
int i = 0;
540530
int err = 0;
531+
541532
if (add->new_tables_len == 0)
542533
goto done;
543534

@@ -550,28 +541,20 @@ int reftable_addition_commit(struct reftable_addition *add)
550541
strbuf_addstr(&table_list, "\n");
551542
}
552543

553-
err = write_in_full(add->lock_file_fd, table_list.buf, table_list.len);
544+
err = write_in_full(lock_file_fd, table_list.buf, table_list.len);
554545
strbuf_release(&table_list);
555546
if (err < 0) {
556547
err = REFTABLE_IO_ERROR;
557548
goto done;
558549
}
559550

560-
err = close(add->lock_file_fd);
561-
add->lock_file_fd = 0;
562-
if (err < 0) {
563-
err = REFTABLE_IO_ERROR;
564-
goto done;
565-
}
566-
567-
err = rename(add->lock_file_name.buf, add->stack->list_file);
551+
err = rename_tempfile(&add->lock_file, add->stack->list_file);
568552
if (err < 0) {
569553
err = REFTABLE_IO_ERROR;
570554
goto done;
571555
}
572556

573557
/* success, no more state to clean up. */
574-
strbuf_release(&add->lock_file_name);
575558
for (i = 0; i < add->new_tables_len; i++) {
576559
reftable_free(add->new_tables[i]);
577560
}

0 commit comments

Comments
 (0)