@matheusbsbs / matheus-bagliano / commits / 44d1c19ee8
Fork 0

Make loose object file reading more careful

We used to do 'stat()+open()+mmap()+close()' to read the loose object file data, which does work fine, but has a couple of problems: - it unnecessarily walks the filename twice (at 'stat()' time and then again to open it) - NFS generally has open-close consistency guarantees, which means that the initial 'stat()' was technically done outside of the normal consistency rules. So change it to do 'open()+fstat()+mmap()+close()' instead, which avoids both these issues. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Linus Torvalds committed Jun 14, 2008 at 11:32 UTC 44d1c19ee8ab405108b90ab9c02cd86a014639e8
1 file changed +44 -26
sha1_file.c
+44 -26
@@ -35,8 +35,6 @@ static size_t sz_fmt(size_t s) { return s; }
35
36 const unsigned char null_sha1[20];
37
38 -static unsigned int sha1_file_open_flag = O_NOATIME;
39 -
38 const signed char hexval_table[256] = {
39 -1, -1, -1, -1, -1, -1, -1, -1, /* 00-07 */
40 -1, -1, -1, -1, -1, -1, -1, -1, /* 08-0f */
@@ -997,38 +995,58 @@ int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long siz
995 return hashcmp(sha1, real_sha1) ? -1 : 0;
996 }
997
998 +static int git_open_noatime(const char *name)
999 +{
1000 + static int sha1_file_open_flag = O_NOATIME;
1001 + int fd = open(name, O_RDONLY | sha1_file_open_flag);
1002 +
1003 + /* Might the failure be due to O_NOATIME? */
1004 + if (fd < 0 && errno != ENOENT && sha1_file_open_flag) {
1005 + fd = open(name, O_RDONLY);
1006 + if (fd >= 0)
1007 + sha1_file_open_flag = 0;
1008 + }
1009 + return fd;
1010 +}
1011 +
1012 +static int open_sha1_file(const unsigned char *sha1)
1013 +{
1014 + int fd;
1015 + char *name = sha1_file_name(sha1);
1016 + struct alternate_object_database *alt;
1017 +
1018 + fd = git_open_noatime(name);
1019 + if (fd >= 0)
1020 + return fd;
1021 +
1022 + prepare_alt_odb();
1023 + errno = ENOENT;
1024 + for (alt = alt_odb_list; alt; alt = alt->next) {
1025 + name = alt->name;
1026 + fill_sha1_path(name, sha1);
1027 + fd = git_open_noatime(alt->base);
1028 + if (fd >= 0)
1029 + return fd;
1030 + }
1031 + return -1;
1032 +}
1033 +
1034 static void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
1035 {
1002 - struct stat st;
1036 void *map;
1037 int fd;
1005 - char *filename = find_sha1_file(sha1, &st);
1038
1007 - if (!filename) {
1008 - return NULL;
1009 - }
1039 + fd = open_sha1_file(sha1);
1040 + map = NULL;
1041 + if (fd >= 0) {
1042 + struct stat st;
1043
1011 - fd = open(filename, O_RDONLY | sha1_file_open_flag);
1012 - if (fd < 0) {
1013 - /* See if it works without O_NOATIME */
1014 - switch (sha1_file_open_flag) {
1015 - default:
1016 - fd = open(filename, O_RDONLY);
1017 - if (fd >= 0)
1018 - break;
1019 - /* Fallthrough */
1020 - case 0:
1021 - return NULL;
1044 + if (!fstat(fd, &st)) {
1045 + *size = xsize_t(st.st_size);
1046 + map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
1047 }
1023 -
1024 - /* If it failed once, it will probably fail again.
1025 - * Stop using O_NOATIME
1026 - */
1027 - sha1_file_open_flag = 0;
1048 + close(fd);
1049 }
1029 - *size = xsize_t(st.st_size);
1030 - map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
1031 - close(fd);
1050 return map;
1051 }
1052