From: Rik van Riel <riel@redhat.com>

Here is the last agreed-on patch that lets normal users mlock pages up to
their rlimit.  This patch addresses all the issues brought up by Chris and
Andrea.

Signed-off-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/hugetlbfs/inode.c           |    9 +++++--
 25-akpm/include/asm-alpha/resource.h   |    2 -
 25-akpm/include/asm-arm/resource.h     |    2 -
 25-akpm/include/asm-arm26/resource.h   |    2 -
 25-akpm/include/asm-cris/resource.h    |    2 -
 25-akpm/include/asm-h8300/resource.h   |    2 -
 25-akpm/include/asm-i386/resource.h    |    2 -
 25-akpm/include/asm-ia64/resource.h    |    2 -
 25-akpm/include/asm-m68k/resource.h    |    2 -
 25-akpm/include/asm-parisc/resource.h  |    2 -
 25-akpm/include/asm-ppc/resource.h     |    2 -
 25-akpm/include/asm-ppc64/resource.h   |    2 -
 25-akpm/include/asm-s390/resource.h    |    2 -
 25-akpm/include/asm-sh/resource.h      |    2 -
 25-akpm/include/asm-sparc/resource.h   |    2 -
 25-akpm/include/asm-sparc64/resource.h |    2 -
 25-akpm/include/asm-v850/resource.h    |    2 -
 25-akpm/include/asm-x86_64/resource.h  |    2 -
 25-akpm/include/linux/mm.h             |   13 +++++++++-
 25-akpm/include/linux/sched.h          |    1 
 25-akpm/include/linux/shm.h            |    1 
 25-akpm/ipc/shm.c                      |   36 +++++++++++++++++-----------
 25-akpm/kernel/user.c                  |    4 ++-
 25-akpm/mm/mlock.c                     |   41 +++++++++++++++++++++++++++++----
 25-akpm/mm/mmap.c                      |   14 +++++++----
 25-akpm/mm/mremap.c                    |    6 +++-
 25-akpm/mm/shmem.c                     |   18 ++++++++++++--
 27 files changed, 128 insertions(+), 49 deletions(-)

