#ifndef _LINUX_SHM_H_
 #define _LINUX_SHM_H_
 
+#include <linux/list.h>
 #include <asm/page.h>
 #include <uapi/linux/shm.h>
 #include <asm/shmparam.h>
 
        /* The task created the shm object.  NULL if the task is dead. */
        struct task_struct      *shm_creator;
+       struct list_head        shm_clist;      /* list by creator */
 };
 
 /* shm_mode upper byte flags */
 #define SHM_HUGE_1GB    (30 << SHM_HUGE_SHIFT)
 
 #ifdef CONFIG_SYSVIPC
+struct sysv_shm {
+       struct list_head shm_clist;
+};
+
 long do_shmat(int shmid, char __user *shmaddr, int shmflg, unsigned long *addr,
              unsigned long shmlba);
 extern int is_file_shm_hugepages(struct file *file);
-extern void exit_shm(struct task_struct *task);
+void exit_shm(struct task_struct *task);
+#define shm_init_task(task) INIT_LIST_HEAD(&(task)->sysvshm.shm_clist)
 #else
+struct sysv_shm {
+       /* empty */
+};
+
 static inline long do_shmat(int shmid, char __user *shmaddr,
                            int shmflg, unsigned long *addr,
                            unsigned long shmlba)
 static inline void exit_shm(struct task_struct *task)
 {
 }
+static inline void shm_init_task(struct task_struct *task)
+{
+}
 #endif
 
 #endif /* _LINUX_SHM_H_ */
 
 
 static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
 {
+       list_del(&s->shm_clist);
        ipc_rmid(&shm_ids(ns), &s->shm_perm);
 }
 
 }
 
 /* Called with ns->shm_ids(ns).rwsem locked */
-static int shm_try_destroy_current(int id, void *p, void *data)
+static void shm_mark_orphan(struct shmid_kernel *shp, struct ipc_namespace *ns)
 {
-       struct ipc_namespace *ns = data;
-       struct kern_ipc_perm *ipcp = p;
-       struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
-
-       if (shp->shm_creator != current)
-               return 0;
+       if (WARN_ON(shp->shm_creator != current)) /* Remove me when it works */
+               return;
 
        /*
         * Mark it as orphaned to destroy the segment when
         * is not set, it shouldn't be deleted here.
         */
        if (!ns->shm_rmid_forced)
-               return 0;
+               return;
 
        if (shm_may_destroy(ns, shp)) {
                shm_lock_by_ptr(shp);
                shm_destroy(ns, shp);
        }
-       return 0;
 }
 
 /* Called with ns->shm_ids(ns).rwsem locked */
 void exit_shm(struct task_struct *task)
 {
        struct ipc_namespace *ns = task->nsproxy->ipc_ns;
+       struct shmid_kernel *shp, *n;
 
        if (shm_ids(ns).in_use == 0)
                return;
 
        /* Destroy all already created segments, but not mapped yet */
        down_write(&shm_ids(ns).rwsem);
-       if (shm_ids(ns).in_use)
-               idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns);
+       list_for_each_entry_safe(shp, n, &task->sysvshm.shm_clist, shm_clist)
+               shm_mark_orphan(shp, ns);
+       /* remove the list head from any segments still attached */
+       list_del(&task->sysvshm.shm_clist);
        up_write(&shm_ids(ns).rwsem);
 }
 
        shp->shm_nattch = 0;
        shp->shm_file = file;
        shp->shm_creator = current;
+       list_add(&shp->shm_clist, ¤t->sysvshm.shm_clist);
 
        /*
         * shmid gets reported as "inode#" in /proc/pid/maps.
 
        if (retval)
                goto bad_fork_cleanup_policy;
        /* copy all the process information */
+       shm_init_task(p);
        retval = copy_semundo(clone_flags, p);
        if (retval)
                goto bad_fork_cleanup_audit;
                         */
                        exit_sem(current);
                }
+               if (unshare_flags & CLONE_NEWIPC) {
+                       /* Orphan segments in old ns (see sem above). */
+                       exit_shm(current);
+                       shm_init_task(current);
+               }
 
                if (new_nsproxy)
                        switch_task_namespaces(current, new_nsproxy);