diff options
-rw-r--r-- | fs/hugetlbfs/inode.c | 12 | ||||
-rw-r--r-- | include/asm-alpha/resource.h | 2 | ||||
-rw-r--r-- | include/asm-arm/resource.h | 2 | ||||
-rw-r--r-- | include/asm-arm26/resource.h | 2 | ||||
-rw-r--r-- | include/asm-cris/resource.h | 2 | ||||
-rw-r--r-- | include/asm-h8300/resource.h | 2 | ||||
-rw-r--r-- | include/asm-i386/resource.h | 2 | ||||
-rw-r--r-- | include/asm-ia64/resource.h | 2 | ||||
-rw-r--r-- | include/asm-m68k/resource.h | 2 | ||||
-rw-r--r-- | include/asm-parisc/resource.h | 2 | ||||
-rw-r--r-- | include/asm-ppc/resource.h | 2 | ||||
-rw-r--r-- | include/asm-ppc64/resource.h | 2 | ||||
-rw-r--r-- | include/asm-s390/resource.h | 2 | ||||
-rw-r--r-- | include/asm-sh/resource.h | 2 | ||||
-rw-r--r-- | include/asm-sparc/resource.h | 2 | ||||
-rw-r--r-- | include/asm-sparc64/resource.h | 2 | ||||
-rw-r--r-- | include/asm-v850/resource.h | 2 | ||||
-rw-r--r-- | include/asm-x86_64/resource.h | 2 | ||||
-rw-r--r-- | include/linux/mm.h | 13 | ||||
-rw-r--r-- | include/linux/sched.h | 1 | ||||
-rw-r--r-- | include/linux/shm.h | 1 | ||||
-rw-r--r-- | ipc/shm.c | 36 | ||||
-rw-r--r-- | kernel/user.c | 4 | ||||
-rw-r--r-- | mm/mlock.c | 41 | ||||
-rw-r--r-- | mm/mmap.c | 14 | ||||
-rw-r--r-- | mm/mremap.c | 6 | ||||
-rw-r--r-- | mm/shmem.c | 15 |
27 files changed, 127 insertions, 50 deletions
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 90c07ffb7800a..d5aa417d89560 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -720,12 +720,13 @@ static unsigned long hugetlbfs_counter(void) static int can_do_hugetlb_shm(void) { return likely(capable(CAP_IPC_LOCK) || - in_group_p(sysctl_hugetlb_shm_group)); + in_group_p(sysctl_hugetlb_shm_group) || + can_do_mlock()); } struct file *hugetlb_zero_setup(size_t size) { - int error; + int error = -ENOMEM; struct file *file; struct inode *inode; struct dentry *dentry, *root; @@ -738,6 +739,9 @@ struct file *hugetlb_zero_setup(size_t size) if (!is_hugepage_mem_enough(size)) return ERR_PTR(-ENOMEM); + if (!user_shm_lock(size, current->user)) + return ERR_PTR(-ENOMEM); + root = hugetlbfs_vfsmount->mnt_root; snprintf(buf, 16, "%lu", hugetlbfs_counter()); quick_string.name = buf; @@ -745,7 +749,7 @@ struct file *hugetlb_zero_setup(size_t size) quick_string.hash = 0; dentry = d_alloc(root, &quick_string); if (!dentry) - return ERR_PTR(-ENOMEM); + goto out_shm_unlock; error = -ENFILE; file = get_empty_filp(); @@ -772,6 +776,8 @@ out_file: put_filp(file); out_dentry: dput(dentry); +out_shm_unlock: + user_shm_unlock(size, current->user); return ERR_PTR(error); } diff --git a/include/asm-alpha/resource.h b/include/asm-alpha/resource.h index b94759c615213..2b0f4bcf2644c 100644 --- a/include/asm-alpha/resource.h +++ b/include/asm-alpha/resource.h @@ -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 */ \ + {0, 0 }, /* RLIMIT_MEMLOCK */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_LOCKS */ \ {MAX_SIGPENDING, MAX_SIGPENDING}, /* RLIMIT_SIGPENDING */ \ {MQ_BYTES_MAX, MQ_BYTES_MAX}, /* RLIMIT_MSGQUEUE */ \ diff --git a/include/asm-arm/resource.h b/include/asm-arm/resource.h index 748c660edb154..323167464b976 100644 --- a/include/asm-arm/resource.h +++ b/include/asm-arm/resource.h @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING}, \ diff --git a/include/asm-arm26/resource.h b/include/asm-arm26/resource.h index 748c660edb154..28a05990277d8 100644 --- a/include/asm-arm26/resource.h +++ b/include/asm-arm26/resource.h @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING}, \ diff --git a/include/asm-cris/resource.h b/include/asm-cris/resource.h index e33ada08d9b82..606a4c9a95798 100644 --- a/include/asm-cris/resource.h +++ b/include/asm-cris/resource.h @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff --git a/include/asm-h8300/resource.h b/include/asm-h8300/resource.h index a87720b14a900..65cf2c6962f26 100644 --- a/include/asm-h8300/resource.h +++ b/include/asm-h8300/resource.h @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff --git a/include/asm-i386/resource.h b/include/asm-i386/resource.h index 3e391b2e941f3..47bdff24d040d 100644 --- a/include/asm-i386/resource.h +++ b/include/asm-i386/resource.h @@ -40,7 +40,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff --git a/include/asm-ia64/resource.h b/include/asm-ia64/resource.h index 76345b5c14c8f..c0a403a8a42e0 100644 --- a/include/asm-ia64/resource.h +++ b/include/asm-ia64/resource.h @@ -46,7 +46,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff --git a/include/asm-m68k/resource.h b/include/asm-m68k/resource.h index 8362001c286cd..51ef4bbb8e6ad 100644 --- a/include/asm-m68k/resource.h +++ b/include/asm-m68k/resource.h @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff --git a/include/asm-parisc/resource.h b/include/asm-parisc/resource.h index 59a446534c5b6..ac9de533eb622 100644 --- a/include/asm-parisc/resource.h +++ b/include/asm-parisc/resource.h @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff --git a/include/asm-ppc/resource.h b/include/asm-ppc/resource.h index 3d29914559fc5..a8392167ae6e6 100644 --- a/include/asm-ppc/resource.h +++ b/include/asm-ppc/resource.h @@ -36,7 +36,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff --git a/include/asm-ppc64/resource.h b/include/asm-ppc64/resource.h index c54e9d69d829b..d23ea5ba1b9b0 100644 --- a/include/asm-ppc64/resource.h +++ b/include/asm-ppc64/resource.h @@ -45,7 +45,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff --git a/include/asm-s390/resource.h b/include/asm-s390/resource.h index 5f0f2ba958dd7..837ed3ab12756 100644 --- a/include/asm-s390/resource.h +++ b/include/asm-s390/resource.h @@ -47,7 +47,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff --git a/include/asm-sh/resource.h b/include/asm-sh/resource.h index 73e517a3e80f3..690f83a92b210 100644 --- a/include/asm-sh/resource.h +++ b/include/asm-sh/resource.h @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff --git a/include/asm-sparc/resource.h b/include/asm-sparc/resource.h index 58e90f72ca708..098bfa7145f80 100644 --- a/include/asm-sparc/resource.h +++ b/include/asm-sparc/resource.h @@ -44,7 +44,7 @@ { 0, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {INR_OPEN, INR_OPEN}, {0, 0}, \ - {RLIM_INFINITY, RLIM_INFINITY}, \ + {0, 0}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {MAX_SIGPENDING, MAX_SIGPENDING}, \ diff --git a/include/asm-sparc64/resource.h b/include/asm-sparc64/resource.h index 4a77dd6206217..60afa3362b7fd 100644 --- a/include/asm-sparc64/resource.h +++ b/include/asm-sparc64/resource.h @@ -43,7 +43,7 @@ { 0, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {INR_OPEN, INR_OPEN}, {0, 0}, \ - {RLIM_INFINITY, RLIM_INFINITY}, \ + {0, 0 }, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {MAX_SIGPENDING, MAX_SIGPENDING}, \ diff --git a/include/asm-v850/resource.h b/include/asm-v850/resource.h index 9f4ca4ae638f8..0b757f33dd921 100644 --- a/include/asm-v850/resource.h +++ b/include/asm-v850/resource.h @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff --git a/include/asm-x86_64/resource.h b/include/asm-x86_64/resource.h index 9628f77179fd1..4ed168acafb8e 100644 --- a/include/asm-x86_64/resource.h +++ b/include/asm-x86_64/resource.h @@ -39,7 +39,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { MAX_SIGPENDING, MAX_SIGPENDING }, \ diff --git a/include/linux/mm.h b/include/linux/mm.h index fc87162452946..b7859da6d3339 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -496,9 +496,20 @@ int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *new); 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_shm_lock(size_t, struct user_struct *); +extern void user_shm_unlock(size_t, struct user_struct *); + /* * Parameter block passed down to zap_pte_range in exceptional cases. */ diff --git a/include/linux/sched.h b/include/linux/sched.h index a01f849da7a5a..24066551b9668 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -316,6 +316,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 --git a/include/linux/shm.h b/include/linux/shm.h index 9a00f5ff6c581..1907355c0eb14 100644 --- a/include/linux/shm.h +++ b/include/linux/shm.h @@ -84,6 +84,7 @@ struct shmid_kernel /* private to the kernel */ time_t shm_ctim; pid_t shm_cprid; pid_t shm_lprid; + struct user_struct *mlock_user; }; /* shm_mode upper byte flags */ diff --git a/ipc/shm.c b/ipc/shm.c index de76c1961367a..55dc1ba4229e1 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -114,7 +114,10 @@ static void shm_destroy (struct shmid_kernel *shp) 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_shm_unlock(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, size_t size) 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, size_t size) 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, int cmd, struct shmid_ds __user *buf) 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, int cmd, struct shmid_ds __user *buf) 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, 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 --git a/kernel/user.c b/kernel/user.c index 9f9859ef88ea2..523175afeecdc 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -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 --git a/mm/mlock.c b/mm/mlock.c index a9e37161dcef6..b428752c61870 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -60,7 +60,7 @@ static int do_mlock(unsigned long start, size_t len, int on) 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 start, size_t len) 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(¤t->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(¤t->mm->mmap_sem); @@ -193,3 +193,36 @@ asmlinkage long sys_munlockall(void) up_write(¤t->mm->mmap_sem); return ret; } + +/* + * Objects with different lifetime than processes (SHM_LOCK and SHM_HUGETLB + * shm segments) get accounted against the user_struct instead. + */ +static spinlock_t shmlock_user_lock = SPIN_LOCK_UNLOCKED; + +int user_shm_lock(size_t size, struct user_struct *user) +{ + unsigned long lock_limit, locked; + int allowed = 0; + + spin_lock(&shmlock_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 && !capable(CAP_IPC_LOCK)) + goto out; + get_uid(user); + user->locked_shm += locked; + allowed = 1; +out: + spin_unlock(&shmlock_user_lock); + return allowed; +} + +void user_shm_unlock(size_t size, struct user_struct *user) +{ + spin_lock(&shmlock_user_lock); + user->locked_shm -= (size >> PAGE_SHIFT); + spin_unlock(&shmlock_user_lock); + free_uid(user); +} diff --git a/mm/mmap.c b/mm/mmap.c index 3f7495c75228c..04dc9e2849183 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -796,15 +796,17 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, 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; } @@ -1625,9 +1627,11 @@ unsigned long do_brk(unsigned long addr, unsigned long len) * 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 --git a/mm/mremap.c b/mm/mremap.c index 984b8ddbd2184..6be63314688f1 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -324,10 +324,12 @@ unsigned long do_mremap(unsigned long addr, 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 --git a/mm/shmem.c b/mm/shmem.c index 8ca20e04b60cb..c3b4cc5d59ff0 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1151,17 +1151,26 @@ shmem_get_policy(struct vm_area_struct *vma, unsigned long addr) } #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; spin_lock(&info->lock); - if (lock) + if (lock && !(info->flags & VM_LOCKED)) { + if (!user_shm_lock(inode->i_size, user)) + goto out_nomem; info->flags |= VM_LOCKED; - else + } + if (!lock && (info->flags & VM_LOCKED) && user) { + user_shm_unlock(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) |