This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 2/2 v3] [BZ #10283] localedef: align fixed maps to SHMLBA


Many Linux arches require fixed mmaps to be aligned higher than pagesize,
so use the SHMLBA define as it represents this quantity exactly.

This fixes spurious errors seen on those arches like:
cannot map archive header: Invalid argument

URL: http://sourceware.org/bugzilla/show_bug.cgi?id=10283
Reported-by: CHIKAMA Masaki <masaki.chikama@gmail.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>

2013-05-23  Mike Frysinger  <vapier@gentoo.org>

	[BZ #10283]
	* locale/locarchive.h (struct locarhandle): Add mmap_base and mmap_len.
	* locale/programs/locarchive.c: Include sys/shm.h.
	(prepare_address_space): Take two new outputs (the mmap base and len).
	Align p to SHMLBA.  Set mmap base and len to the right values.
	(create_archive): Declare new mmap base and len values for
	prepare_address_space, and store the result in ah.
	(file_data_available_p): Replace pagesz with SHMLBA.
	(enlarge_archive): If ah->mmap_base is not NULL, use that and
	ah->mmap_len to unmap rather than ah->addr and ah->reserved.
	Declare new mmap base and len values for
	prepare_address_space, and store the result in new_ah.
	(open_archive): Declare new mmap base and len values for
	prepare_address_space, and store the result in ah.
	(close_archive): If ah->mmap_base is not NULL, use that and
	ah->mmap_len to unmap rather than ah->addr and ah->reserved.
---
v3
	- split out pointer changes
	- still need to split out the SHMLBA definition to a dedicated header

 locale/locarchive.h          |  7 +++++
 locale/programs/locarchive.c | 62 ++++++++++++++++++++++++++++++++------------
 2 files changed, 53 insertions(+), 16 deletions(-)

diff --git a/locale/locarchive.h b/locale/locarchive.h
index db05603..852d3d3 100644
--- a/locale/locarchive.h
+++ b/locale/locarchive.h
@@ -84,6 +84,13 @@ struct locarhandle
   void *addr;
   size_t mmaped;
   size_t reserved;
+  /* If this mmap required adjustment (such as re-aligning), then this is the
+     real address that was returned from mmap() and thus should be passed to
+     the munmap() call.  The addr field above is the first usable address.  */
+  void *mmap_base;
+  /* Same as above for mmap_base vs addr, but this is the real length of the
+     map rather than the usable (which is what reserved represents).  */
+  size_t mmap_len;
 };
 
 
diff --git a/locale/programs/locarchive.c b/locale/programs/locarchive.c
index 2f54489..209fcb8 100644
--- a/locale/programs/locarchive.c
+++ b/locale/programs/locarchive.c
@@ -37,6 +37,7 @@
 #include <stdint.h>
 #include <sys/mman.h>
 #include <sys/param.h>
+#include <sys/shm.h>
 #include <sys/stat.h>
 
 #include "../../crypt/md5.h"
@@ -79,21 +80,31 @@ static const char *locnames[] =
    mapping affects the address selection.  So do this mapping from the
    actual file, even though it's only a dummy to reserve address space.  */
 static void *
-prepare_address_space (int fd, size_t total, size_t *reserved, int *xflags)
+prepare_address_space (int fd, size_t total, size_t *reserved, int *xflags,
+		       void **mmap_base, size_t *mmap_len)
 {
   if (total < RESERVE_MMAP_SIZE)
     {
       void *p = mmap64 (NULL, RESERVE_MMAP_SIZE, PROT_NONE, MAP_SHARED, fd, 0);
       if (p != MAP_FAILED)
-        {
-          *reserved = RESERVE_MMAP_SIZE;
-          *xflags = MAP_FIXED;
-          return p;
-        }
+	{
+	  /* Some arches require fixed mappings to be aligned higher than
+	     pagesize, and SHMLBA represents that size.  */
+	  void *aligned_p = PTR_ALIGN_UP (p, SHMLBA);
+	  size_t align_adjust = aligned_p - p;
+	  *mmap_base = p;
+	  *mmap_len = RESERVE_MMAP_SIZE;
+	  assert (align_adjust < RESERVE_MMAP_SIZE);
+	  *reserved = RESERVE_MMAP_SIZE - align_adjust;
+	  *xflags = MAP_FIXED;
+	  return aligned_p;
+	}
     }
 
   *reserved = total;
   *xflags = 0;
+  *mmap_base = NULL;
+  *mmap_len = 0;
   return NULL;
 }
 
@@ -151,9 +162,11 @@ create_archive (const char *archivefname, struct locarhandle *ah)
       error (EXIT_FAILURE, errval, _("cannot resize archive file"));
     }
 