diff -puN fs/hugetlbfs/inode.c~mlock-as-user-for-268-rc2-mm2 fs/hugetlbfs/inode.c
--- 25/fs/hugetlbfs/inode.c~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/fs/hugetlbfs/inode.c	2004-08-06 22:45:25.159974000 -0700
@@ -739,7 +739,7 @@ static int can_do_hugetlb_shm(void)
 
 struct file *hugetlb_zero_setup(size_t size)
 {
-	int error;
+	int error = -ENOMEM;
 	struct file *file;
 	struct inode *inode;
 	struct dentry *dentry, *root;
@@ -752,6 +752,9 @@ struct file *hugetlb_zero_setup(size_t s
 	if (!is_hugepage_mem_enough(size))
 		return ERR_PTR(-ENOMEM);
 
+	if (!user_can_mlock(size, current->user))
+		return ERR_PTR(-ENOMEM);
+
 	root = hugetlbfs_vfsmount->mnt_root;
 	snprintf(buf, 16, "%lu", hugetlbfs_counter());
 	quick_string.name = buf;
@@ -759,7 +762,7 @@ struct file *hugetlb_zero_setup(size_t s
 	quick_string.hash = 0;
 	dentry = d_alloc(root, &quick_string);
 	if (!dentry)
-		return ERR_PTR(-ENOMEM);
+		goto out_subtract_mlock;
 
 	error = -ENFILE;
 	file = get_empty_filp();
@@ -786,6 +789,8 @@ out_file:
 	put_filp(file);
 out_dentry:
 	dput(dentry);
+out_subtract_mlock:
+	user_subtract_mlock(size, current->user);
 	return ERR_PTR(error);
 }
 
diff -puN include/asm-alpha/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-alpha/resource.h
--- 25/include/asm-alpha/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-alpha/resource.h	2004-08-06 22:45:25.160973848 -0700
@@ -41,7 +41,7 @@
     {INR_OPEN, INR_OPEN},			/* RLIMIT_NOFILE */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_AS */		\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_NPROC */	\
-    {LONG_MAX, LONG_MAX},			/* RLIMIT_MEMLOCK */	\
+    {PAGE_SIZE, PAGE_SIZE},			/* RLIMIT_MEMLOCK */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_LOCKS */	\
     {MAX_SIGPENDING, MAX_SIGPENDING},		/* RLIMIT_SIGPENDING */ \
     {MQ_BYTES_MAX, MQ_BYTES_MAX},		/* RLIMIT_MSGQUEUE */	\
diff -puN include/asm-arm26/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-arm26/resource.h
--- 25/include/asm-arm26/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-arm26/resource.h	2004-08-06 22:45:25.160973848 -0700
@@ -39,7 +39,7 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
 	{ 0,             0             },	\
 	{ INR_OPEN,      INR_OPEN      },	\
-	{ RLIM_INFINITY, RLIM_INFINITY },	\
+	{ PAGE_SIZE,     PAGE_SIZE     },	\
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
 	{ MAX_SIGPENDING, MAX_SIGPENDING},	\
diff -puN include/asm-arm/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-arm/resource.h
--- 25/include/asm-arm/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-arm/resource.h	2004-08-06 22:45:25.161973696 -0700
@@ -39,7 +39,7 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
 	{ 0,             0             },	\
 	{ INR_OPEN,      INR_OPEN      },	\
-	{ RLIM_INFINITY, RLIM_INFINITY },	\
+	{ PAGE_SIZE,      PAGE_SIZE    },	\
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
 	{ MAX_SIGPENDING, MAX_SIGPENDING},	\
diff -puN include/asm-cris/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-cris/resource.h
--- 25/include/asm-cris/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-cris/resource.h	2004-08-06 22:45:25.162973544 -0700
@@ -39,7 +39,7 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{             0,             0 },		\
 	{      INR_OPEN,     INR_OPEN  },		\
-	{ RLIM_INFINITY, RLIM_INFINITY },               \
+	{     PAGE_SIZE,    PAGE_SIZE  },               \
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
diff -puN include/asm-h8300/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-h8300/resource.h
--- 25/include/asm-h8300/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-h8300/resource.h	2004-08-06 22:45:25.162973544 -0700
@@ -39,7 +39,7 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{             0,             0 },		\
 	{      INR_OPEN,     INR_OPEN  },		\
-	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ PAGE_SIZE,     PAGE_SIZE     },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
diff -puN include/asm-i386/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-i386/resource.h
--- 25/include/asm-i386/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-i386/resource.h	2004-08-06 22:45:25.163973392 -0700
@@ -40,7 +40,7 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{             0,             0 },		\
 	{      INR_OPEN,     INR_OPEN  },		\
-	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ PAGE_SIZE,     PAGE_SIZE     },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
diff -puN include/asm-ia64/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-ia64/resource.h
--- 25/include/asm-ia64/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-ia64/resource.h	2004-08-06 22:45:25.164973240 -0700
@@ -46,7 +46,7 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{             0,             0 },		\
 	{      INR_OPEN,     INR_OPEN  },		\
-	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ PAGE_SIZE,     PAGE_SIZE     },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
diff -puN include/asm-m68k/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-m68k/resource.h
--- 25/include/asm-m68k/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-m68k/resource.h	2004-08-06 22:45:25.164973240 -0700
@@ -39,7 +39,7 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{             0,             0 },		\
 	{      INR_OPEN,     INR_OPEN  },		\
-	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ PAGE_SIZE,     PAGE_SIZE     },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
diff -puN include/asm-parisc/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-parisc/resource.h
--- 25/include/asm-parisc/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-parisc/resource.h	2004-08-06 22:45:25.165973088 -0700
@@ -39,7 +39,7 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{             0,             0 },		\
 	{      INR_OPEN,     INR_OPEN  },		\
-	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ PAGE_SIZE,     PAGE_SIZE     },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
diff -puN include/asm-ppc64/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-ppc64/resource.h
--- 25/include/asm-ppc64/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-ppc64/resource.h	2004-08-06 22:45:25.166972936 -0700
@@ -45,7 +45,7 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{             0,             0 },		\
 	{      INR_OPEN,     INR_OPEN  },		\
