The semaphores are restored by creating each 'sem object read from the
checkpoint image. Each semaphore array (sem->sem_base) is checked for
validity of contents before copies to the corresponding semaphore.

TODO: this patch does not handle semaphore-undo -- this data should be
restored per-task while iterating through the tasks.

Signed-off-by: Oren Laadan <[email protected]>
---
 ipc/checkpoint.c     |    2 -
 ipc/checkpoint_sem.c |  116 ++++++++++++++++++++++++++++++++++++++++++++++++++
 ipc/util.h           |    3 +
 3 files changed, 119 insertions(+), 2 deletions(-)

diff --git a/ipc/checkpoint.c b/ipc/checkpoint.c
index 7a2f4a5..e14dea6 100644
--- a/ipc/checkpoint.c
+++ b/ipc/checkpoint.c
@@ -213,12 +213,10 @@ static int do_restore_ipc_ns(struct ckpt_ctx *ctx)
                goto out;
        ret = restore_ipc_any(ctx, IPC_MSG_IDS,
                              CKPT_HDR_IPC_MSG, restore_ipc_msg);
-#if 0 /* NEXT FEW PATCHES */
        if (ret < 0)
                goto out;
        ret = restore_ipc_any(ctx, IPC_SEM_IDS,
                              CKPT_HDR_IPC_SEM, restore_ipc_sem);
-#endif
  out:
        ckpt_hdr_put(ctx, h);
        return ret;
diff --git a/ipc/checkpoint_sem.c b/ipc/checkpoint_sem.c
index fc6ea44..0065202 100644
--- a/ipc/checkpoint_sem.c
+++ b/ipc/checkpoint_sem.c
@@ -99,3 +99,119 @@ int checkpoint_ipc_sem(int id, void *p, void *data)
        ckpt_hdr_put(ctx, h);
        return ret;
 }
+
+/************************************************************************
+ * ipc restart
+ */
+
+static int load_ipc_sem_hdr(struct ckpt_ctx *ctx,
+                              struct ckpt_hdr_ipc_sem *h,
+                              struct sem_array *sem)
+{
+       int ret = 0;
+
+       ret = restore_load_ipc_perms(&h->perms, &sem->sem_perm);
+       if (ret < 0)
+               return ret;
+
+       ckpt_debug("sem: nsems %u\n", h->sem_nsems);
+
+       sem->sem_otime = h->sem_otime;
+       sem->sem_ctime = h->sem_ctime;
+       sem->sem_nsems = h->sem_nsems;
+
+       return 0;
+}
+
+/**
+ * ckpt_read_sem_array - read the state of a semaphore array
+ * @ctx: checkpoint context
+ * @sem: semphore array
+ *
+ * Expect the data in an array of 'struct sem': {32 bit, 32 bit}.
+ * See comment in ckpt_write_sem_array().
+ *
+ * The sem-undo information is not restored per ipc_ns, but rather per task.
+ */
+static struct sem *restore_sem_array(struct ckpt_ctx *ctx, int nsems)
+{
+       struct sem *sma;
+       int i, ret;
+
+       sma = kmalloc(nsems * sizeof(*sma), GFP_KERNEL);
+       ret = _ckpt_read_buffer(ctx, sma, nsems * sizeof(*sma));
+       if (ret < 0)
+               goto out;
+
+       /* validate sem array contents */
+       for (i = 0; i < nsems; i++) {
+               if (sma[i].semval < 0 || sma[i].sempid < 0) {
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+ out:
+       if (ret < 0) {
+               kfree(sma);
+               sma = ERR_PTR(ret);
+       }
+       return sma;
+}
+
+int restore_ipc_sem(struct ckpt_ctx *ctx)
+{
+       struct ckpt_hdr_ipc_sem *h;
+       struct kern_ipc_perm *perms;
+       struct sem_array *sem;
+       struct sem *sma = NULL;
+       struct ipc_ids *sem_ids = &current->nsproxy->ipc_ns->ids[IPC_SEM_IDS];
+       int semflag, ret;
+
+       h = ckpt_read_obj_type(ctx, sizeof(*h), CKPT_HDR_IPC_SEM);
+       if (IS_ERR(h))
+               return PTR_ERR(h);
+
+       ret = -EINVAL;
+       if (h->perms.id < 0)
+               goto out;
+       if (h->sem_nsems < 0)
+               goto out;
+
+       /* read sempahore array state */
+       sma = restore_sem_array(ctx, h->sem_nsems);
+       if (IS_ERR(sma)) {
+               ret = PTR_ERR(sma);
+               goto out;
+       }
+
+       /* restore the message queue now */
+       semflag = h->perms.mode | IPC_CREAT | IPC_EXCL;
+       ckpt_debug("sem: do_semget key %d flag %#x id %d\n",
+                h->perms.key, semflag, h->perms.id);
+       ret = do_semget(h->perms.key, h->sem_nsems, semflag, h->perms.id);
+       ckpt_debug("sem: do_msgget ret %d\n", ret);
+       if (ret < 0)
+               goto out;
+
+       down_write(&sem_ids->rw_mutex);
+
+       /* we are the sole owners/users of this ipc_ns, it can't go away */
+       perms = ipc_lock(sem_ids, h->perms.id);
+       BUG_ON(IS_ERR(perms));  /* ipc_ns is private to us */
+
+       sem = container_of(perms, struct sem_array, sem_perm);
+       memcpy(sem->sem_base, sma, sem->sem_nsems * sizeof(*sma));
+
+       ret = load_ipc_sem_hdr(ctx, h, sem);
+       ipc_unlock(perms);
+
+       if (ret < 0) {
+               ckpt_debug("sem: need to remove (%d)\n", ret);
+               freeary(current->nsproxy->ipc_ns, perms);
+       }
+       up_write(&sem_ids->rw_mutex);
+ out:
+       kfree(sma);
+       ckpt_hdr_put(ctx, h);
+       return ret;
+}
diff --git a/ipc/util.h b/ipc/util.h
index 5b7cead..54f9acb 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -184,6 +184,8 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
 /* for checkpoint/restart */
 extern int do_shmget(key_t key, size_t size, int shmflg, int req_id);
 extern int do_msgget(key_t key, int msgflg, int req_id);
+extern int do_semget(key_t key, int nsems, int semflg, int req_id);
+
 extern void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp);
 extern void freeary(struct ipc_namespace *, struct kern_ipc_perm *);
 
@@ -202,6 +204,7 @@ extern int checkpoint_ipc_msg(int id, void *p, void *data);
 extern int restore_ipc_msg(struct ckpt_ctx *ctx);
 
 extern int checkpoint_ipc_sem(int id, void *p, void *data);
+extern int restore_ipc_sem(struct ckpt_ctx *ctx);
 #endif
 
 #endif
-- 
1.5.4.3

_______________________________________________
Containers mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/containers

_______________________________________________
Devel mailing list
[email protected]
https://openvz.org/mailman/listinfo/devel

Reply via email to