X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ipc%2Fshm.c;h=c3784f6fa37d0c6e9c2a18d59c54800733809c26;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=ebe5fa4e0ca0b393168c285bc60c6bbbd3023b87;hpb=a8e794ca871505c8ea96cc102f4ad555c5231d7f;p=linux-2.6.git diff --git a/ipc/shm.c b/ipc/shm.c index ebe5fa4e0..c3784f6fa 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #include #include "util.h" @@ -60,7 +63,7 @@ void __init shm_init (void) { ipc_init_ids(&shm_ids, 1); #ifdef CONFIG_PROC_FS - create_proc_read_entry("sysvipc/shm", 0, 0, sysvipc_shm_read_proc, NULL); + create_proc_read_entry("sysvipc/shm", 0, NULL, sysvipc_shm_read_proc, NULL); #endif } @@ -78,7 +81,7 @@ static inline struct shmid_kernel *shm_rmid(int id) static inline int shm_addid(struct shmid_kernel *shp) { - return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni+1); + return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni); } @@ -110,14 +113,23 @@ static void shm_open (struct vm_area_struct *shmd) */ static void shm_destroy (struct shmid_kernel *shp) { - shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT; + struct vx_info *vxi = locate_vx_info(shp->shm_perm.xid); + int numpages = (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT; + + vx_ipcshm_sub(vxi, shp, numpages); + shm_tot -= numpages; + 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_free(shp, sizeof(struct shmid_kernel)); + put_vx_info(vxi); + ipc_rcu_putref(shp); } /* @@ -163,6 +175,10 @@ static struct vm_operations_struct shm_vm_ops = { .open = shm_open, /* callback for a new vm-area open */ .close = shm_close, /* callback for when the vm-area is released */ .nopage = shmem_nopage, +#ifdef CONFIG_NUMA + .set_policy = shmem_set_policy, + .get_policy = shmem_get_policy, +#endif }; static int newseg (key_t key, int shmflg, size_t size) @@ -179,25 +195,30 @@ static int newseg (key_t key, int shmflg, size_t size) if (shm_tot + numpages >= shm_ctlall) return -ENOSPC; + if (!vx_ipcshm_avail(current->vx_info, numpages)) + return -ENOSPC; shp = ipc_rcu_alloc(sizeof(*shp)); if (!shp) return -ENOMEM; shp->shm_perm.key = key; - shp->shm_perm.xid = current->xid; + shp->shm_perm.xid = vx_current_xid(); shp->shm_flags = (shmflg & S_IRWXUGO); + shp->mlock_user = NULL; shp->shm_perm.security = NULL; error = security_shm_alloc(shp); if (error) { - ipc_rcu_free(shp, sizeof(*shp)); + ipc_rcu_putref(shp); 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); } @@ -224,6 +245,7 @@ static int newseg (key_t key, int shmflg, size_t size) else file->f_op = &shm_file_operations; shm_tot += numpages; + vx_ipcshm_add(current->vx_info, key, numpages); shm_unlock(shp); return shp->id; @@ -231,7 +253,7 @@ no_id: fput(file); no_file: security_shm_free(shp); - ipc_rcu_free(shp, sizeof(*shp)); + ipc_rcu_putref(shp); return error; } @@ -501,14 +523,6 @@ 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)) { - err = -EPERM; - goto out; - } - shp = shm_lock(shmid); if(shp==NULL) { err = -EINVAL; @@ -518,18 +532,33 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) if(err) goto out_unlock; + if (!capable(CAP_IPC_LOCK)) { + err = -EPERM; + if (current->euid != shp->shm_perm.uid && + current->euid != shp->shm_perm.cuid) + goto out_unlock; + if (cmd == SHM_LOCK && + !current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur) + goto out_unlock; + } + err = security_shm_shmctl(shp, cmd); if (err) 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; @@ -677,6 +706,10 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) o_flags = O_RDWR; acc_mode = S_IRUGO | S_IWUGO; } + if (shmflg & SHM_EXEC) { + prot |= PROT_EXEC; + acc_mode |= S_IXUGO; + } /* * We cannot rely on the fs check since SYSV IPC does have an @@ -851,7 +884,7 @@ static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int l if (!vx_check(shp->shm_perm.xid, VX_IDENT)) { shm_unlock(shp); - continue; + continue; } if (sizeof(size_t) <= sizeof(int)) format = SMALL_STRING;