-  size_t reserved;
+  size_t reserved, mmap_len;
   int xflags;
-  void *p = prepare_address_space (fd, total, &reserved, &xflags);
+  void *mmap_base;
+  void *p = prepare_address_space (fd, total, &reserved, &xflags, &mmap_base,
+				   &mmap_len);
 
   /* Map the header and all the administration data structures.  */
   p = mmap64 (p, total, PROT_READ | PROT_WRITE, MAP_SHARED | xflags, fd, 0);
@@ -199,6 +212,8 @@ create_archive (const char *archivefname, struct locarhandle *ah)
     }
 
   ah->fd = fd;
+  ah->mmap_base = mmap_base;
+  ah->mmap_len = mmap_len;
   ah->addr = p;
   ah->mmaped = total;
   ah->reserved = reserved;
@@ -271,8 +286,7 @@ file_data_available_p (struct locarhandle *ah, uint32_t offset, uint32_t size)
   if (st.st_size > ah->reserved)
     return false;
 
-  const size_t pagesz = getpagesize ();
-  size_t start = ah->mmaped & ~(pagesz - 1);
+  size_t start = ALIGN_DOWN (ah->mmaped, SHMLBA);
   void *p = mmap64 (ah->addr + start, st.st_size - start,
 		    PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED,
 		    ah->fd, start);
@@ -332,10 +346,15 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
 		       MAP_SHARED | MAP_FIXED, ah->fd, 0);
   else
     {
-      munmap (ah->addr, ah->reserved);
+      if (ah->mmap_base)
+	munmap (ah->mmap_base, ah->mmap_len);
+      else
+	munmap (ah->addr, ah->reserved);
       ah->addr = mmap64 (NULL, st.st_size, PROT_READ | PROT_WRITE,
 			 MAP_SHARED, ah->fd, 0);
       ah->reserved = st.st_size;
+      ah->mmap_base = NULL;
+      ah->mmap_len = 0;
       head = ah->addr;
     }
   if (ah->addr == MAP_FAILED)
@@ -401,9 +420,11 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
       error (EXIT_FAILURE, errval, _("cannot resize archive file"));
     }
 
-  size_t reserved;
+  size_t reserved, mmap_len;
   int xflags;
-  void *p = prepare_address_space (fd, total, &reserved, &xflags);
+  void *mmap_base;
+  void *p = prepare_address_space (fd, total, &reserved, &xflags, &mmap_base,
+				   &mmap_len);
 
   /* Map the header and all the administration data structures.  */
   p = mmap64 (p, total, PROT_READ | PROT_WRITE, MAP_SHARED | xflags, fd, 0);
@@ -423,6 +444,8 @@ enlarge_archive (struct locarhandle *ah, const struct locarhead *head)
     }
 
   new_ah.mmaped = total;
+  new_ah.mmap_base = mmap_base;
+  new_ah.mmap_len = mmap_len;
   new_ah.addr = p;
   new_ah.fd = fd;
   new_ah.reserved = reserved;
@@ -606,9 +629,11 @@ open_archive (struct locarhandle *ah, bool readonly)
   ah->fd = fd;
   ah->mmaped = st.st_size;
 
-  size_t reserved;
+  size_t reserved, mmap_len;
   int xflags;
-  void *p = prepare_address_space (fd, st.st_size, &reserved, &xflags);
+  void *mmap_base;
+  void *p = prepare_address_space (fd, st.st_size, &reserved, &xflags,
+				   &mmap_base, &mmap_len);
 
   /* Map the entire file.  We might need to compare the category data
      in the file with the newly added data.  */
@@ -620,6 +645,8 @@ open_archive (struct locarhandle *ah, bool readonly)
       error (EXIT_FAILURE, errno, _("cannot map archive header"));
     }
   ah->reserved = reserved;
+  ah->mmap_base = mmap_base;
+  ah->mmap_len = mmap_len;
 }
 
 
@@ -628,7 +655,10 @@ close_archive (struct locarhandle *ah)
 {
   if (ah->fd != -1)
     {
-      munmap (ah->addr, ah->reserved);
+      if (ah->mmap_base)
+	munmap (ah->mmap_base, ah->mmap_len);
+      else
+	munmap (ah->addr, ah->reserved);
       close (ah->fd);
     }
 }
-- 
1.8.2.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]