Bruno Wolff III 70f244
From 55f7ba830d40d438f0b0663a505e0c227fc68b6b Mon Sep 17 00:00:00 2001
Bruno Wolff III 70f244
From: Phillip Lougher <phillip@squashfs.org.uk>
Bruno Wolff III 70f244
Date: Tue, 10 Jun 2014 21:51:52 +0100
Bruno Wolff III 70f244
Subject: mksquashfs: fix phys mem calculation for 32-bit processes on
Bruno Wolff III 70f244
 PAE/64-bit kernels
Bruno Wolff III 70f244
Bruno Wolff III 70f244
When adding the code to base default memory usage on physical memory
Bruno Wolff III 70f244
(by default use 25% of physical memory), I made an oversight.  I assumed
Bruno Wolff III 70f244
the process would be able to address 25% of physical memory.
Bruno Wolff III 70f244
Bruno Wolff III 70f244
However, for 32-bit processes running on a PAE kernel or 64-bit kernel,
Bruno Wolff III 70f244
25% of physical memory can easily exceed the addressible memory for a
Bruno Wolff III 70f244
32-bit process, e.g. if a machine has 24 GB of physical memory, the
Bruno Wolff III 70f244
code would asume the process could easily use 6 GB.
Bruno Wolff III 70f244
Bruno Wolff III 70f244
A 32-bit process by definition can only address 4 GB (32-bit pointers).
Bruno Wolff III 70f244
But, due to the typical kernel/user-space split (1GB/3GB, or 2GB/2GB)
Bruno Wolff III 70f244
on PAE kernels, a 32-bit process may only be able to address 2 GB.
Bruno Wolff III 70f244
Bruno Wolff III 70f244
So, if Mksquashfs is a 32-bit application running on a PAE/64-bit kernel,
Bruno Wolff III 70f244
the code assumes it can address much more memory than it really can, which
Bruno Wolff III 70f244
means it runs out of memory.
Bruno Wolff III 70f244
Bruno Wolff III 70f244
The fix is to impose a maximum default limit on 32-bit kernels, or
Bruno Wolff III 70f244
otherwise to never use a value more than 25% of the address space.  If
Bruno Wolff III 70f244
we assume the maximum address space is 2 GB, then the maximum becomes
Bruno Wolff III 70f244
512 MB.  But, given most kernels used the 1GB/3GB split, that may be
Bruno Wolff III 70f244
unduely conservative, and 25% of 3 GB (756 MB) may be better.  This
Bruno Wolff III 70f244
patch compromises on 640 MB, which is mid-way between the 512 MB and 756 MB
Bruno Wolff III 70f244
values.  It is also the fixed default value previously used by Mksquashfs.
Bruno Wolff III 70f244
Bruno Wolff III 70f244
This patch also alters the code which imposes a maximum size.  Previously
Bruno Wolff III 70f244
it was believed limiting to the physical memory size was adequate.  But
Bruno Wolff III 70f244
obviously this needs to be updated to take into account a 32-bit process
Bruno Wolff III 70f244
may only be able to address 2 GB.  In the process I've also taken the
Bruno Wolff III 70f244
opportunity to limit all requests to no more than 75% of physical memory.
Bruno Wolff III 70f244
Bruno Wolff III 70f244
Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk>
Bruno Wolff III 70f244
Bruno Wolff III 70f244
diff --git a/squashfs-tools/mksquashfs.c b/squashfs-tools/mksquashfs.c
Bruno Wolff III 70f244
index 86f82bb..5370ecf 100644
Bruno Wolff III 70f244
--- a/squashfs-tools/mksquashfs.c
Bruno Wolff III 70f244
+++ b/squashfs-tools/mksquashfs.c
Bruno Wolff III 70f244
@@ -304,7 +304,7 @@ void restorefs();
Bruno Wolff III 70f244
 struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth);
Bruno Wolff III 70f244
 void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad);
Bruno Wolff III 70f244
 unsigned short get_checksum_mem(char *buff, int bytes);
Bruno Wolff III 70f244
-int get_physical_memory();
Bruno Wolff III 70f244
+void check_usable_phys_mem(int total_mem);
Bruno Wolff III 70f244
 
