Skip to content

Commit 079424a

Browse files
committed
Merge branch 'mh/ref-races'
"git pack-refs" that races with new ref creation or deletion have been susceptible to lossage of refs under right conditions, which has been tightened up. * mh/ref-races: for_each_ref: load all loose refs before packed refs get_packed_ref_cache: reload packed-refs file when it changes add a stat_validity struct Extract a struct stat_data from cache_entry packed_ref_cache: increment refcount when locked do_for_each_entry(): increment the packed refs cache refcount refs: manage lifetime of packed refs cache via reference counting refs: implement simple transactions for the packed-refs file refs: wrap the packed refs cache in a level of indirection pack_refs(): split creation of packed refs and entry writing repack_without_ref(): split list curation and entry writing
2 parents 08585fd + 98eeb09 commit 079424a

File tree

6 files changed

+466
-134
lines changed

6 files changed

+466
-134
lines changed

builtin/clone.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,13 +493,16 @@ static void write_remote_refs(const struct ref *local_refs)
493493
{
494494
const struct ref *r;
495495

496+
lock_packed_refs(LOCK_DIE_ON_ERROR);
497+
496498
for (r = local_refs; r; r = r->next) {
497499
if (!r->peer_ref)
498500
continue;
499501
add_packed_ref(r->peer_ref->name, r->old_sha1);
500502
}
501503

502-
pack_refs(PACK_REFS_ALL);
504+
if (commit_packed_refs())
505+
die_errno("unable to overwrite old ref-pack file");
503506
}
504507

505508
static void write_followtags(const struct ref *refs, const char *msg)

builtin/ls-files.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,13 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
165165
}
166166
write_name(ce->name, ce_namelen(ce));
167167
if (debug_mode) {
168-
printf(" ctime: %d:%d\n", ce->ce_ctime.sec, ce->ce_ctime.nsec);
169-
printf(" mtime: %d:%d\n", ce->ce_mtime.sec, ce->ce_mtime.nsec);
170-
printf(" dev: %d\tino: %d\n", ce->ce_dev, ce->ce_ino);
171-
printf(" uid: %d\tgid: %d\n", ce->ce_uid, ce->ce_gid);
172-
printf(" size: %d\tflags: %x\n", ce->ce_size, ce->ce_flags);
168+
struct stat_data *sd = &ce->ce_stat_data;
169+
170+
printf(" ctime: %d:%d\n", sd->sd_ctime.sec, sd->sd_ctime.nsec);
171+
printf(" mtime: %d:%d\n", sd->sd_mtime.sec, sd->sd_mtime.nsec);
172+
printf(" dev: %d\tino: %d\n", sd->sd_dev, sd->sd_ino);
173+
printf(" uid: %d\tgid: %d\n", sd->sd_uid, sd->sd_gid);
174+
printf(" size: %d\tflags: %x\n", sd->sd_size, ce->ce_flags);
173175
}
174176
}
175177

cache.h

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,19 @@ struct cache_time {
119119
unsigned int nsec;
120120
};
121121

