Add checkpoint/restart of controlling terminal: current->signal->tty.
This is only done for session leaders.

If the session leader belongs to the ancestor pid-ns, then checkpoint
skips this tty; On restart, it will not be restored, and whatever tty
is in place from parent pid-ns (at restart) will be inherited.

Chagnelog [v1]:
  - Don't restore tty_old_pgrp it pgid is CKPT_PID_NULL
  - Initialize pgrp to NULL in restore_signal

Signed-off-by: Oren Laadan <or...@cs.columbia.edu>
Acked-by: Serge E. Hallyn <se...@us.ibm.com>
Tested-by: Serge E. Hallyn <se...@us.ibm.com>
---
 checkpoint/signal.c            |   79 +++++++++++++++++++++++++++++++++++++++-
 drivers/char/tty_io.c          |   33 +++++++++++++----
 include/linux/checkpoint.h     |    1 +
 include/linux/checkpoint_hdr.h |    6 +++
 include/linux/tty.h            |    5 +++
 5 files changed, 115 insertions(+), 9 deletions(-)

diff --git a/checkpoint/signal.c b/checkpoint/signal.c
index ecb94f8..9d0e9c3 100644
--- a/checkpoint/signal.c
+++ b/checkpoint/signal.c
@@ -316,12 +316,13 @@ static int checkpoint_signal(struct ckpt_ctx *ctx, struct 
task_struct *t)
        struct ckpt_hdr_signal *h;
        struct signal_struct *signal;
        struct sigpending shared_pending;
+       struct tty_struct *tty = NULL;
        struct rlimit *rlim;
        struct timeval tval;
        struct cpu_itimer *it;
        cputime_t cputime;
        unsigned long flags;
-       int i, ret;
+       int i, ret = 0;
 
        h = ckpt_hdr_get_type(ctx, sizeof(*h), CKPT_HDR_SIGNAL);
        if (!h)
@@ -403,9 +404,34 @@ static int checkpoint_signal(struct ckpt_ctx *ctx, struct 
task_struct *t)
        cputime_to_timeval(it->incr, &tval);
        h->it_prof_incr = timeval_to_ns(&tval);
 
+       /* tty */
+       if (signal->leader) {
+               h->tty_old_pgrp = ckpt_pid_nr(ctx, signal->tty_old_pgrp);
+               tty = tty_kref_get(signal->tty);
+               if (tty) {
+                       /* irq is already disabled */
+                       spin_lock(&tty->ctrl_lock);
+                       h->tty_pgrp = ckpt_pid_nr(ctx, tty->pgrp);
+                       spin_unlock(&tty->ctrl_lock);
+                       tty_kref_put(tty);
+               }
+       }
+
        unlock_task_sighand(t, &flags);
 
-       ret = ckpt_write_obj(ctx, &h->h);
+       /*
+        * If the session is in an ancestor namespace, skip this tty
+        * and set tty_objref = 0. It will not be explicitly restored,
+        * but rather inherited from parent pid-ns at restart time.
+        */
+       if (tty && ckpt_pid_nr(ctx, tty->session) > 0) {
+               h->tty_objref = checkpoint_obj(ctx, tty, CKPT_OBJ_TTY);
+               if (h->tty_objref < 0)
+                       ret = h->tty_objref;
+       }
+
+       if (!ret)
+               ret = ckpt_write_obj(ctx, &h->h);
        if (!ret)
                ret = checkpoint_sigpending(ctx, &shared_pending);
 
@@ -476,8 +502,10 @@ static int restore_signal(struct ckpt_ctx *ctx)
        struct ckpt_hdr_signal *h;
        struct sigpending new_pending;
        struct sigpending *pending;
+       struct tty_struct *tty = NULL;
        struct itimerval itimer;
        struct rlimit rlim;
+       struct pid *pgrp = NULL;
        int i, ret;
 
        h = ckpt_read_obj_type(ctx, sizeof(*h), CKPT_HDR_SIGNAL);
@@ -497,6 +525,40 @@ static int restore_signal(struct ckpt_ctx *ctx)
        if (ret < 0)
                goto out;
 
+       /* tty - session */
+       if (h->tty_objref) {
+               tty = ckpt_obj_fetch(ctx, h->tty_objref, CKPT_OBJ_TTY);
+               if (IS_ERR(tty)) {
+                       ret = PTR_ERR(tty);
+                       goto out;
+               }
+               /* this will fail unless we're the session leader */
+               ret = tiocsctty(tty, 0);
+               if (ret < 0)
+                       goto out;
+               /* now restore the foreground group (job control) */
+               if (h->tty_pgrp) {
+                       /*
+                        * If tty_pgrp == CKPT_PID_NULL, below will
+                        * fail, so no need for explicit test
+                        */
+                       ret = do_tiocspgrp(tty, tty_pair_get_tty(tty),
+                                          h->tty_pgrp);
+                       if (ret < 0)
+                               goto out;
+               }
+       } else {
+               /*
+                * If tty_objref isn't set, we _keep_ whatever tty we
+                * already have as a ctty. Why does this make sense ?
+                * - If our session is "within" the restart context,
+                * then that session has no controlling terminal.
+                * - If out session is "outside" the restart context,
+                * then we're like to keep whatever we inherit from
+                * the parent pid-ns.
+                */
+       }
+
        /*
         * Reset real/virt/prof itimer (in case they were set), to
         * prevent unwanted signals after flushing current signals
@@ -508,7 +570,20 @@ static int restore_signal(struct ckpt_ctx *ctx)
        do_setitimer(ITIMER_VIRTUAL, &itimer, NULL);
        do_setitimer(ITIMER_PROF, &itimer, NULL);
 
+       /* tty - tty_old_pgrp */
+       if (current->signal->leader && h->tty_old_pgrp != CKPT_PID_NULL) {
+               rcu_read_lock();
+               pgrp = get_pid(_ckpt_find_pgrp(ctx, h->tty_old_pgrp));
+               rcu_read_unlock();
+               if (!pgrp)
+                       goto out;
+       }
+
        spin_lock_irq(&current->sighand->siglock);
