vserver 1.9.5.x5
[linux-2.6.git] / ipc / shm.c
index ebe5fa4..c3784f6 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -26,6 +26,9 @@
 #include <linux/proc_fs.h>
 #include <linux/shmem_fs.h>
 #include <linux/security.h>
+#include <linux/syscalls.h>
+#include <linux/vs_context.h>
+#include <linux/vs_limit.h>
 #include <asm/uaccess.h>
 
 #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;