122+
struct stat_data {
123+
struct cache_time sd_ctime;
124+
struct cache_time sd_mtime;
125+
unsigned int sd_dev;
126+
unsigned int sd_ino;
127+
unsigned int sd_uid;
128+
unsigned int sd_gid;
129+
unsigned int sd_size;
130+
};
131+
122132
struct cache_entry {
123-
struct cache_time ce_ctime;
124-
struct cache_time ce_mtime;
125-
unsigned int ce_dev;
126-
unsigned int ce_ino;
133+
struct stat_data ce_stat_data;
127134
unsigned int ce_mode;
128-
unsigned int ce_uid;
129-
unsigned int ce_gid;
130-
unsigned int ce_size;
131135
unsigned int ce_flags;
132136
unsigned int ce_namelen;
133137
unsigned char sha1[20];
@@ -511,6 +515,21 @@ extern int limit_pathspec_to_literal(void);
511515
#define HASH_FORMAT_CHECK 2
512516
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
513517
extern int index_path(unsigned char *sha1, const char *path, struct stat *st, unsigned flags);
518+
519+
/*
520+
* Record to sd the data from st that we use to check whether a file
521+
* might have changed.
522+
*/
523+
extern void fill_stat_data(struct stat_data *sd, struct stat *st);
524+
525+
/*
526+
* Return 0 if st is consistent with a file not having been changed
527+
* since sd was filled. If there are differences, return a
528+
* combination of MTIME_CHANGED, CTIME_CHANGED, OWNER_CHANGED,
529+
* INODE_CHANGED, and DATA_CHANGED.
530+
*/
531+
extern int match_stat_data(const struct stat_data *sd, struct stat *st);
532+
514533
extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
515534

516535
#define REFRESH_REALLY 0x0001 /* ignore_valid */
@@ -1338,4 +1357,31 @@ int checkout_fast_forward(const unsigned char *from,
13381357

13391358
int sane_execvp(const char *file, char *const argv[]);
13401359

1360+
/*
1361+
* A struct to encapsulate the concept of whether a file has changed
1362+
* since we last checked it. This uses criteria similar to those used
1363+
* for the index.
1364+
*/
1365+
struct stat_validity {
1366+
struct stat_data *sd;
1367+
};
1368+
1369+
void stat_validity_clear(struct stat_validity *sv);
1370+
1371+
/*
1372+
* Returns 1 if the path is a regular file (or a symlink to a regular
1373+
* file) and matches the saved stat_validity, 0 otherwise. A missing
1374+
* or inaccessible file is considered a match if the struct was just
1375+
* initialized, or if the previous update found an inaccessible file.
1376+
*/
1377+
int stat_validity_check(struct stat_validity *sv, const char *path);
1378+
1379+
/*
1380+
* Update the stat_validity from a file opened at descriptor fd. If
1381+
* the file is missing, inaccessible, or not a regular file, then
1382+
* future calls to stat_validity_check will match iff one of those
1383+
* conditions continues to be true.
1384+
*/
1385+
void stat_validity_update(struct stat_validity *sv, int fd);
1386+
13411387
#endif /* CACHE_H */

read-cache.c

Lines changed: 113 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -67,22 +67,69 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
6767
add_index_entry(istate, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
6868
}
6969

70+
void fill_stat_data(struct stat_data *sd, struct stat *st)
71+
{
72+
sd->sd_ctime.sec = (unsigned int)st->st_ctime;
73+
sd->sd_mtime.sec = (unsigned int)st->st_mtime;
74+
sd->sd_ctime.nsec = ST_CTIME_NSEC(*st);
75+
sd->sd_mtime.nsec = ST_MTIME_NSEC(*st);
76+
sd->sd_dev = st->st_dev;
77+
sd->sd_ino = st->st_ino;
78+
sd->sd_uid = st->st_uid;
79+
sd->sd_gid = st->st_gid;
80+
sd->sd_size = st->st_size;
81+
}
82+
83+
int match_stat_data(const struct stat_data *sd, struct stat *st)
84+
{
85+
int changed = 0;
86+
87+
if (sd->sd_mtime.sec != (unsigned int)st->st_mtime)
88+
changed |= MTIME_CHANGED;
89+
if (trust_ctime && check_stat &&
90+
sd->sd_ctime.sec != (unsigned int)st->st_ctime)
91+
changed |= CTIME_CHANGED;
92+
93+
#ifdef USE_NSEC
94+
if (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st))
95+
changed |= MTIME_CHANGED;
96+
if (trust_ctime && check_stat &&
97+
sd->sd_ctime.nsec != ST_CTIME_NSEC(*st))
98+
changed |= CTIME_CHANGED;
99+
#endif
100+
101+
if (check_stat) {
102+
if (sd->sd_uid != (unsigned int) st->st_uid ||
103+
sd->sd_gid != (unsigned int) st->st_gid)
104+
changed |= OWNER_CHANGED;
105+
if (sd->sd_ino != (unsigned int) st->st_ino)
106+
changed |= INODE_CHANGED;
107+
}
108+
109+
#ifdef USE_STDEV
110+
/*
111+
* st_dev breaks on network filesystems where different
112+
* clients will have different views of what "device"
113+
* the filesystem is on
114+
*/
115+
if (check_stat && sd->sd_dev != (unsigned int) st->st_dev)
116+
changed |= INODE_CHANGED;
117+
#endif
118+
119+
if (sd->sd_size != (unsigned int) st->st_size)
120+
changed |= DATA_CHANGED;
121+
122+
return changed;
123+
}
124+
70125
/*
71126
* This only updates the "non-critical" parts of the directory
72127
* cache, ie the parts that aren't tracked by GIT, and only used
73128
* to validate the cache.
74129
*/
75130
void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
76131
{
77-
ce->ce_ctime.sec = (unsigned int)st->st_ctime;
78-
ce->ce_mtime.sec = (unsigned int)st->st_mtime;
79-
ce->ce_ctime.nsec = ST_CTIME_NSEC(*st);
80-
ce->ce_mtime.nsec = ST_MTIME_NSEC(*st);
81-
ce->ce_dev = st->st_dev;
82-
ce->ce_ino = st->st_ino;
83-
ce->ce_uid = st->st_uid;
84-
ce->ce_gid = st->st_gid;
85-
ce->ce_size = st->st_size;
132+
fill_stat_data(&ce->ce_stat_data, st);
86133

87134
if (assume_unchanged)
88135
ce->ce_flags |= CE_VALID;
@@ -195,43 +242,11 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
195242
default:
196243
die("internal error: ce_mode is %o", ce->ce_mode);
197244
}
198-
if (ce->ce_mtime.sec != (unsigned int)st->st_mtime)
199-
changed |= MTIME_CHANGED;
200-
if (trust_ctime && check_stat &&
201-
ce->ce_ctime.sec != (unsigned int)st->st_ctime)
202-
changed |= CTIME_CHANGED;
203-
204-
#ifdef USE_NSEC
205-
if (check_stat && ce->ce_mtime.nsec != ST_MTIME_NSEC(*st))
206-
changed |= MTIME_CHANGED;
207-
if (trust_ctime && check_stat &&
208-
ce->ce_ctime.nsec != ST_CTIME_NSEC(*st))
209-
changed |= CTIME_CHANGED;
210-
#endif
211-
212-
if (check_stat) {
213-
if (ce->ce_uid != (unsigned int) st->st_uid ||
214-
ce->ce_gid != (unsigned int) st->st_gid)
215-
changed |= OWNER_CHANGED;
216-
if (ce->ce_ino != (unsigned int) st->st_ino)
217-
changed |= INODE_CHANGED;
218-
}
219245

220-
#ifdef USE_STDEV
221-
/*
222-
* st_dev breaks on network filesystems where different
223-
* clients will have different views of what "device"
224-
* the filesystem is on
225-
*/
226-
if (check_stat && ce->ce_dev != (unsigned int) st->st_dev)
227-
changed |= INODE_CHANGED;
228-
#endif
229-
230-
if (ce->ce_size != (unsigned int) st->st_size)
231-
changed |= DATA_CHANGED;
246+
changed |= match_stat_data(&ce->ce_stat_data, st);
232247

233248
/* Racily smudged entry? */
234-
if (!ce->ce_size) {
249+
if (!ce->ce_stat_data.sd_size) {
235250
if (!is_empty_blob_sha1(ce->sha1))
236251
changed |= DATA_CHANGED;
237252
}
@@ -246,11 +261,11 @@ static int is_racy_timestamp(const struct index_state *istate,
246261
istate->timestamp.sec &&
247262
#ifdef USE_NSEC
248263
/* nanosecond timestamped files can also be racy! */
249-
(istate->timestamp.sec < ce->ce_mtime.sec ||
250-
(istate->timestamp.sec == ce->ce_mtime.sec &&
251-
istate->timestamp.nsec <= ce->ce_mtime.nsec))
264+
(istate->timestamp.sec < ce->ce_stat_data.sd_mtime.sec ||
265+
(istate->timestamp.sec == ce->ce_stat_data.sd_mtime.sec &&
266+
istate->timestamp.nsec <= ce->ce_stat_data.sd_mtime.nsec))
252267
#else
253-
istate->timestamp.sec <= ce->ce_mtime.sec
268+
istate->timestamp.sec <= ce->ce_stat_data.sd_mtime.sec
254269
#endif
255270
);
256271
}
@@ -342,7 +357,7 @@ int ie_modified(const struct index_state *istate,
342357
* then we know it is.
343358
*/
344359
if ((changed & DATA_CHANGED) &&
345-
(S_ISGITLINK(ce->ce_mode) || ce->ce_size != 0))
360+
(S_ISGITLINK(ce->ce_mode) || ce->ce_stat_data.sd_size != 0))
346361
return changed;
347362

348363
changed_fs = ce_modified_check_fs(ce, st);
@@ -1324,16 +1339,16 @@ static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *on
13241339
{
13251340
struct cache_entry *ce = xmalloc(cache_entry_size(len));
13261341

1327-
ce->ce_ctime.sec = ntoh_l(ondisk->ctime.sec);
1328-
ce->ce_mtime.sec = ntoh_l(ondisk->mtime.sec);
1329-
ce->ce_ctime.nsec = ntoh_l(ondisk->ctime.nsec);
1330-
ce->ce_mtime.nsec = ntoh_l(ondisk->mtime.nsec);
1331-
ce->ce_dev = ntoh_l(ondisk->dev);
1332-
ce->ce_ino = ntoh_l(ondisk->ino);
1342+
ce->ce_stat_data.sd_ctime.sec = ntoh_l(ondisk->ctime.sec);
1343+
ce->ce_stat_data.sd_mtime.sec = ntoh_l(ondisk->mtime.sec);
1344+
ce->ce_stat_data.sd_ctime.nsec = ntoh_l(ondisk->ctime.nsec);
1345+
ce->ce_stat_data.sd_mtime.nsec = ntoh_l(ondisk->mtime.nsec);
1346+
ce->ce_stat_data.sd_dev = ntoh_l(ondisk->dev);
1347+
ce->ce_stat_data.sd_ino = ntoh_l(ondisk->ino);
13331348
ce->ce_mode = ntoh_l(ondisk->mode);
1334-
ce->ce_uid = ntoh_l(ondisk->uid);
1335-
ce->ce_gid = ntoh_l(ondisk->gid);
1336-
ce->ce_size = ntoh_l(ondisk->size);
1349+
ce->ce_stat_data.sd_uid = ntoh_l(ondisk->uid);
1350+
ce->ce_stat_data.sd_gid = ntoh_l(ondisk->gid);
1351+
ce->ce_stat_data.sd_size = ntoh_l(ondisk->size);
13371352
ce->ce_flags = flags & ~CE_NAMEMASK;
13381353
ce->ce_namelen = len;
13391354
hashcpy(ce->sha1, ondisk->sha1);
@@ -1611,7 +1626,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
16111626
* The only thing we care about in this function is to smudge the
16121627
* falsely clean entry due to touch-update-touch race, so we leave
16131628
* everything else as they are. We are called for entries whose
1614-
* ce_mtime match the index file mtime.
1629+
* ce_stat_data.sd_mtime match the index file mtime.
16151630
*
16161631
* Note that this actually does not do much for gitlinks, for
16171632
* which ce_match_stat_basic() always goes to the actual
@@ -1650,7 +1665,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
16501665
* file, and never calls us, so the cached size information
16511666
* for "frotz" stays 6 which does not match the filesystem.
16521667
*/
1653-
ce->ce_size = 0;
1668+
ce->ce_stat_data.sd_size = 0;
16541669
}
16551670
}
16561671