Bruno Wolff III 70f244
 
Bruno Wolff III 70f244
 void prep_exit()
Bruno Wolff III 70f244
@@ -4053,11 +4053,7 @@ void initialise_threads(int readq, int fragq, int bwriteq, int fwriteq,
Bruno Wolff III 70f244
 		BAD_ERROR("Queue sizes rediculously too large\n");
Bruno Wolff III 70f244
 	total_mem += fwriteq;
Bruno Wolff III 70f244
 
Bruno Wolff III 70f244
-	if(total_mem > get_physical_memory()) {
Bruno Wolff III 70f244
-		ERROR("Total queue sizes larger than physical memory.\n");
Bruno Wolff III 70f244
-		ERROR("Mksquashfs will exhaust physical memory and thrash.\n");
Bruno Wolff III 70f244
-		BAD_ERROR("Queues too large\n");
Bruno Wolff III 70f244
-	}
Bruno Wolff III 70f244
+	check_usable_phys_mem(total_mem);
Bruno Wolff III 70f244
 
Bruno Wolff III 70f244
 	/*
Bruno Wolff III 70f244
 	 * convert from queue size in Mbytes to queue size in
Bruno Wolff III 70f244
@@ -4879,6 +4875,72 @@ int get_physical_memory()
Bruno Wolff III 70f244
 }
Bruno Wolff III 70f244
 
Bruno Wolff III 70f244
 
Bruno Wolff III 70f244
+void check_usable_phys_mem(int total_mem)
Bruno Wolff III 70f244
+{
Bruno Wolff III 70f244
+	/*
Bruno Wolff III 70f244
+	 * We want to allow users to use as much of their physical
Bruno Wolff III 70f244
+	 * memory as they wish.  However, for practical reasons there are
Bruno Wolff III 70f244
+	 * limits which need to be imposed, to protect users from themselves
Bruno Wolff III 70f244
+	 * and to prevent people from using Mksquashfs as a DOS attack by using
Bruno Wolff III 70f244
+	 * all physical memory.   Mksquashfs uses memory to cache data from disk
Bruno Wolff III 70f244
+	 * to optimise performance.  It is pointless to ask it to use more
Bruno Wolff III 70f244
+	 * than 75% of physical memory, as this causes thrashing and it is thus
Bruno Wolff III 70f244
+	 * self-defeating.
Bruno Wolff III 70f244
+	 */
Bruno Wolff III 70f244
+	int mem = get_physical_memory();
Bruno Wolff III 70f244
+
Bruno Wolff III 70f244
+	mem = (mem >> 1) + (mem >> 2); /* 75% */
Bruno Wolff III 70f244
+						
Bruno Wolff III 70f244
+	if(total_mem > mem) {
Bruno Wolff III 70f244
+		ERROR("Total memory requested is more than 75%% of physical "
Bruno Wolff III 70f244
+						"memory.\n");
Bruno Wolff III 70f244
+		ERROR("Mksquashfs uses memory to cache data from disk to "
Bruno Wolff III 70f244
+						"optimise performance.\n");
Bruno Wolff III 70f244
+		ERROR("It is pointless to ask it to use more than this amount "
Bruno Wolff III 70f244
+						"of memory, as this\n");
Bruno Wolff III 70f244
+		ERROR("causes thrashing and it is thus self-defeating.\n");
Bruno Wolff III 70f244
+		BAD_ERROR("Requested memory size too large\n");
Bruno Wolff III 70f244
+	}
Bruno Wolff III 70f244
+
Bruno Wolff III 70f244
+	if(sizeof(void *) == 4 && total_mem > 2048) {
Bruno Wolff III 70f244
+		/*
Bruno Wolff III 70f244
+		 * If we're running on a kernel with PAE or on a 64-bit kernel,
Bruno Wolff III 70f244
+		 * then the 75% physical memory limit can still easily exceed
Bruno Wolff III 70f244
+		 * the addressable memory by this process.
Bruno Wolff III 70f244
+		 *
Bruno Wolff III 70f244
+		 * Due to the typical kernel/user-space split (1GB/3GB, or
Bruno Wolff III 70f244
+		 * 2GB/2GB), we have to conservatively assume the 32-bit
Bruno Wolff III 70f244
+		 * processes can only address 2-3GB.  So refuse if the user
Bruno Wolff III 70f244
+		 * tries to allocate more than 2GB.
Bruno Wolff III 70f244
+		 */
Bruno Wolff III 70f244
+		ERROR("Total memory requested may exceed maximum "
Bruno Wolff III 70f244
+				"addressable memory by this process\n");
Bruno Wolff III 70f244
+		BAD_ERROR("Requested memory size too large\n");
Bruno Wolff III 70f244
+	}
Bruno Wolff III 70f244
+}
Bruno Wolff III 70f244
+
Bruno Wolff III 70f244
+
Bruno Wolff III 70f244
+int get_default_phys_mem()
Bruno Wolff III 70f244
+{
Bruno Wolff III 70f244
+	int mem = get_physical_memory() / SQUASHFS_TAKE;
Bruno Wolff III 70f244
+
Bruno Wolff III 70f244
+	if(sizeof(void *) == 4 && mem > 640) {
Bruno Wolff III 70f244
+		/*
Bruno Wolff III 70f244
+		 * If we're running on a kernel with PAE or on a 64-bit kernel,
Bruno Wolff III 70f244
+		 * the default memory usage can exceed the addressable
Bruno Wolff III 70f244
+		 * memory by this process.
Bruno Wolff III 70f244
+		 * Due to the typical kernel/user-space split (1GB/3GB, or
Bruno Wolff III 70f244
+		 * 2GB/2GB), we have to conservatively assume the 32-bit
Bruno Wolff III 70f244
+		 * processes can only address 2-3GB.  So limit the  default
Bruno Wolff III 70f244
+		 * usage to 640M, which gives room for other data.
Bruno Wolff III 70f244
+		 */
Bruno Wolff III 70f244
+		mem = 640;
Bruno Wolff III 70f244
+	}
Bruno Wolff III 70f244
+
Bruno Wolff III 70f244
+	return mem;
Bruno Wolff III 70f244
+}
Bruno Wolff III 70f244
+
Bruno Wolff III 70f244
+
Bruno Wolff III 70f244
 void calculate_queue_sizes(int mem, int *readq, int *fragq, int *bwriteq,
Bruno Wolff III 70f244
 							int *fwriteq)
