summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rpmio/rpmio.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/rpmio/rpmio.c b/rpmio/rpmio.c
index 7add8536b..e8c55ff39 100644
--- a/rpmio/rpmio.c
+++ b/rpmio/rpmio.c
@@ -6,6 +6,10 @@
#include <stdarg.h>
#include <errno.h>
#include <ctype.h>
+#if defined(__linux__)
+#include <sys/personality.h>
+#endif
+#include <sys/utsname.h>
#include <rpm/rpmlog.h>
#include <rpm/rpmmacro.h>
@@ -952,6 +956,45 @@ static LZFILE *lzopen_internal(const char *path, const char *mode, int fd, int x
.filters = NULL,
.check = LZMA_CHECK_SHA256 };
+#if __WORDSIZE == 32
+ /* In 32 bit environment, required memory easily exceeds memory address
+ * space limit if compressing using multiple threads.
+ * By setting a memory limit, liblzma will automatically adjust number
+ * of threads to avoid exceeding memory.
+ */
+ if (threads > 1) {
+ struct utsname u;
+ uint32_t memlimit = (SIZE_MAX>>1) + (SIZE_MAX>>3);
+ uint64_t memory_usage;
+ /* While a 32 bit linux kernel will have an address limit of 3GiB
+ * for processes (which is why set the memory limit to 2.5GiB as a safety
+ * margin), 64 bit kernels will have a limit of 4GiB for 32 bit binaries.
+ * Therefore the memory limit should be higher if running on a 64 bit
+ * kernel, so we increase it to 3,5GiB.
+ */
+ uname(&u);
+ if (strstr(u.machine, "64") || strstr(u.machine, "s390x")
+#if defined(__linux__)
+ || ((personality(0xffffffff) & PER_MASK) == PER_LINUX32)
+#endif
+ )
+ memlimit += (SIZE_MAX>>2);
+
+ /* keep reducing the number of threads untill memory usage gets below limit */
+ while ((memory_usage = lzma_stream_encoder_mt_memusage(&mt_options)) > memlimit) {
+ /* number of threads shouldn't be able to hit zero with compression
+ * settings aailable to set through rpm... */
+ assert(--mt_options.threads != 0);
+ }
+ lzma_memlimit_set(&lzfile->strm, memlimit);
+
+ if (threads != (int)mt_options.threads)
+ rpmlog(RPMLOG_NOTICE,
+ "XZ: Adjusted the number of threads from %d to %d to not exceed the memory usage limit of %lu bytes",
+ threads, mt_options.threads, memlimit);
+ }
+#endif
+
ret = lzma_stream_encoder_mt(&lzfile->strm, &mt_options);
}
} else {