IPC: introduce ipc_update_perm()
[cascardo/linux.git] / ipc / util.c
index fd1b50d..dc8943a 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/audit.h>
 #include <linux/nsproxy.h>
 #include <linux/rwsem.h>
+#include <linux/memory.h>
 #include <linux/ipc_namespace.h>
 
 #include <asm/unistd.h>
@@ -52,11 +53,57 @@ struct ipc_namespace init_ipc_ns = {
        },
 };
 
+atomic_t nr_ipc_ns = ATOMIC_INIT(1);
+
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+
+static void ipc_memory_notifier(struct work_struct *work)
+{
+       ipcns_notify(IPCNS_MEMCHANGED);
+}
+
+static DECLARE_WORK(ipc_memory_wq, ipc_memory_notifier);
+
+
+static int ipc_memory_callback(struct notifier_block *self,
+                               unsigned long action, void *arg)
+{
+       switch (action) {
+       case MEM_ONLINE:    /* memory successfully brought online */
+       case MEM_OFFLINE:   /* or offline: it's time to recompute msgmni */
+               /*
+                * This is done by invoking the ipcns notifier chain with the
+                * IPC_MEMCHANGED event.
+                * In order not to keep the lock on the hotplug memory chain
+                * for too long, queue a work item that will, when waken up,
+                * activate the ipcns notification chain.
+                * No need to keep several ipc work items on the queue.
+                */
+               if (!work_pending(&ipc_memory_wq))
+                       schedule_work(&ipc_memory_wq);
+               break;
+       case MEM_GOING_ONLINE:
+       case MEM_GOING_OFFLINE:
+       case MEM_CANCEL_ONLINE:
+       case MEM_CANCEL_OFFLINE:
+       default:
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+#endif /* CONFIG_MEMORY_HOTPLUG */
+
 /**
  *     ipc_init        -       initialise IPC subsystem
  *
  *     The various system5 IPC resources (semaphores, messages and shared
  *     memory) are initialised
+ *     A callback routine is registered into the memory hotplug notifier
+ *     chain: since msgmni scales to lowmem this callback routine will be
+ *     called upon successful memory add / remove to recompute msmgni.
  */
  
 static int __init ipc_init(void)
@@ -64,6 +111,8 @@ static int __init ipc_init(void)
        sem_init();
        msg_init();
        shm_init();
+       hotplug_memory_notifier(ipc_memory_callback, IPC_CALLBACK_PRI);
+       register_ipcns_notifier(&init_ipc_ns);
        return 0;
 }
 __initcall(ipc_init);
@@ -231,6 +280,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
        if(ids->seq > ids->seq_max)
                ids->seq = 0;
 
+       new->id = ipc_buildid(id, new->seq);
        spin_lock_init(&new->lock);
        new->deleted = 0;
        rcu_read_lock();
@@ -761,6 +811,19 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
                return ipcget_public(ns, ids, ops, params);
 }
 
+/**
+ * ipc_update_perm - update the permissions of an IPC.
+ * @in:  the permission given as input.
+ * @out: the permission of the ipc to set.
+ */
+void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
+{
+       out->uid = in->uid;
+       out->gid = in->gid;
+       out->mode = (out->mode & ~S_IRWXUGO)
+               | (in->mode & S_IRWXUGO);
+}
+
 #ifdef __ARCH_WANT_IPC_PARSE_VERSION