xmmap: inform Linux users of tuning knobs on ENOMEM

Linux users may benefit from additional information on how to avoid ENOMEM from mmap despite the system having enough RAM to accomodate them. We can't reliably unmap pack windows to work around the issue since malloc and other library routines may mmap without our knowledge. Signed-off-by: Eric Wong <e@80x24.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Eric Wong committed Jun 30, 2021 at 00:01 UTC dc0592941138df684770bfe800ccad6b810214c3
5 files changed +22 -5
config.c
+2 -1
@@ -3051,7 +3051,8 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
3051 if (contents == MAP_FAILED) {
3052 if (errno == ENODEV && S_ISDIR(st.st_mode))
3053 errno = EISDIR;
3054 - error_errno(_("unable to mmap '%s'"), config_filename);
3054 + error_errno(_("unable to mmap '%s'%s"),
3055 + config_filename, mmap_os_err());
3056 ret = CONFIG_INVALID_FILE;
3057 contents = NULL;
3058 goto out_free;
git-compat-util.h
+1
@@ -876,6 +876,7 @@ char *xstrndup(const char *str, size_t len);
876 void *xrealloc(void *ptr, size_t size);
877 void *xcalloc(size_t nmemb, size_t size);
878 void *xmmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
879 +const char *mmap_os_err(void);
880 void *xmmap_gently(void *start, size_t length, int prot, int flags, int fd, off_t offset);
881 int xopen(const char *path, int flags, ...);
882 ssize_t xread(int fd, void *buf, size_t len);
object-file.c
+15 -1
@@ -1023,12 +1023,26 @@ void *xmmap_gently(void *start, size_t length,
1023 return ret;
1024 }
1025
1026 +const char *mmap_os_err(void)
1027 +{
1028 + static const char blank[] = "";
1029 +#if defined(__linux__)
1030 + if (errno == ENOMEM) {
1031 + /* this continues an existing error message: */
1032 + static const char enomem[] =
1033 +", check sys.vm.max_map_count and/or RLIMIT_DATA";
1034 + return enomem;
1035 + }
1036 +#endif /* OS-specific bits */
1037 + return blank;
1038 +}
1039 +
1040 void *xmmap(void *start, size_t length,
1041 int prot, int flags, int fd, off_t offset)
1042 {
1043 void *ret = xmmap_gently(start, length, prot, flags, fd, offset);
1044 if (ret == MAP_FAILED)
1031 - die_errno(_("mmap failed"));
1045 + die_errno(_("mmap failed%s"), mmap_os_err());
1046 return ret;
1047 }
1048
packfile.c
+2 -2
@@ -652,8 +652,8 @@ unsigned char *use_pack(struct packed_git *p,
652 PROT_READ, MAP_PRIVATE,
653 p->pack_fd, win->offset);
654 if (win->base == MAP_FAILED)
655 - die_errno("packfile %s cannot be mapped",
656 - p->pack_name);
655 + die_errno(_("packfile %s cannot be mapped%s"),
656 + p->pack_name, mmap_os_err());
657 if (!win->offset && win->len == p->pack_size
658 && !p->do_not_close)
659 close_pack_fd(p);
read-cache.c
+2 -1
@@ -2236,7 +2236,8 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
2236
2237 mmap = xmmap_gently(NULL, mmap_size, PROT_READ, MAP_PRIVATE, fd, 0);
2238 if (mmap == MAP_FAILED)
2239 - die_errno(_("%s: unable to map index file"), path);
2239 + die_errno(_("%s: unable to map index file%s"), path,
2240 + mmap_os_err());
2241 close(fd);
2242
2243 hdr = (const struct cache_header *)mmap;