+       /* tty - tty_old_pgrp */
+       put_pid(current->signal->tty_old_pgrp);
+       current->signal->tty_old_pgrp = pgrp;
+       /* pending signals */
        pending = &current->signal->shared_pending;
        flush_sigqueue(pending);
        pending->signal = new_pending.signal;
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 0dbf3f0..86946af 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2173,7 +2173,7 @@ static int fionbio(struct file *file, int __user *p)
  *             Takes ->siglock() when updating signal->tty
  */
 
-static int tiocsctty(struct tty_struct *tty, int arg)
+int tiocsctty(struct tty_struct *tty, int arg)
 {
        int ret = 0;
        if (current->signal->leader && (task_session(current) == tty->session))
@@ -2262,10 +2262,10 @@ static int tiocgpgrp(struct tty_struct *tty, struct 
tty_struct *real_tty, pid_t
 }
 
 /**
- *     tiocspgrp               -       attempt to set process group
+ *     do_tiocspgrp            -       attempt to set process group
  *     @tty: tty passed by user
  *     @real_tty: tty side device matching tty passed by user
- *     @p: pid pointer
+ *     @pid: pgrp_nr
  *
  *     Set the process group of the tty to the session passed. Only
  *     permitted where the tty session is our session.
@@ -2273,10 +2273,10 @@ static int tiocgpgrp(struct tty_struct *tty, struct 
tty_struct *real_tty, pid_t
  *     Locking: RCU, ctrl lock
  */
 
-static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, 
pid_t __user *p)
+int do_tiocspgrp(struct tty_struct *tty,
+                struct tty_struct *real_tty, pid_t pgrp_nr)
 {
        struct pid *pgrp;
-       pid_t pgrp_nr;
        int retval = tty_check_change(real_tty);
        unsigned long flags;
 
@@ -2288,8 +2288,6 @@ static int tiocspgrp(struct tty_struct *tty, struct 
tty_struct *real_tty, pid_t
            (current->signal->tty != real_tty) ||
            (real_tty->session != task_session(current)))
                return -ENOTTY;
-       if (get_user(pgrp_nr, p))
-               return -EFAULT;
        if (pgrp_nr < 0)
                return -EINVAL;
        rcu_read_lock();
@@ -2311,6 +2309,27 @@ out_unlock:
 }
 
 /**
+ *     tiocspgrp               -       attempt to set process group
+ *     @tty: tty passed by user
+ *     @real_tty: tty side device matching tty passed by user
+ *     @p: pid pointer
+ *
+ *     Set the process group of the tty to the session passed. Only
+ *     permitted where the tty session is our session.
+ *
+ *     Locking: RCU, ctrl lock
+ */
+
+static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, 
pid_t __user *p)
+{
+       pid_t pgrp_nr;
+
+       if (get_user(pgrp_nr, p))
+               return -EFAULT;
+       return do_tiocspgrp(tty, real_tty, pgrp_nr);
+}
+
+/**
  *     tiocgsid                -       get session id
  *     @tty: tty passed by user
  *     @real_tty: tty side of the tty pased by the user if a pty else the tty
diff --git a/include/linux/checkpoint.h b/include/linux/checkpoint.h
index c7bd9d4..ca91405 100644
--- a/include/linux/checkpoint.h
+++ b/include/linux/checkpoint.h
@@ -99,6 +99,7 @@ extern int restore_read_page(struct ckpt_ctx *ctx, struct 
page *page);
 
 /* pids */
 extern pid_t ckpt_pid_nr(struct ckpt_ctx *ctx, struct pid *pid);
+extern struct pid *_ckpt_find_pgrp(struct ckpt_ctx *ctx, pid_t pgid);
 
 /* socket functions */
 extern int ckpt_sock_getnames(struct ckpt_ctx *ctx,
diff --git a/include/linux/checkpoint_hdr.h b/include/linux/checkpoint_hdr.h
index 549093c..4fe63b1 100644
--- a/include/linux/checkpoint_hdr.h
+++ b/include/linux/checkpoint_hdr.h
@@ -808,13 +808,19 @@ struct ckpt_rlimit {
 
 struct ckpt_hdr_signal {
        struct ckpt_hdr h;
+       /* rlimit */
        struct ckpt_rlimit rlim[CKPT_RLIM_NLIMITS];
+       /* itimer */
        __u64 it_real_value;
        __u64 it_real_incr;
        __u64 it_virt_value;
        __u64 it_virt_incr;
        __u64 it_prof_value;
        __u64 it_prof_incr;
+       /* tty */
+       __s32 tty_objref;
+       __s32 tty_pgrp;
+       __s32 tty_old_pgrp;
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_signal_task {
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 887afd1..e2edb2d 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -504,6 +504,11 @@ extern void tty_ldisc_enable(struct tty_struct *tty);
 /* This one is for ptmx_close() */
 extern int tty_release(struct inode *inode, struct file *filp);
 
+/* These are for checkpoint/restart */
+extern int tiocsctty(struct tty_struct *tty, int arg);
+extern int do_tiocspgrp(struct tty_struct *tty,
+                       struct tty_struct *real_tty, pid_t pgrp_nr);
+
 #ifdef CONFIG_CHECKPOINT
 struct ckpt_ctx;
 struct ckpt_hdr_file;
-- 
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to