Skip to contentSkip to conversation

sys_restore prototype

PATCH In review Serge E. Hallyn 3 participants 7 messages Jul 25, 2008 – Jul 29, 2008 4 messages not in the archive

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover sys_restore prototype

We were talking this morning about what trivial patchset to begin with to get a start on checkpoint and restart. We thought that rather than start with checkpoint, maybe we should start with something that reads a "checkpoint file" and "restarts" a single task. In this case, restart means it sets the process id and executes the file which are found in the checkpoint file.

So here's what we whipped up for a half hour this morning, and during some of Mark's talk this afternoon.

It refuses to run if it isn't the container init, so you must unshare your pidns before calling sys_restore().

To test, I did:

[root@kvm-f9 ~]# cat mycheckpoint
99 /root/whoami
[root@kvm-f9 ~]# cat restore.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()

{
        int ret;
        char *argv[3];
        char *envp[1];

        //argv[0] = argv[1] = "/bin/bash";
        //argv[2] = envp[0] = NULL;
        argv[0] = "/root/whoami";
        argv[1] = envp[0] = NULL;
        int fd = open("/root/mycheckpoint", O_RDONLY);
        if (fd < 0)
                perror("open checkpoint file");
        ret = syscall(327, fd, argv, envp);
        printf("syscall returned %d\n", ret);
        perror("syscall for checkpoint");
        close(fd);
        return ret;
}

[root@kvm-f9 ~]# cat whoami.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()

{
        printf("I am %d\n", getpid());
        return 0;
}

Next, I create a new pid namespace, remount /proc, and
execute 'restore' using 'exec' so that pid 1 is doing it:

[root@kvm-f9 ~]# /home/hallyn/cryo/utils/ns_exec -cp /bin/bash about to clone with 20020000
[root@kvm-f9 ~]# mount -t proc none /proc [root@kvm-f9 ~]# ps -ef

UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  1 18:46 pts/0    00:00:00 /bin/bash
root        26     1  0 18:46 pts/0    00:00:00 ps -ef

[root@kvm-f9 ~]# exec ./restore
I am 99

Seems to work.

-serge

A message that is not in the archive (sent off-list or not yet received): 20080725225655.GA28276-r/[email protected]

#2 lore raw

PATCH 1/2 introduce sys_restore

Create a useless (?) sys_restore system call. All it does is read a "checkpoint file" :) for a pid number and a file to execute.

Since we don't take things like argv and envp and registers from the checkpoint file, in order to make this easily testable, we take those things as arguments.

---
 arch/x86/kernel/process_32.c       |   10 ++++++++
 arch/x86/kernel/syscall_table_32.S |    2 +
 kernel/fork.c                      |   43 ++++++++++++++++++++++++++++++++++++
 3 files changed, 55 insertions(+), 0 deletions(-)
arch/x86/kernel/process_32.c +10 -0
index 0c3927a..e11627d 100644
@@ -688,6 +688,16 @@ out:
 	return error;
 }
 
+long do_restore(unsigned int fd,
+		char __user * __user *argv,
+                char __user * __user *envp,
+		struct pt_regs *regs);
+
+asmlinkage long sys_restore(struct pt_regs regs)
+{
+	return do_restore(regs.bx, regs.cx, regs.dx, &regs);
+}
+
 #define top_esp                (THREAD_SIZE - sizeof(unsigned long))
 #define top_ebp                (THREAD_SIZE - 2*sizeof(unsigned long))
 
arch/x86/kernel/syscall_table_32.S +2 -0
index adff556..019a8e4 100644
@@ -326,3 +326,5 @@ ENTRY(sys_call_table)
 	.long sys_fallocate
 	.long sys_timerfd_settime	/* 325 */
 	.long sys_timerfd_gettime
+	.long sys_restore
+	
kernel/fork.c +43 -0

46 lines not on this page · raw message

Signature · 1 line
1.5.4.3
#3 lore raw

PATCH 2/2 sys_restore: set the pid number

In reply to a message not in the archive

Set the pid number for a restored task. This is purely a toy, as it only sets the pidnr in the lowest level pid namespace.

---
 kernel/fork.c |    5 +++++
 kernel/pid.c  |   19 +++++++++++++++++++
 2 files changed, 24 insertions(+), 0 deletions(-)
kernel/fork.c +5 -0
index 0e43f69..41c46d2 100644
@@ -1685,6 +1685,8 @@ int unshare_files(struct files_struct **displaced)
 char buf[CKPT_SIZE];
 char exe_filename[PAGE_SIZE];
 
