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