# HG changeset patch # User sherman # Date 1268345169 28800 # Node ID 2bf5469864ea8b0e282650bb9caab8937a900197 # Parent 96642e83ad413bf1792172afbb815b2a7591e8c5 6929479: Add a system property sun.zip.disableMemoryMapping to disable mmap use in ZipFile Summary: system property sun.zip.disableMemoryMapping to disable mmap use Reviewed-by: alanb diff -r 96642e83ad41 -r 2bf5469864ea jdk/src/share/classes/java/util/zip/ZipFile.java --- a/jdk/src/share/classes/java/util/zip/ZipFile.java Thu Mar 11 17:50:30 2010 +0000 +++ b/jdk/src/share/classes/java/util/zip/ZipFile.java Thu Mar 11 14:06:09 2010 -0800 @@ -36,6 +36,8 @@ import java.util.Set; import java.util.HashSet; import java.util.NoSuchElementException; +import java.security.AccessController; +import sun.security.action.GetPropertyAction; import static java.util.zip.ZipConstants64.*; /** @@ -78,6 +80,17 @@ private static native void initIDs(); + private static final boolean usemmap; + + static { + // A system prpperty to disable mmap use to avoid vm crash when + // in-use zip file is accidently overwritten by others. + String prop = AccessController.doPrivileged( + new GetPropertyAction("sun.zip.disableMemoryMapping")); + usemmap = (prop == null || + !(prop.length() == 0 || prop.equalsIgnoreCase("true"))); + } + /** * Opens a zip file for reading. * @@ -196,7 +209,7 @@ throw new NullPointerException("charset is null"); this.zc = ZipCoder.get(charset); long t0 = System.nanoTime(); - jzfile = open(name, mode, file.lastModified()); + jzfile = open(name, mode, file.lastModified(), usemmap); sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0); sun.misc.PerfCounter.getZipFileCount().increment(); this.name = name; @@ -673,8 +686,8 @@ } - private static native long open(String name, int mode, long lastModified) - throws IOException; + private static native long open(String name, int mode, long lastModified, + boolean usemmap) throws IOException; private static native int getTotal(long jzfile); private static native int read(long jzfile, long jzentry, long pos, byte[] b, int off, int len); diff -r 96642e83ad41 -r 2bf5469864ea jdk/src/share/native/java/util/zip/ZipFile.c --- a/jdk/src/share/native/java/util/zip/ZipFile.c Thu Mar 11 17:50:30 2010 +0000 +++ b/jdk/src/share/native/java/util/zip/ZipFile.c Thu Mar 11 14:06:09 2010 -0800 @@ -81,7 +81,8 @@ JNIEXPORT jlong JNICALL Java_java_util_zip_ZipFile_open(JNIEnv *env, jclass cls, jstring name, - jint mode, jlong lastModified) + jint mode, jlong lastModified, + jboolean usemmap) { const char *path = JNU_GetStringPlatformChars(env, name, 0); char *msg = 0; @@ -109,7 +110,7 @@ goto finally; } #endif - zip = ZIP_Put_In_Cache(path, zfd, &msg, lastModified); + zip = ZIP_Put_In_Cache0(path, zfd, &msg, lastModified, usemmap); } if (zip != 0) { diff -r 96642e83ad41 -r 2bf5469864ea jdk/src/share/native/java/util/zip/zip_util.c --- a/jdk/src/share/native/java/util/zip/zip_util.c Thu Mar 11 17:50:30 2010 +0000 +++ b/jdk/src/share/native/java/util/zip/zip_util.c Thu Mar 11 14:06:09 2010 -0800 @@ -251,11 +251,16 @@ if (zip->lock != NULL) MDESTROY(zip->lock); free(zip->name); freeCEN(zip); + #ifdef USE_MMAP - if (zip->maddr != NULL) munmap((char *)zip->maddr, zip->mlen); -#else - free(zip->cencache.data); + if (zip->usemmap) { + if (zip->maddr != NULL) + munmap((char *)zip->maddr, zip->mlen); + } else #endif + { + free(zip->cencache.data); + } if (zip->comment != NULL) free(zip->comment); if (zip->zfd != -1) ZFILE_Close(zip->zfd); @@ -585,49 +590,53 @@ ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)"); #ifdef USE_MMAP - /* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to - * read the jar file contents. However, this greatly increased the perceived - * footprint numbers because the mmap'ed pages were adding into the totals shown - * by 'ps' and 'top'. We switched to mmaping only the central directory of jar - * file while calling 'read' to read the rest of jar file. Here are a list of - * reasons apart from above of why we are doing so: - * 1. Greatly reduces mmap overhead after startup complete; - * 2. Avoids dual path code maintainance; - * 3. Greatly reduces risk of address space (not virtual memory) exhaustion. - */ - if (pagesize == 0) { - pagesize = (jlong)sysconf(_SC_PAGESIZE); - if (pagesize == 0) goto Catch; - } - if (cenpos > pagesize) { - offset = cenpos & ~(pagesize - 1); - } else { - offset = 0; + if (zip->usemmap) { + /* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to + * read the jar file contents. However, this greatly increased the perceived + * footprint numbers because the mmap'ed pages were adding into the totals shown + * by 'ps' and 'top'. We switched to mmaping only the central directory of jar + * file while calling 'read' to read the rest of jar file. Here are a list of + * reasons apart from above of why we are doing so: + * 1. Greatly reduces mmap overhead after startup complete; + * 2. Avoids dual path code maintainance; + * 3. Greatly reduces risk of address space (not virtual memory) exhaustion. + */ + if (pagesize == 0) { + pagesize = (jlong)sysconf(_SC_PAGESIZE); + if (pagesize == 0) goto Catch; + } + if (cenpos > pagesize) { + offset = cenpos & ~(pagesize - 1); + } else { + offset = 0; + } + /* When we are not calling recursively, knownTotal is -1. */ + if (knownTotal == -1) { + void* mappedAddr; + /* Mmap the CEN and END part only. We have to figure + out the page size in order to make offset to be multiples of + page size. + */ + zip->mlen = cenpos - offset + cenlen + endhdrlen; + zip->offset = offset; + mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset); + zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL : + (unsigned char*)mappedAddr; + + if (zip->maddr == NULL) { + jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n"); + goto Catch; + } + } + cenbuf = zip->maddr + cenpos - offset; + } else +#endif + { + if ((cenbuf = malloc((size_t) cenlen)) == NULL || + (readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1)) + goto Catch; } - /* When we are not calling recursively, knownTotal is -1. */ - if (knownTotal == -1) { - void* mappedAddr; - /* Mmap the CEN and END part only. We have to figure - out the page size in order to make offset to be multiples of - page size. - */ - zip->mlen = cenpos - offset + cenlen + endhdrlen; - zip->offset = offset; - mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset); - zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL : - (unsigned char*)mappedAddr; - if (zip->maddr == NULL) { - jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n"); - goto Catch; - } - } - cenbuf = zip->maddr + cenpos - offset; -#else - if ((cenbuf = malloc((size_t) cenlen)) == NULL || - (readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1)) - goto Catch; -#endif cenend = cenbuf + cenlen; /* Initialize zip file data structures based on the total number @@ -700,9 +709,11 @@ cenpos = -1; Finally: -#ifndef USE_MMAP - free(cenbuf); +#ifdef USE_MMAP + if (!zip->usemmap) #endif + free(cenbuf); + return cenpos; } @@ -782,9 +793,17 @@ * If a zip error occurs, then *pmsg will be set to the error message text if * pmsg != 0. Otherwise, *pmsg will be set to NULL. */ + jzfile * ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified) { + return ZIP_Put_In_Cache0(name, zfd, pmsg, lastModified, JNI_TRUE); +} + +jzfile * +ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, + jboolean usemmap) +{ static char errbuf[256]; jlong len; jzfile *zip; @@ -793,6 +812,9 @@ return NULL; } +#ifdef USE_MMAP + zip->usemmap = usemmap; +#endif zip->refs = 1; zip->lastModified = lastModified; @@ -877,8 +899,6 @@ return; } -#ifndef USE_MMAP - /* Empirically, most CEN headers are smaller than this. */ #define AMPLE_CEN_HEADER_SIZE 160 @@ -928,7 +948,6 @@ cache->pos = cenpos; return cen; } -#endif /* not USE_MMAP */ typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint; @@ -953,14 +972,17 @@ ze->comment = NULL; #ifdef USE_MMAP - cen = (char*) zip->maddr + zc->cenpos - zip->offset; -#else - if (accessHint == ACCESS_RANDOM) - cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE); - else - cen = sequentialAccessReadCENHeader(zip, zc->cenpos); - if (cen == NULL) goto Catch; + if (zip->usemmap) { + cen = (char*) zip->maddr + zc->cenpos - zip->offset; + } else #endif + { + if (accessHint == ACCESS_RANDOM) + cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE); + else + cen = sequentialAccessReadCENHeader(zip, zc->cenpos); + if (cen == NULL) goto Catch; + } nlen = CENNAM(cen); elen = CENEXT(cen); @@ -976,7 +998,6 @@ if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch; memcpy(ze->name, cen + CENHDR, nlen); ze->name[nlen] = '\0'; - if (elen > 0) { char *extra = cen + CENHDR + nlen; @@ -1037,9 +1058,10 @@ ze = NULL; Finally: -#ifndef USE_MMAP - if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen); +#ifdef USE_MMAP + if (!zip->usemmap) #endif + if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen); return ze; } diff -r 96642e83ad41 -r 2bf5469864ea jdk/src/share/native/java/util/zip/zip_util.h --- a/jdk/src/share/native/java/util/zip/zip_util.h Thu Mar 11 17:50:30 2010 +0000 +++ b/jdk/src/share/native/java/util/zip/zip_util.h Thu Mar 11 14:06:09 2010 -0800 @@ -45,9 +45,6 @@ * Header sizes including signatures */ -#ifdef USE_MMAP -#define SIGSIZ 4 -#endif #define LOCHDR 30 #define EXTHDR 16 #define CENHDR 46 @@ -211,9 +208,9 @@ jlong mlen; /* length (in bytes) mmaped */ jlong offset; /* offset of the mmapped region from the start of the file. */ -#else + jboolean usemmap; /* if mmap is used. */ +#endif cencache cencache; /* CEN header cache */ -#endif ZFILE zfd; /* open file descriptor */ void *lock; /* read lock */ char *comment; /* zip file comment */ @@ -259,6 +256,9 @@ jzfile * ZIP_Put_In_Cache(const char *name, ZFILE zfd, char **pmsg, jlong lastModified); +jzfile * +ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, jboolean usemmap); + void JNICALL ZIP_Close(jzfile *zip);