+extern int choose_pidmap(struct pid *pid, int new);
+
 /*
  * userspace will already have made us a new pidns
  */
@@ -1717,6 +1719,9 @@ long do_restore(unsigned int fd,
 	if (nr_scanned != 2)
 		return -EINVAL;
 
+	ret = choose_pidmap(task_pid(current), pid);
+	if (!ret)
+		return -EAGAIN;
 
 	ret = do_execve(exe_filename, argv, envp, regs);
 out:
kernel/pid.c +19 -0
index 30bd5d4..88a5e2a 100644
@@ -122,6 +122,25 @@ static void free_pidmap(struct upid *upid)
 	atomic_inc(&map->nr_free);
 }
 
+int choose_pidmap(struct pid *pid, int new)
+{
+	struct pidmap *map;
+	int level = pid->level;
+	struct upid *upid = &pid->numbers[level];
+	struct pid_namespace *pid_ns = upid->ns;
+	int old = upid->nr;
+
+	map = &pid_ns->pidmap[new/BITS_PER_PAGE];
+	if (!test_and_set_bit(new, map->page)) {
+		map = &pid_ns->pidmap[old/BITS_PER_PAGE];
+		clear_bit(old, map->page);
+		upid->nr = new;
+		return 1;
+	}
+
+	return 0;
+}
+
 static int alloc_pidmap(struct pid_namespace *pid_ns)
 {
 	int i, offset, max_scan, pid, last = pid_ns->last_pid;
Signature · 1 line
1.5.4.3

A message that is not in the archive (sent off-list or not yet received): 20080725225935.GB28764-r/[email protected]

#5 lore raw

Re: [Devel] [PATCH 2/2] sys_restore: set the pid number

Quoted 40 lines · Serge E. Hallyn

Set the pid number for a restored task. This is purely a toy, as it only sets the pidnr in the lowest level pid namespace.

---
 kernel/fork.c |    5 +++++
 kernel/pid.c  |   19 +++++++++++++++++++
 2 files changed, 24 insertions(+), 0 deletions(-)
kernel/fork.c +5 -0
index 0e43f69..41c46d2 100644
@@ -1685,6 +1685,8 @@ int unshare_files(struct files_struct **displaced)
 char buf[CKPT_SIZE];
 char exe_filename[PAGE_SIZE];
 
+extern int choose_pidmap(struct pid *pid, int new);
+
 /*
  * userspace will already have made us a new pidns
  */
@@ -1717,6 +1719,9 @@ long do_restore(unsigned int fd,
 	if (nr_scanned != 2)
 		return -EINVAL;
 
+	ret = choose_pidmap(task_pid(current), pid);
+	if (!ret)
+		return -EAGAIN;
 
 	ret = do_execve(exe_filename, argv, envp, regs);
 out:
kernel/pid.c +0 -0
index 30bd5d4..88a5e2a 100644
@@ -122,6 +122,25 @@ static void free_pidmap(struct upid *upid)
 	atomic_inc(&map->nr_free);
 }
 

kernel/pid.c static void free_pidmap(struct upid *upid) · line 134

Quoted 10 lines
kernel/pid.c +10 -0
+int choose_pidmap(struct pid *pid, int new)
+{
+	struct pidmap *map;
+	int level = pid->level;
+	struct upid *upid = &pid->numbers[level];
+	struct pid_namespace *pid_ns = upid->ns;
+	int old = upid->nr;
+
+	map = &pid_ns->pidmap[new/BITS_PER_PAGE];
+	if (!test_and_set_bit(new, map->page)) {

This and...

kernel/pid.c static void free_pidmap(struct upid *upid) · line 136

Quoted 2 lines
kernel/pid.c +2 -0
+		map = &pid_ns->pidmap[old/BITS_PER_PAGE];
+		clear_bit(old, map->page);

this are both a bit buggy, since the bit number on the page is not the same as the pid id itself ;)

Quoted 10 lines
kernel/pid.c +7 -0
+		upid->nr = new;
+		return 1;
+	}
+
+	return 0;
+}
+
 static int alloc_pidmap(struct pid_namespace *pid_ns)
 {
 	int i, offset, max_scan, pid, last = pid_ns->last_pid;

A message that is not in the archive (sent off-list or not yet received): [email protected]

#7 lore raw

Re: [Devel] [PATCH 2/2] sys_restore: set the pid number

Quoted 54 lines · Pavel Emelyanov
Quoted 40 lines · Serge E. Hallyn

Set the pid number for a restored task. This is purely a toy, as it only sets the pidnr in the lowest level pid namespace.

---
 kernel/fork.c |    5 +++++
 kernel/pid.c  |   19 +++++++++++++++++++
 2 files changed, 24 insertions(+), 0 deletions(-)
kernel/fork.c +5 -0
index 0e43f69..41c46d2 100644
@@ -1685,6 +1685,8 @@ int unshare_files(struct files_struct **displaced)
 char buf[CKPT_SIZE];
 char exe_filename[PAGE_SIZE];
 
+extern int choose_pidmap(struct pid *pid, int new);
+
 /*
  * userspace will already have made us a new pidns
  */
@@ -1717,6 +1719,9 @@ long do_restore(unsigned int fd,
 	if (nr_scanned != 2)
 		return -EINVAL;
 
+	ret = choose_pidmap(task_pid(current), pid);
+	if (!ret)
+		return -EAGAIN;
 
 	ret = do_execve(exe_filename, argv, envp, regs);
 out:
kernel/pid.c +0 -0
index 30bd5d4..88a5e2a 100644
@@ -122,6 +122,25 @@ static void free_pidmap(struct upid *upid)
 	atomic_inc(&map->nr_free);
 }
 

kernel/pid.c static void free_pidmap(struct upid *upid) · line 134

Quoted 10 lines
kernel/pid.c +10 -0
+int choose_pidmap(struct pid *pid, int new)
+{
+	struct pidmap *map;
+	int level = pid->level;
+	struct upid *upid = &pid->numbers[level];
+	struct pid_namespace *pid_ns = upid->ns;
+	int old = upid->nr;
+
+	map = &pid_ns->pidmap[new/BITS_PER_PAGE];
+	if (!test_and_set_bit(new, map->page)) {

This and...

Quoted 5 lines

kernel/pid.c static void free_pidmap(struct upid *upid) · line 136

Quoted 2 lines
kernel/pid.c +2 -0
+		map = &pid_ns->pidmap[old/BITS_PER_PAGE];
+		clear_bit(old, map->page);

this are both a bit buggy, since the bit number on the page is not the same as the pid id itself ;)

Oops. Yes, I see.

thanks,
-serge

Quoted 10 lines
Quoted 10 lines
kernel/pid.c +7 -0
+		upid->nr = new;
+		return 1;
+	}
+
+	return 0;
+}
+
 static int alloc_pidmap(struct pid_namespace *pid_ns)
 {
 	int i, offset, max_scan, pid, last = pid_ns->last_pid;
#8 lore raw
In reply to a message not in the archive
Quoted 7 lines · Serge E. Hallyn

We were talking this morning about what trivial patchset to begin with to get a start on checkpoint and restart. We thought that rather than start with checkpoint, maybe we should start with something that reads a "checkpoint file" and "restarts" a single task. In this case, restart means it sets the process id and executes the file which are found in the checkpoint file.

Quoted 5 lines

So here's what we whipped up for a half hour this morning, and during some of Mark's talk this afternoon.

It refuses to run if it isn't the container init, so you must unshare your pidns before calling sys_restore().

A reasonable approximation.

Dave Hansen made a good point when he asked how do we graft a restored checkpoint into the rest of the system. Requiring us to unshare everything we intend to unshare before restore achieves this easily, and you are following in that model.

That leads to an interesting implication. We don't need to set the pid of the first process. At most we can verify that the pid is the same. If we have unshared the pid namespace the pid will be 1 and the needed pid of the first process will be 1.

More later.

Eric

A message that is not in the archive (sent off-list or not yet received): [email protected]

#10 lore raw
Quoted 22 lines · Eric W. Biederman
Quoted 7 lines · Serge E. Hallyn

We were talking this morning about what trivial patchset to begin with to get a start on checkpoint and restart. We thought that rather than start with checkpoint, maybe we should start with something that reads a "checkpoint file" and "restarts" a single task. In this case, restart means it sets the process id and executes the file which are found in the checkpoint file.

Quoted 5 lines

So here's what we whipped up for a half hour this morning, and during some of Mark's talk this afternoon.

It refuses to run if it isn't the container init, so you must unshare your pidns before calling sys_restore().

A reasonable approximation.

Dave Hansen made a good point when he asked how do we graft a restored checkpoint into the rest of the system. Requiring us to unshare everything we intend to unshare before restore achieves this easily, and you are following in that model.

Quoted 6 lines

That leads to an interesting implication. We don't need to set the pid of the first process. At most we can verify that the pid is the same. If we have unshared the pid namespace the pid will be 1 and the needed pid of the first process will be 1.

More later.

Good point. Sounds like our trivial prototype was still way over-featureful :)

-serge