-	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ PAGE_SIZE,     PAGE_SIZE     },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
diff -puN include/asm-ppc/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-ppc/resource.h
--- 25/include/asm-ppc/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-ppc/resource.h	2004-08-06 22:45:25.166972936 -0700
@@ -36,7 +36,7 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{             0,             0 },		\
 	{      INR_OPEN,     INR_OPEN  },		\
-	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ PAGE_SIZE,     PAGE_SIZE     },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
diff -puN include/asm-s390/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-s390/resource.h
--- 25/include/asm-s390/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-s390/resource.h	2004-08-06 22:45:25.167972784 -0700
@@ -47,7 +47,7 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{             0,             0 },		\
 	{ INR_OPEN, INR_OPEN },                         \
-	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ PAGE_SIZE,     PAGE_SIZE     },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
diff -puN include/asm-sh/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-sh/resource.h
--- 25/include/asm-sh/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-sh/resource.h	2004-08-06 22:45:25.167972784 -0700
@@ -39,7 +39,7 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{             0,             0 },		\
 	{      INR_OPEN,     INR_OPEN  },		\
-	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ PAGE_SIZE,     PAGE_SIZE     },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
diff -puN include/asm-sparc64/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-sparc64/resource.h
--- 25/include/asm-sparc64/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-sparc64/resource.h	2004-08-06 22:45:25.168972632 -0700
@@ -43,7 +43,7 @@
     {       0, RLIM_INFINITY},		\
     {RLIM_INFINITY, RLIM_INFINITY},	\
     {INR_OPEN, INR_OPEN}, {0, 0},	\
-    {RLIM_INFINITY, RLIM_INFINITY},	\
+    {PAGE_SIZE,     PAGE_SIZE    },	\
     {RLIM_INFINITY, RLIM_INFINITY},	\
     {RLIM_INFINITY, RLIM_INFINITY},	\
     {MAX_SIGPENDING, MAX_SIGPENDING},	\
diff -puN include/asm-sparc/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-sparc/resource.h
--- 25/include/asm-sparc/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-sparc/resource.h	2004-08-06 22:45:25.169972480 -0700
@@ -44,7 +44,7 @@
     {       0, RLIM_INFINITY},		\
     {RLIM_INFINITY, RLIM_INFINITY},	\
     {INR_OPEN, INR_OPEN}, {0, 0},	\
-    {RLIM_INFINITY, RLIM_INFINITY},	\
+    {PAGE_SIZE, PAGE_SIZE},	\
     {RLIM_INFINITY, RLIM_INFINITY},	\
     {RLIM_INFINITY, RLIM_INFINITY},	\
     {MAX_SIGPENDING, MAX_SIGPENDING},	\
diff -puN include/asm-v850/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-v850/resource.h
--- 25/include/asm-v850/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-v850/resource.h	2004-08-06 22:45:25.169972480 -0700
@@ -39,7 +39,7 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{             0,             0 },		\
 	{      INR_OPEN,     INR_OPEN  },		\
-	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ PAGE_SIZE, PAGE_SIZE  },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
diff -puN include/asm-x86_64/resource.h~mlock-as-user-for-268-rc2-mm2 include/asm-x86_64/resource.h
--- 25/include/asm-x86_64/resource.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/asm-x86_64/resource.h	2004-08-06 22:45:25.170972328 -0700
@@ -39,7 +39,7 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{             0,             0 },		\
 	{      INR_OPEN,     INR_OPEN  },		\