Bruno Wolff III 70f244
 {
Bruno Wolff III 70f244
@@ -4890,7 +4952,7 @@ void calculate_queue_sizes(int mem, int *readq, int *fragq, int *bwriteq,
Bruno Wolff III 70f244
 
Bruno Wolff III 70f244
 
Bruno Wolff III 70f244
 #define VERSION() \
Bruno Wolff III 70f244
-	printf("mksquashfs version 4.3 (2014/05/12)\n");\
Bruno Wolff III 70f244
+	printf("mksquashfs version 4.3-git (2014/06/09)\n");\
Bruno Wolff III 70f244
 	printf("copyright (C) 2014 Phillip Lougher "\
Bruno Wolff III 70f244
 		"<phillip@squashfs.org.uk>\n\n"); \
Bruno Wolff III 70f244
 	printf("This program is free software; you can redistribute it and/or"\
Bruno Wolff III 70f244
@@ -4918,7 +4980,7 @@ int main(int argc, char *argv[])
Bruno Wolff III 70f244
 	int fragq;
Bruno Wolff III 70f244
 	int bwriteq;
Bruno Wolff III 70f244
 	int fwriteq;
Bruno Wolff III 70f244
-	int total_mem = get_physical_memory() / SQUASHFS_TAKE;
Bruno Wolff III 70f244
+	int total_mem = get_default_phys_mem();
Bruno Wolff III 70f244
 	int progress = TRUE;
Bruno Wolff III 70f244
 	int force_progress = FALSE;
Bruno Wolff III 70f244
 	struct file_buffer **fragment = NULL;
Bruno Wolff III 70f244
-- 
Bruno Wolff III 70f244
cgit v0.10.1
Bruno Wolff III 70f244