OpenVZ Forum


Home » Mailing lists » Devel » [PATCH 1/2] signal checkpoint: define /proc/pid/sig/
[PATCH 2/2] signal c/r: implement /proc/pid/sig writing [message #18833 is a reply to message #18832] Fri, 08 June 2007 15:54 Go to previous messageGo to previous message
serue is currently offline  serue
Messages: 750
Registered: February 2006
Senior Member
>From 0fc34dcb54fe80ea720225825ad1dcb1b847d8ab Mon Sep 17 00:00:00 2001
From: Serge E. Hallyn <serue@us.ibm.com>
Date: Thu, 17 May 2007 17:28:07 -0400
Subject: [PATCH 2/2] signal c/r: implement /proc/pid/sig writing

Allow restore through writes to /proc/pid/sig/*, except for
the waiters file.  Waits must be restored by the waiter actually
running wait.

To test writes to the action file I use the included handlertest.c.
Start it up in one terminal as
	./handlertest 1
It should print "using handler 1"
in another terminal
	pid=`ps -ef | grep handlertest | grep -v grep | awk '{ print $2 '}`
	cat /proc/$pid/sig/action > action
	kill -USR1 $pid
handlertest should print "handler 1 called"

You can repeat this with
	./handlertest 2
to make sure it does what you expect with the second signal handler.

Restart handlertest with a different signal handler:
	./handlertest 2
It prints "using handler 2"
Overwrite it's sigactions from another terminal
	pid=`ps -ef | grep handlertest | grep -v grep | awk '{ print $2 '}`
	cat action > /proc/$pid/sig/action
and send it a USR1
	kill -USR1 $pid
and it should say "handler 1 called".

=====================================================================
handlertest.c
=====================================================================

void handler1(int sig)
{
	printf("handler 1 called\n");
}

void handler2(int sig)
{
	printf("handler 2 called\n");
}

int main(int argc, char *argv[])
{
	int hnum;
	__sighandler_t h = handler1;

	if (argc<2) {
		printf("usage: %s [1|2]\n", argv[0]);
		exit(2);
	}
	hnum = atoi(argv[1]);
	if (hnum == 1) {
		printf("using handler 1\n");
	} else {
		h = handler2;
		printf("using handler 2\n");
	}
	signal(SIGUSR1, h);

	sleep(100);
}

Signed-off-by: Serge E. Hallyn <serue@us.ibm.com>
---
 fs/proc/base.c         |   97 +++++++++++++++++++++-
 include/linux/signal.h |    2 +
 kernel/signal.c        |  218 +++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 313 insertions(+), 4 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 8e0dd7a..22817bb 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1701,9 +1701,104 @@ static ssize_t proc_pid_sig_read(struct file * file, char __user * buf,
 	return length;
 }
 
+struct proc_pid_sig_partial {
+	char *buf;
+	loff_t pos;
+	size_t count;
+};
+
+static struct proc_pid_sig_partial *make_partial(char *page, int start, int total_count)
+{
+	struct proc_pid_sig_partial *partial;
+
+	partial = kzalloc(sizeof(*partial), GFP_KERNEL);
+	if (!partial)
+		return NULL;
+	partial->buf = page;
+	partial->pos = start;
+	partial->count = total_count;
+	return partial;
+}
+
+static ssize_t proc_pid_sig_write(struct file * file, const char __user * buf,
+				   size_t count, loff_t *ppos)
+{
+	struct dentry * dentry = file->f_path.dentry;
+	struct inode * inode = dentry->d_inode;
+	char *page;
+	ssize_t length;
+	struct task_struct *task = get_proc_task(inode);
+	struct proc_pid_sig_partial *partial;
+	int partial_size = 0, total_count;
+
+	length = -ESRCH;
+	if (!task)
+		goto out_no_task;
+
+	partial = file->private_data;
+	file->private_data = NULL;
+	if (partial)
+		partial_size = partial->count - partial->pos;
+	total_count = count + partial_size;
+
+	printk(KERN_NOTICE "%s: 1\n", __FUNCTION__);
+	length = -ENOMEM;
+	page = kmalloc(total_count, GFP_USER);
+	if (!page)
+		goto out_put_task;
+	printk(KERN_NOTICE "%s: 2\n", __FUNCTION__);
+
+	if (partial) {
+		memcpy(page, partial->buf + partial->pos, partial_size);
+		kfree(partial->buf);
+		kfree(partial);
+	}
+
+	printk(KERN_NOTICE "%s: 3\n", __FUNCTION__);
+	length = -EFAULT;
+	if (copy_from_user(page+partial_size, buf, count))
+		goto out_free_page;
+
+	length = task_write_procsig(task,
+				      (char*)file->f_path.dentry->d_name.name,
+				      (void*)page, total_count);
+
+	printk(KERN_NOTICE "%s: 4, length was %d, count %d totcnt %d\n", __FUNCTION__,
+			length, count, total_count);
+	if (length >= 0 && length < total_count) {
+		/* should i just allocate a new buffer for just the unread portion? */
+		file->private_data = make_partial(page, length+1, total_count);
+		if (!file->private_data)
+			length = -ENOMEM;
+		else
+			goto out_put_task; /* don't free page, partial points to it */
+	}
+
+out_free_page:
+	kfree(page);
+out_put_task:
+	put_task_struct(task);
+out_no_task:
+	if (length >= 0)
+		return count;
+	return length;
+}
+
+static int proc_pid_sig_release(struct inode *inode, struct file *file)
+{
+	struct proc_pid_sig_partial *partial = file->private_data;
+
+	if (partial) {
+		kfree(partial->buf);
+		kfree(partial);
+	}
+	return 0;
+}
+
 static const struct file_operations proc_sig_attr_operations = {
 	.read		= proc_pid_sig_read,
-//	.write		= proc_pid_sig_write,
+	.write		= proc_pid_sig_write,
+	.release	= proc_pid_sig_release,
 };
 
 
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 6863543..2e6d64c 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -244,6 +244,8 @@ extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
 
 extern struct kmem_cache *sighand_cachep;
 extern int task_read_procsig(struct task_struct *p, char *name, char **value);