-	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ PAGE_SIZE , PAGE_SIZE  },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
diff -puN include/linux/mm.h~mlock-as-user-for-268-rc2-mm2 include/linux/mm.h
--- 25/include/linux/mm.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/linux/mm.h	2004-08-06 22:45:25.171972176 -0700
@@ -498,9 +498,20 @@ int shmem_set_policy(struct vm_area_stru
 struct mempolicy *shmem_get_policy(struct vm_area_struct *vma,
 					unsigned long addr);
 struct file *shmem_file_setup(char * name, loff_t size, unsigned long flags);
-void shmem_lock(struct file * file, int lock);
+int shmem_lock(struct file *file, int lock, struct user_struct *user);
 int shmem_zero_setup(struct vm_area_struct *);
 
+static inline int can_do_mlock(void)
+{
+	if (capable(CAP_IPC_LOCK))
+		return 1;
+	if (current->rlim[RLIMIT_MEMLOCK].rlim_cur != 0)
+		return 1;
+	return 0;
+}
+extern int user_can_mlock(size_t, struct user_struct *user);
+extern void user_subtract_mlock(size_t, struct user_struct *user);
+
 /*
  * Parameter block passed down to zap_pte_range in exceptional cases.
  */
diff -puN include/linux/sched.h~mlock-as-user-for-268-rc2-mm2 include/linux/sched.h
--- 25/include/linux/sched.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/linux/sched.h	2004-08-06 22:45:23.309255352 -0700
@@ -332,6 +332,7 @@ struct user_struct {
 	atomic_t sigpending;	/* How many pending signals does this user have? */
 	/* protected by mq_lock	*/
 	unsigned long mq_bytes;	/* How many bytes can be allocated to mqueue? */
+	unsigned long locked_shm; /* How many pages of mlocked shm ? */
 
 	/* Hash table maintenance information */
 	struct list_head uidhash_list;
diff -puN include/linux/shm.h~mlock-as-user-for-268-rc2-mm2 include/linux/shm.h
--- 25/include/linux/shm.h~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/include/linux/shm.h	2004-08-06 22:16:26.000000000 -0700
@@ -84,6 +84,7 @@ struct shmid_kernel /* private to the ke
 	time_t			shm_ctim;
 	pid_t			shm_cprid;
 	pid_t			shm_lprid;
+	struct user_struct	*mlock_user;
 };
 
 /* shm_mode upper byte flags */
diff -puN ipc/shm.c~mlock-as-user-for-268-rc2-mm2 ipc/shm.c
--- 25/ipc/shm.c~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/ipc/shm.c	2004-08-06 22:45:25.173971872 -0700
@@ -114,7 +114,10 @@ static void shm_destroy (struct shmid_ke
 	shm_rmid (shp->id);
 	shm_unlock(shp);
 	if (!is_file_hugepages(shp->shm_file))
-		shmem_lock(shp->shm_file, 0);
+		shmem_lock(shp->shm_file, 0, shp->mlock_user);
+	else
+		user_subtract_mlock(shp->shm_file->f_dentry->d_inode->i_size,
+						shp->mlock_user);
 	fput (shp->shm_file);
 	security_shm_free(shp);
 	ipc_rcu_putref(shp);
@@ -190,6 +193,7 @@ static int newseg (key_t key, int shmflg
 
 	shp->shm_perm.key = key;
 	shp->shm_flags = (shmflg & S_IRWXUGO);
+	shp->mlock_user = NULL;
 
 	shp->shm_perm.security = NULL;
 	error = security_shm_alloc(shp);
@@ -198,9 +202,11 @@ static int newseg (key_t key, int shmflg
 		return error;
 	}
 
-	if (shmflg & SHM_HUGETLB)
+	if (shmflg & SHM_HUGETLB) {
+		/* hugetlb_zero_setup takes care of mlock user accounting */
 		file = hugetlb_zero_setup(size);
-	else {
+		shp->mlock_user = current->user;
+	} else {
 		sprintf (name, "SYSV%08x", key);
 		file = shmem_file_setup(name, size, VM_ACCOUNT);
 	}
@@ -504,14 +510,11 @@ asmlinkage long sys_shmctl (int shmid, i
 	case SHM_LOCK:
 	case SHM_UNLOCK:
 	{
-/* Allow superuser to lock segment in memory */
-/* Should the pages be faulted in here or leave it to user? */
-/* need to determine interaction with current->swappable */
-		if (!capable(CAP_IPC_LOCK)) {
+		/* Allow superuser to lock segment in memory */
+		if (!can_do_mlock() && cmd == SHM_LOCK) {
 			err = -EPERM;
 			goto out;
 		}
-
 		shp = shm_lock(shmid);
 		if(shp==NULL) {
 			err = -EINVAL;
@@ -526,13 +529,18 @@ asmlinkage long sys_shmctl (int shmid, i
 			goto out_unlock;
 		
 		if(cmd==SHM_LOCK) {
-			if (!is_file_hugepages(shp->shm_file))
-				shmem_lock(shp->shm_file, 1);
-			shp->shm_flags |= SHM_LOCKED;
-		} else {
-			if (!is_file_hugepages(shp->shm_file))
-				shmem_lock(shp->shm_file, 0);
+			struct user_struct * user = current->user;
+			if (!is_file_hugepages(shp->shm_file)) {
+				err = shmem_lock(shp->shm_file, 1, current->user);
+				if (!err) {
+					shp->shm_flags |= SHM_LOCKED;
+					shp->mlock_user = user;
+				}
+			}
+		} else if (!is_file_hugepages(shp->shm_file)) {
+			shmem_lock(shp->shm_file, 0, shp->mlock_user);
 			shp->shm_flags &= ~SHM_LOCKED;
+			shp->mlock_user = NULL;
 		}
 		shm_unlock(shp);
 		goto out;
diff -puN kernel/user.c~mlock-as-user-for-268-rc2-mm2 kernel/user.c
--- 25/kernel/user.c~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/kernel/user.c	2004-08-06 22:45:30.653138912 -0700
@@ -32,7 +32,8 @@ struct user_struct root_user = {
 	.processes	= ATOMIC_INIT(1),
 	.files		= ATOMIC_INIT(0),
 	.sigpending	= ATOMIC_INIT(0),
-	.mq_bytes	= 0
+	.mq_bytes	= 0,
+	.locked_shm     = 0,
 };
 
 /*
@@ -113,6 +114,7 @@ struct user_struct * alloc_uid(uid_t uid
 		atomic_set(&new->sigpending, 0);
 
 		new->mq_bytes = 0;
+		new->locked_shm = 0;
 
 		/*
 		 * Before adding this, check whether we raced
diff -puN mm/mlock.c~mlock-as-user-for-268-rc2-mm2 mm/mlock.c
--- 25/mm/mlock.c~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/mm/mlock.c	2004-08-06 22:45:25.173971872 -0700
@@ -60,7 +60,7 @@ static int do_mlock(unsigned long start,
 	struct vm_area_struct * vma, * next;
 	int error;
 
-	if (on && !capable(CAP_IPC_LOCK))
+	if (on && !can_do_mlock())
 		return -EPERM;
 	len = PAGE_ALIGN(len);
 	end = start + len;
@@ -118,7 +118,7 @@ asmlinkage long sys_mlock(unsigned long 
 	lock_limit >>= PAGE_SHIFT;
 
 	/* check against resource limits */
-	if (locked <= lock_limit)
+	if ( (locked <= lock_limit) || capable(CAP_IPC_LOCK))
 		error = do_mlock(start, len, 1);
 	up_write(&current->mm->mmap_sem);
 	return error;
@@ -142,7 +142,7 @@ static int do_mlockall(int flags)
 	unsigned int def_flags;
 	struct vm_area_struct * vma;
 
-	if (!capable(CAP_IPC_LOCK))
+	if (!can_do_mlock())
 		return -EPERM;
 
 	def_flags = 0;
@@ -177,7 +177,7 @@ asmlinkage long sys_mlockall(int flags)
 	lock_limit >>= PAGE_SHIFT;
 
 	ret = -ENOMEM;
-	if (current->mm->total_vm <= lock_limit)
+	if ((current->mm->total_vm <= lock_limit) || capable(CAP_IPC_LOCK))
 		ret = do_mlockall(flags);
 out:
 	up_write(&current->mm->mmap_sem);
@@ -193,3 +193,36 @@ asmlinkage long sys_munlockall(void)
 	up_write(&current->mm->mmap_sem);
 	return ret;
 }
+
+/*
+ * Objects with different lifetime than processes (mlocked shm segments
+ * and hugetlb files) get accounted against the user_struct instead.
+ */
+static spinlock_t mlock_user_lock = SPIN_LOCK_UNLOCKED;
+
+int user_can_mlock(size_t size, struct user_struct *user)
+{
+	unsigned long lock_limit, locked;
+	int allowed = 0;
+
+	spin_lock(&mlock_user_lock);
+	locked = size >> PAGE_SHIFT;
+	lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
+	lock_limit >>= PAGE_SHIFT;
+	if (locked + user->locked_shm > lock_limit)
+		goto out;
+	get_uid(user);
+	user->locked_shm += locked;
+	allowed = 1;
+out:
+	spin_unlock(&mlock_user_lock);
+	return allowed;
+}
+
+void user_subtract_mlock(size_t size, struct user_struct *user)
+{
+	spin_lock(&mlock_user_lock);
+	user->locked_shm -= (size >> PAGE_SHIFT);
+	spin_unlock(&mlock_user_lock);
+	free_uid(user);
+}
diff -puN mm/mmap.c~mlock-as-user-for-268-rc2-mm2 mm/mmap.c
--- 25/mm/mmap.c~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/mm/mmap.c	2004-08-06 22:16:26.000000000 -0700
@@ -797,15 +797,17 @@ unsigned long do_mmap_pgoff(struct file 
 			mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
 
 	if (flags & MAP_LOCKED) {
-		if (!capable(CAP_IPC_LOCK))
+		if (!can_do_mlock())
 			return -EPERM;
 		vm_flags |= VM_LOCKED;
 	}
 	/* mlock MCL_FUTURE? */
 	if (vm_flags & VM_LOCKED) {
-		unsigned long locked = mm->locked_vm << PAGE_SHIFT;
+		unsigned long locked, lock_limit;
+		locked = mm->locked_vm << PAGE_SHIFT;
+		lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
 		locked += len;
-		if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur)
+		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
 			return -EAGAIN;
 	}
 
@@ -1724,9 +1726,11 @@ unsigned long do_brk(unsigned long addr,
 	 * mlock MCL_FUTURE?
 	 */
 	if (mm->def_flags & VM_LOCKED) {
-		unsigned long locked = mm->locked_vm << PAGE_SHIFT;
+		unsigned long locked, lock_limit;
+		locked = mm->locked_vm << PAGE_SHIFT;
+		lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
 		locked += len;
-		if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur)
+		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
 			return -EAGAIN;
 	}
 
diff -puN mm/mremap.c~mlock-as-user-for-268-rc2-mm2 mm/mremap.c
--- 25/mm/mremap.c~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/mm/mremap.c	2004-08-06 22:16:26.000000000 -0700
@@ -324,10 +324,12 @@ unsigned long do_mremap(unsigned long ad
 			goto out;
 	}
 	if (vma->vm_flags & VM_LOCKED) {
-		unsigned long locked = current->mm->locked_vm << PAGE_SHIFT;
+		unsigned long locked, lock_limit;
+		locked = current->mm->locked_vm << PAGE_SHIFT;
+		lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
 		locked += new_len - old_len;
 		ret = -EAGAIN;
-		if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur)
+		if (locked > lock_limit && !capable(CAP_IPC_LOCK))
 			goto out;
 	}
 	ret = -ENOMEM;
diff -puN mm/shmem.c~mlock-as-user-for-268-rc2-mm2 mm/shmem.c
--- 25/mm/shmem.c~mlock-as-user-for-268-rc2-mm2	2004-08-06 22:16:26.000000000 -0700
+++ 25-akpm/mm/shmem.c	2004-08-06 22:45:25.176971416 -0700
@@ -1151,17 +1151,29 @@ shmem_get_policy(struct vm_area_struct *
 }
 #endif
 
-void shmem_lock(struct file *file, int lock)
+int shmem_lock(struct file *file, int lock, struct user_struct *user)
 {
 	struct inode *inode = file->f_dentry->d_inode;
 	struct shmem_inode_info *info = SHMEM_I(inode);
+	int retval = -ENOMEM;
+
+	if (lock && !can_do_mlock())
+		return -EPERM;
 
 	spin_lock(&info->lock);
-	if (lock)
+	if (lock && !(info->flags & VM_LOCKED)) {
+		if (!user_can_mlock(inode->i_size, user) && !capable(CAP_IPC_LOCK))
+			goto out_nomem;
 		info->flags |= VM_LOCKED;
-	else
+	}
+	if (!lock && (info->flags & VM_LOCKED) && user) {
+		user_subtract_mlock(inode->i_size, user);
 		info->flags &= ~VM_LOCKED;
+	}
+	retval = 0;
+out_nomem:
 	spin_unlock(&info->lock);
+	return retval;
 }
 
 static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
_