@@ -1660,16 +1675,16 @@ static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
16601675
{
16611676
short flags;
16621677

1663-
ondisk->ctime.sec = htonl(ce->ce_ctime.sec);
1664-
ondisk->mtime.sec = htonl(ce->ce_mtime.sec);
1665-
ondisk->ctime.nsec = htonl(ce->ce_ctime.nsec);
1666-
ondisk->mtime.nsec = htonl(ce->ce_mtime.nsec);
1667-
ondisk->dev = htonl(ce->ce_dev);
1668-
ondisk->ino = htonl(ce->ce_ino);
1678+
ondisk->ctime.sec = htonl(ce->ce_stat_data.sd_ctime.sec);
1679+
ondisk->mtime.sec = htonl(ce->ce_stat_data.sd_mtime.sec);
1680+
ondisk->ctime.nsec = htonl(ce->ce_stat_data.sd_ctime.nsec);
1681+
ondisk->mtime.nsec = htonl(ce->ce_stat_data.sd_mtime.nsec);
1682+
ondisk->dev = htonl(ce->ce_stat_data.sd_dev);
1683+
ondisk->ino = htonl(ce->ce_stat_data.sd_ino);
16691684
ondisk->mode = htonl(ce->ce_mode);
1670-
ondisk->uid = htonl(ce->ce_uid);
1671-
ondisk->gid = htonl(ce->ce_gid);
1672-
ondisk->size = htonl(ce->ce_size);
1685+
ondisk->uid = htonl(ce->ce_stat_data.sd_uid);
1686+
ondisk->gid = htonl(ce->ce_stat_data.sd_gid);
1687+
ondisk->size = htonl(ce->ce_stat_data.sd_size);
16731688
hashcpy(ondisk->sha1, ce->sha1);
16741689

16751690
flags = ce->ce_flags;
@@ -1936,3 +1951,33 @@ void *read_blob_data_from_index(struct index_state *istate, const char *path, un
19361951
*size = sz;
19371952
return data;
19381953
}
1954+
1955+
void stat_validity_clear(struct stat_validity *sv)
1956+
{
1957+
free(sv->sd);
1958+
sv->sd = NULL;
1959+
}
1960+
1961+
int stat_validity_check(struct stat_validity *sv, const char *path)
1962+
{
1963+
struct stat st;
1964+
1965+
if (stat(path, &st) < 0)
1966+
return sv->sd == NULL;
1967+
if (!sv->sd)
1968+
return 0;
1969+
return S_ISREG(st.st_mode) && !match_stat_data(sv->sd, &st);
1970+
}
1971+
1972+
void stat_validity_update(struct stat_validity *sv, int fd)
1973+
{
1974+
struct stat st;
1975+
1976+
if (fstat(fd, &st) < 0 || !S_ISREG(st.st_mode))
1977+
stat_validity_clear(sv);
1978+
else {
1979+
if (!sv->sd)
1980+
sv->sd = xcalloc(1, sizeof(struct stat_data));
1981+
fill_stat_data(sv->sd, &st);
1982+
}
1983+
}

0 commit comments

Comments
 (0)