+extern int task_write_procsig(struct task_struct *p, char *name, void *value,
+			size_t size);
 
 /*
  * In POSIX a signal is sent either to a specific thread (Linux task)
diff --git a/kernel/signal.c b/kernel/signal.c
index a2a3ebe..dc50e1b 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2614,7 +2614,7 @@ static int print_sigpending_alloc(char **bufp, struct sigpending *pending)
 
 	list_for_each_entry(q, &pending->list, list) {
 		info = &q->info;
-		if (p-buf+215 > alloced) {
+		if (p-buf+221 > alloced) {
 			int len=p-buf;
 			char *buf2;
 			alloced += PAGE_SIZE;
@@ -2629,8 +2629,8 @@ static int print_sigpending_alloc(char **bufp, struct sigpending *pending)
 			p = buf+len;
 		}
 
-		p += sprintf(p, "sig %d: user %d flags %d",
-			info->si_signo, (int)q->user->uid, q->flags);
+		p += sprintf(p, "sig %d: uid %d pid %d flags %d",
+			info->si_signo, (int)q->user->uid, info->si_pid, q->flags);
 		p += sprintf(p, " errno %d code %d\n",
 			info->si_errno, info->si_code);
 
@@ -2739,3 +2739,215 @@ int task_read_procsig(struct task_struct *p, char *name, char **value)
 
 	return ret;
 }
+
+static int set_sigset(sigset_t *sig, char *value, int size)
+{
+	int i;
+
+	if (size < _NSIG)
+		return -EINVAL;
+	sigemptyset(sig);
+	for (i=0; i<_NSIG; i++)
+		if (value[i] == '1')
+			sigaddset(sig, i);
+	return 0;
+}
+
+static char *next_eol(char *s, int maxlen)
+{
+	int len=0;
+	while (len<maxlen && *s!='\0' && *s !='\n')
+		s++, len++;
+	if (len < maxlen)
+		return s;
+	return NULL;
+}
+
+static int set_sigpending(struct task_struct *t, struct sigpending *pending,
+			  char *value, int size)
+{
+	struct sigqueue *q;
+	int ret;
+#ifdef __ARCH_SI_TRAPNO
+	int trapno;
+#endif
+
+	if (set_sigset(&pending->signal, value, size))
+		return -EINVAL;
+
+	size -= _NSIG+1;
+	value += _NSIG+1;
+	while (size) {
+		int signum, uid, pid, flags, errno, code, status, fd;
+		unsigned long utime, stime, addr, band;
+		char *start, *eol = next_eol(value, size);
+
+		if (!eol)
+			return 0;
+		
+		size -= (eol - value) + 1;
+		start = eol+1;
+		ret = sscanf(value, "sig %d: uid %d pid %d flags %d errno %d code %d\n",
+			&signum, &uid, &pid, &flags, &errno, &code);
+		if (ret != 6)
+			goto out;
+		q = __sigqueue_alloc(t, GFP_KERNEL, 1);
+		if (!q)
+			goto out;
+		q->info.si_signo = signum;
+		q->info.si_errno = errno;
+		q->info.si_code = code;
+		q->info.si_uid = uid;
+		q->info.si_pid = pid;
+
+		switch(signum) {
+			/* XXX skipping posix1b timers and signals for now */
+			default: break;
+			case SIGKILL:
+				eol = next_eol(start, size);
+				if (!eol)
+					goto out;
+				size -= (eol - start) + 1;
+				ret = sscanf(start, " pid %d uid %d\n", &pid, &uid);
+				if (ret != 2)
+					goto out;
+				q->info._sifields._kill._pid = pid;
+				q->info._sifields._kill._uid = uid;
+				break;
+
+			case SIGCHLD:
+				eol = next_eol(start, size);
+				if (!eol)
+					goto out;
+				size -= (eol - start) + 1;
+				ret = sscanf(start, "pid %d uid %d status %d utime %lu stime %lu\n",
+					&pid, &uid, &status, &utime, &stime);
+				if (ret != 5)
+					goto out;
+				q->info._sifields._sigchld._pid = pid;
+				q->info._sifields._sigchld._uid = uid;
+				q->info._sifields._sigchld._status = status;
+				q->info._sifields._sigchld._utime = utime;
+				q->info._sifields._sigchld._stime = stime;
+				break;
+
+			case SIGILL:
+			case SIGFPE:
+			case SIGSEGV:
+			case SIGBUS:
+				eol = next_eol(start, size);
+				if (!eol)
+					goto out;
+				size -= (eol - start) + 1;
+#ifdef __ARCH_SI_TRAPNO
+				ret = sscanf(start, " addr %lu trapno %d\n", &addr, &trapno);
+				if (ret != 2)
+					goto out;
+				q->info._sifields._sigfault._trapno = trapno;
+#else
+				ret = sscanf(start, " addr %lu\n", &addr);
+				if (ret != 1)
+					goto out;
+#endif
+				q->info._sifields._sigfault._addr = (void __user *)addr;
+				break;
+
+			case SIGPOLL:
+				eol = next_eol(start, size);
+				if (!eol)
+					goto out;
+				size -= (eol - start) + 1;
+				ret = sscanf(start, " band %ld fd %d\n", &band, &fd);
+				if (ret != 2)
+					goto out;
+				q->info._sifields._sigpoll._band = band;
+				q->info._sifields._sigpoll._fd = fd;
+				break;
+		}
+		start = eol+1;
+		list_add_tail(&q->list, &pending->list);
+	}
+
+out:
+	return size;
+}
+
+static int s
...

 
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Previous Topic: [PATCH] se401: fix "&& 0x" typo
Next Topic: [PATCH 2.6.21-rc6] [netfilter] early_drop imrovement
Goto Forum:
  


Current Time: Wed Oct 08 08:06:54 GMT 2025

Total time taken to generate the page: 0.09520 seconds