public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] task ornaments
@ 2002-01-25 18:54 David Howells
  0 siblings, 0 replies; 2+ messages in thread
From: David Howells @ 2002-01-25 18:54 UTC (permalink / raw)
  To: torvalds; +Cc: hch, mingo, linux-kernel, dhowells


Hi Linus,

Given application of the syscall latency patch #1, the attached patch adds
task ornaments to 2.5.3-pre5, which:

   * permit notification of certain major process events (such as signals,
     exec, fork/clone, exit, syscall entry/exit).

   * will permit ptrace() stuff to be done without task reparenting.

   * will make it easier to produce a Wine support module.

   * may make it possible to abstract out the parent signal notification.

   * (mingo@redhat.com has also expressed interest with respect to tux).

   * (hch@caldera.com has also expressed interest with respect to the linux
     ABI stuff).

Most notable are the changes to the following files:

	include/linux/sched.h
	include/linux/taskornament.h
	kernel/taskornament.c

David

diff -uNr linux-work-253p5/arch/i386/kernel/ptrace.c linux-orn-253p5/arch/i386/kernel/ptrace.c
--- linux-work-253p5/arch/i386/kernel/ptrace.c	Fri Jan 25 15:01:07 2002
+++ linux-orn-253p5/arch/i386/kernel/ptrace.c	Fri Jan 25 17:25:46 2002
@@ -13,6 +13,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/taskornament.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -456,9 +457,12 @@
 __attribute__((regparm(3)))
 void do_syscall_trace(struct pt_regs *regs, int entryexit)
 {
+	task_ornament_notify_syscall(regs,entryexit);
+
 	if ((current->ptrace & (PT_PTRACED|PT_SYSCALLTRACE)) !=
 	    (PT_PTRACED|PT_SYSCALLTRACE))
 		return;
+
 	/* the 0x80 provides a way for the tracing parent to distinguish
 	   between a syscall stop and SIGTRAP delivery */
 	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
@@ -484,7 +488,5 @@
 void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
 		      struct task_work work_pending)
 {
-	/* deal with pending signal delivery */
-	if (work_pending.sigpending)
-		do_signal(regs,oldset);
+	task_ornament_notify_resume(regs,oldset,work_pending);
 }
diff -uNr linux-work-253p5/arch/i386/kernel/signal.c linux-orn-253p5/arch/i386/kernel/signal.c
--- linux-work-253p5/arch/i386/kernel/signal.c	Fri Jan 25 15:01:07 2002
+++ linux-orn-253p5/arch/i386/kernel/signal.c	Fri Jan 25 16:35:57 2002
@@ -20,6 +20,7 @@
 #include <linux/stddef.h>
 #include <linux/tty.h>
 #include <linux/personality.h>
+#include <linux/taskornament.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/i387.h>
@@ -606,6 +607,27 @@
 		if (!signr)
 			break;
 
+		if (!list_empty(&current->ornaments)) {
+			int action = task_ornament_notify_signal(signr,&info);
+			switch (action) {
+			case 0: /* no action */
+				break;
+			case -1: /* cancelled */
+				continue;
+				
+			default:
+				/* change of signal
+				 * - if the (new) signal is now blocked, requeue it
+				 */
+				signr = action;
+				if (sigismember(&current->blocked,signr)) {
+					send_sig_info(signr,&info,current);
+					continue;
+				}
+				break;
+			}
+		}
+
 		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
 			/* Let the debugger run.  */
 			current->exit_code = signr;
diff -uNr linux-work-253p5/fs/exec.c linux-orn-253p5/fs/exec.c
--- linux-work-253p5/fs/exec.c	Fri Jan 25 14:53:15 2002
+++ linux-orn-253p5/fs/exec.c	Fri Jan 25 16:35:57 2002
@@ -35,6 +35,7 @@
 #include <linux/highmem.h>
 #include <linux/spinlock.h>
 #include <linux/personality.h>
+#include <linux/taskornament.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 
@@ -548,6 +549,9 @@
 	if (retval) goto mmap_failed;
 
 	/* This is the point of no return */
+	if (!list_empty(&current->ornaments))
+		task_ornament_notify_execve();
+
 	release_old_signals(oldsig);
 
 	current->sas_ss_sp = current->sas_ss_size = 0;
diff -uNr linux-work-253p5/fs/proc/base.c linux-orn-253p5/fs/proc/base.c
--- linux-work-253p5/fs/proc/base.c	Fri Jan 25 14:53:15 2002
+++ linux-orn-253p5/fs/proc/base.c	Fri Jan 25 16:36:57 2002
@@ -26,6 +26,7 @@
 #include <linux/seq_file.h>
 #include <linux/namespace.h>
 #include <linux/mm.h>
+#include <linux/taskornament.h>
 
 /*
  * For hysterical raisins we keep the same inumbers as in the old procfs.
@@ -289,6 +290,19 @@
 	release:	mounts_release,
 };
 
+static ssize_t pid_taskornlist_read(struct file * file, char * buf,
+				size_t count, loff_t *ppos)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	struct task_struct *task = inode->u.proc_i.task;
+
+	return proc_pid_read_taskornlist(task, file, buf, count, ppos);
+}
+
+static struct file_operations proc_taskornlist_operations = {
+	read:		pid_taskornlist_read,
+};
+
 #define PROC_BLOCK_SIZE	(3*1024)		/* 4K page size but our output routines use some slack for overruns */
 
 static ssize_t proc_info_read(struct file * file, char * buf,
@@ -541,6 +555,7 @@
 	PROC_PID_MAPS,
 	PROC_PID_CPU,
 	PROC_PID_MOUNTS,
+	PROC_PID_TASKORN,
 	PROC_PID_FD_DIR = 0x8000,	/* 0x8000-0xffff */
 };
 
@@ -557,6 +572,7 @@
 #endif
   E(PROC_PID_MAPS,	"maps",		S_IFREG|S_IRUGO),
   E(PROC_PID_MEM,	"mem",		S_IFREG|S_IRUSR|S_IWUSR),
+  E(PROC_PID_TASKORN,	"ornaments",	S_IFREG|S_IRUGO),
   E(PROC_PID_CWD,	"cwd",		S_IFLNK|S_IRWXUGO),
   E(PROC_PID_ROOT,	"root",		S_IFLNK|S_IRWXUGO),
   E(PROC_PID_EXE,	"exe",		S_IFLNK|S_IRWXUGO),
@@ -920,6 +936,9 @@
 			inode->i_op = &proc_mem_inode_operations;
 			inode->i_fop = &proc_mem_operations;
 			break;
+		case PROC_PID_TASKORN:
+			inode->i_fop = &proc_taskornlist_operations;
+			break;
 		case PROC_PID_MOUNTS:
 			inode->i_fop = &proc_mounts_operations;
 			break;
diff -uNr linux-work-253p5/include/linux/init_task.h linux-orn-253p5/include/linux/init_task.h
--- linux-work-253p5/include/linux/init_task.h	Fri Jan 25 15:12:17 2002
+++ linux-orn-253p5/include/linux/init_task.h	Fri Jan 25 17:07:21 2002
@@ -86,6 +86,7 @@
     pending:		{ NULL, &tsk.pending.head, {{0}}},		\
     blocked:		{{0}},						\
     alloc_lock:		SPIN_LOCK_UNLOCKED,				\
+    ornaments:		LIST_HEAD_INIT(tsk.ornaments),			\
     journal_info:	NULL,						\
 }
 
diff -uNr linux-work-253p5/include/linux/sched.h linux-orn-253p5/include/linux/sched.h
--- linux-work-253p5/include/linux/sched.h	Fri Jan 25 15:05:45 2002
+++ linux-orn-253p5/include/linux/sched.h	Fri Jan 25 17:44:28 2002
@@ -364,6 +364,9 @@
 /* Protection of (de-)allocation: mm, files, fs, tty */
 	spinlock_t alloc_lock;
 
+/* Task ornaments */
+	struct list_head ornaments;	/* modify: hold alloc_lock and sigmask_lock */
+
 /* journalling filesystem info */
 	void *journal_info;
 };
diff -uNr linux-work-253p5/include/linux/taskornament.h linux-orn-253p5/include/linux/taskornament.h
--- linux-work-253p5/include/linux/taskornament.h	Thu Jan  1 01:00:00 1970
+++ linux-orn-253p5/include/linux/taskornament.h	Fri Jan 25 17:48:28 2002
@@ -0,0 +1,192 @@
+/* taskornament.h: task ornament definitions
+ *
+ * (c) Copyright 2001   David Howells (dhowells@redhat.com)
+ */
+
+#ifndef _H_F92CE22E_93FF_11D4_8781_0000C0005742
+#define _H_F92CE22E_93FF_11D4_8781_0000C0005742
+
+#ifdef __KERNEL__
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <asm/atomic.h>
+
+struct task_ornament_operations;
+struct task_ornament;
+struct task_struct;
+
+/*****************************************************************************/
+/*
+ * ornament that can be strung onto a task to intercept important task events
+ */
+struct task_ornament
+{
+	struct list_head	to_list;
+	struct task_ornament_operations *to_ops;
+	struct task_struct	*to_task;		/* owner task */
+	atomic_t		to_count;
+	int			to_magic;
+	unsigned short		to_order;		/* list ordering priority (lowest first) */
+	unsigned short		to_nfy_resume : 1;	/* invoke resumption operation */
+	void			*to_data;
+	void			*to_data2;
+};
+
+/*****************************************************************************/
+/*
+ * the operations that allow an ornament to intercept task events
+ * - all ops but close() and proc_read() will be called in the context of the owner process
+ */
+struct task_ornament_operations
+{
+	/* ornament name */
+	const char *name;
+
+	/* responsible module */
+	struct module *owner;
+
+	/* default ornament sort key */
+	unsigned short def_order;
+
+	/* destructor
+	 * - can sleep
+	 */
+	void (*close)(struct task_ornament *ornament);
+
+	/* ornament specific information request
+	 * - called from /proc/<pid>/ornaments implementation
+	 * - must terminate any text it adds with newline chars
+	 * - should return the next text insertion point
+	 * - can sleep
+	 */
+	char *(*proc_read)(struct task_ornament *ornament, char *ptr, char *end);
+
+	/* notification of exit (status in exit_code)
+	 * - current->flags will have been marked PF_EXITING
+	 * - the big kernel lock will be held by do_exit();
+	 * - can sleep
+	 */
+	void (*exit)(struct task_ornament *ornament, int exit_code);
+
+	/* notification of execve
+	 * - can add/remove ornaments (including itself)
+	 * - can sleep
+	 */
+	void (*execve)(struct task_ornament *ornament);
+
+	/* notification that fork/clone has set up the new process and
+	 * is just about to dispatch it
+	 * - ornaments have to copy themselves to the child
+	 * - can add/remove ornaments (including itself)
+	 * - can sleep
+	 */
+	void (*fork)(struct task_ornament *ornament,
+		     struct task_struct *child,
+		     unsigned long clone_flags);
+
+	/* notification of pending resumption of userspace execution
+	 * - only called if orn->to_work is set and task->ornwork is set
+	 * - can sleep, but preferred not to
+	 * - can add/remove ornaments (including itself)
+	 */
+	void (*resume)(struct task_ornament *ornament);
+
+	/* notification of pending signal delivery
+	 * - set *action to -1 to cancel the signal
+	 * - set *action to new signal number and update *info to change the signal
+	 * - leave *action unchanged otherwise
+	 * - *action and *info may already have been changed by a previous ornament
+	 * - can sleep
+	 * - can add/remove ornaments (including itself)
+	 */
+	void (*signal)(struct task_ornament *ornament, int signr, siginfo_t *info, int *action);
+
+	/* syscall trace hook
+	 * - entryexit is 0 on entry, 1 on exit
+	 */
+	void (*syscall_trace)(struct task_ornament *ornament, struct pt_regs *regs, int entryexit);
+};
+
+#define TASK_ORNAMENT_MAGIC 0x54614572
+
+#define task_ornament_valid(to) ((to)->to_magic==TASK_ORNAMENT_MAGIC)
+
+static __inline__
+void ornget(struct task_ornament *orn)
+{
+	atomic_inc(&orn->to_count);
+}
+
+extern void __ornput(struct task_ornament *orn);
+static __inline__
+void ornput(struct task_ornament *orn)
+{
+	if (atomic_dec_and_test(&orn->to_count))
+		__ornput(orn);
+}
+
+extern void task_ornament_init(void);
+extern struct task_ornament *task_ornament_alloc(struct task_ornament_operations *);
+extern int  __task_ornament_add(struct task_struct *target, struct task_ornament *orn);
+extern void __task_ornament_remove(struct task_struct *target, struct task_ornament *orn);
+extern void exit_task_ornaments(int exit_code);
+extern int  task_ornament_notify_signal(int signr, siginfo_t *info);
+extern void task_ornament_notify_execve(void);
+extern void task_ornament_notify_fork(struct task_struct *child, unsigned long clone_flags);
+extern int  task_ornament_request_resume_service(struct task_ornament *orn);
+
+extern asmlinkage
+void FASTCALL(task_ornament_notify_syscall(struct pt_regs *regs, int entryexit));
+
+extern asmlinkage
+void FASTCALL(task_ornament_notify_resume(struct pt_regs *regs, sigset_t *oldset,
+					  struct task_work work_pending));
+
+extern asmlinkage
+int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
+
+extern void syscall_trace(void);
+
+extern struct task_ornament *__task_ornament_find(struct task_struct *target,
+						  const struct task_ornament_operations *type);
+
+static __inline__
+int task_ornament_add(struct task_struct *target, struct task_ornament *orn)
+{
+	int ret;
+	task_lock(target);
+	ret = __task_ornament_add(target,orn);
+	task_unlock(target);
+	return ret;
+}
+
+static __inline__
+void task_ornament_remove(struct task_struct *target, struct task_ornament *orn)
+{
+	task_lock(target);
+	__task_ornament_remove(target,orn);
+	task_unlock(target);
+	ornput(orn);
+}
+
+static __inline__
+struct task_ornament *task_ornament_find(struct task_struct *target,
+					 const struct task_ornament_operations *type)
+{
+	struct task_ornament *result;
+	task_lock(target);
+	result = __task_ornament_find(target,type);
+	task_unlock(target);
+	return result;
+}
+
+extern struct file_operations task_ornament_ptrace_operations;
+extern ssize_t proc_pid_read_taskornlist(struct task_struct *tsk, struct file *file,
+					 char *buf, size_t count, loff_t *ppos);
+
+#endif /* __KERNEL__ */
+
+#endif /* _H_F92CE22E_93FF_11D4_8781_0000C0005742 */
diff -uNr linux-work-253p5/kernel/Makefile linux-orn-253p5/kernel/Makefile
--- linux-work-253p5/kernel/Makefile	Fri Jan 25 14:53:17 2002
+++ linux-orn-253p5/kernel/Makefile	Fri Jan 25 16:37:51 2002
@@ -10,12 +10,12 @@
 O_TARGET := kernel.o
 
 export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \
-		printk.o device.o
+		printk.o device.o taskornament.o
 
 obj-y     = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
 	    sysctl.o acct.o capability.o ptrace.o timer.o user.o \
-	    signal.o sys.o kmod.o context.o device.o
+	    signal.o sys.o kmod.o context.o device.o taskornament.o
 
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += ksyms.o
diff -uNr linux-work-253p5/kernel/exit.c linux-orn-253p5/kernel/exit.c
--- linux-work-253p5/kernel/exit.c	Fri Jan 25 14:53:17 2002
+++ linux-orn-253p5/kernel/exit.c	Fri Jan 25 16:38:47 2002
@@ -18,6 +18,7 @@
 #include <linux/acct.h>
 #endif
 #include <linux/file.h>
+#include <linux/taskornament.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -458,7 +459,6 @@
 	 *	as a result of our exiting, and if they have any stopped
 	 *	jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
 	 */
-
 	write_lock_irq(&tasklist_lock);
 	current->state = TASK_ZOMBIE;
 	do_notify_parent(current, current->exit_signal);
@@ -530,6 +530,7 @@
 	if (tsk->binfmt && tsk->binfmt->module)
 		__MOD_DEC_USE_COUNT(tsk->binfmt->module);
 
+	exit_task_ornaments(code);
 	tsk->exit_code = code;
 	exit_notify();
 	schedule();
diff -uNr linux-work-253p5/kernel/fork.c linux-orn-253p5/kernel/fork.c
--- linux-work-253p5/kernel/fork.c	Fri Jan 25 15:01:07 2002
+++ linux-orn-253p5/kernel/fork.c	Fri Jan 25 16:40:22 2002
@@ -22,6 +22,7 @@
 #include <linux/namespace.h>
 #include <linux/personality.h>
 #include <linux/file.h>
+#include <linux/taskornament.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -677,6 +678,13 @@
 	if (retval)
 		goto bad_fork_cleanup_namespace;
 	p->semundo = NULL;
+
+	/*
+	 * tell attached ornaments that they may want to duplicate themselves
+	 */
+	INIT_LIST_HEAD(&p->ornaments);
+	if (!list_empty(&current->ornaments))
+		task_ornament_notify_fork(p,clone_flags);
 	
 	/* Our parent execution domain becomes current domain
 	   These must match for thread signalling to apply */
@@ -829,4 +837,6 @@
 			SLAB_HWCACHE_ALIGN, NULL, NULL);
 	if(!mm_cachep)
 		panic("vma_init: Cannot alloc mm_struct SLAB cache");
+
+	task_ornament_init();
 }
diff -uNr linux-work-253p5/kernel/taskornament.c linux-orn-253p5/kernel/taskornament.c
--- linux-work-253p5/kernel/taskornament.c	Thu Jan  1 01:00:00 1970
+++ linux-orn-253p5/kernel/taskornament.c	Fri Jan 25 17:51:39 2002
@@ -0,0 +1,695 @@
+/* taskornament.c: task ornament handling
+ *
+ * Copyright (c) 2001   David Howells (dhowells@redhat.com)
+ */
+#include <linux/sched.h>
+#include <linux/taskornament.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+EXPORT_SYMBOL(__ornput);
+EXPORT_SYMBOL(task_ornament_alloc);
+EXPORT_SYMBOL(__task_ornament_add);
+EXPORT_SYMBOL(__task_ornament_remove);
+EXPORT_SYMBOL(__task_ornament_find);
+EXPORT_SYMBOL(task_ornament_request_resume_service);
+
+//#define ktrace(FMT,...) printk("[%05d] "FMT,current->pid,##__VA_ARGS__)
+#define ktrace(FMT,...)
+
+#define task_ornament_buoy_init(x)				\
+do {								\
+	INIT_LIST_HEAD(&(x)->to_list);				\
+	(x)->to_ops = NULL;					\
+	atomic_set(&(x)->to_count,0x3fffffff);			\
+	(x)->to_magic = TASK_ORNAMENT_MAGIC;			\
+} while(0)
+
+static inline void __add_orn(struct task_struct *target, struct task_ornament *orn,
+			     struct task_ornament *after)
+{
+	list_add(&orn->to_list,&after->to_list);
+}
+
+static inline void __remove_orn(struct task_struct *target, struct task_ornament *orn)
+{
+	list_del(&orn->to_list);
+}
+
+/* SLAB cache for task_ornament structures */
+static kmem_cache_t *task_ornament_cachep;
+
+void __init task_ornament_init(void)
+{
+	task_ornament_cachep =
+		kmem_cache_create("task_ornament", sizeof(struct task_ornament), 0,
+				  0, NULL, NULL);
+	if (!task_ornament_cachep)
+		panic("cannot create task ornament SLAB cache");
+}
+
+/*****************************************************************************/
+/*
+ * allocate a task ornament
+ */
+struct task_ornament *task_ornament_alloc(struct task_ornament_operations *ops)
+{
+	struct task_ornament *orn;
+
+	orn = (struct task_ornament *) kmem_cache_alloc(task_ornament_cachep,SLAB_KERNEL);
+	if (orn) {
+		INIT_LIST_HEAD(&orn->to_list);
+		orn->to_task = NULL;
+		orn->to_ops = ops;
+		if (ops->owner)
+			__MOD_INC_USE_COUNT(ops->owner);
+		atomic_set(&orn->to_count,1);
+		orn->to_magic = TASK_ORNAMENT_MAGIC;
+		orn->to_order = ops->def_order;
+	}
+
+	return orn;
+} /* end task_ornament_alloc() */
+
+/*****************************************************************************/
+/*
+ * destroy an ornament
+ * - to_count should already be zero
+ */
+void __ornput(struct task_ornament *orn)
+{
+	struct task_ornament_operations *ops = orn->to_ops;
+
+	if (ops->close)
+		ops->close(orn);
+	if (ops->owner)
+		__MOD_DEC_USE_COUNT(ops->owner);
+
+	kmem_cache_free(task_ornament_cachep,orn);
+} /* end __ornput() */
+
+/*****************************************************************************/
+/*
+ * add an ornament to a task
+ * - must be called holding task_lock(target)
+ * - returns 0 if successful, -ESRCH if the target process is a zombie or is exiting
+ */
+int __task_ornament_add(struct task_struct *target, struct task_ornament *orn)
+{
+	struct list_head *_ptr;
+	int ret;
+
+	ktrace("==>__task_ornament_add(%d,%p)\n",target->pid,orn);
+
+	if (!task_ornament_valid(orn))
+		panic("Adding invalid task ornament: %p [caller %p]\n",
+		      orn,__builtin_return_address(0));
+
+	ret = -ESRCH;
+	if (target->state!=TASK_ZOMBIE && !(target->flags&PF_EXITING)) {
+		list_for_each(_ptr,&target->ornaments) {
+			struct task_ornament *ptr = list_entry(_ptr,struct task_ornament,to_list);
+			if (ptr->to_order>orn->to_order)
+				break;
+		}
+
+		list_add_tail(&orn->to_list,_ptr);
+		ornget(orn);
+		orn->to_task = target;
+		ret = 0;
+	}
+
+	ktrace("<== __task_ornament_add() = %d\n",ret);
+
+	return ret;
+} /* end __task_ornament_add() */
+
+/*****************************************************************************/
+/*
+ * remove an ornament from a task
+ * - does nothing if the target process is a zombie or is exiting
+ * - doesn't decrement the ornament usage count (since the destructor might sleep)
+ */
+void __task_ornament_remove(struct task_struct *target, struct task_ornament *orn)
+{
+	ktrace("==>__task_ornament_remove(%d,%p)\n",target->pid,orn);
+
+	if (!task_ornament_valid(orn))
+		panic("Removing invalid task ornament: %p [caller %p]\n",
+		      orn,__builtin_return_address(0));
+
+	if (target->state!=TASK_ZOMBIE && !(target->flags&PF_EXITING)) {
+		list_del(&orn->to_list);
+		orn->to_task = NULL;
+	}
+
+	ktrace("<==__task_ornament_remove()\n");
+} /* end __task_ornament_remove() */
+
+/*****************************************************************************/
+/*
+ * find an ornament of a particular type attached to a specific task
+ * - note that if an ornament is returned, then its counter will be incremented
+ * - must be called holding task_lock(target)
+ */
+struct task_ornament *__task_ornament_find(struct task_struct *target,
+					   const struct task_ornament_operations *type)
+{
+	struct task_ornament *orn;
+	struct list_head *ptr;
+
+	if (!type) return NULL;
+
+	for (ptr=target->ornaments.next; ptr!=&target->ornaments; ptr=ptr->next) {
+		orn = list_entry(ptr,struct task_ornament,to_list);
+
+		if (!task_ornament_valid(orn))
+			panic("Find: invalid task ornament: %p [caller %p]\n",
+			      orn,__builtin_return_address(0));
+
+		if (orn->to_ops==type)
+			goto found;
+	}
+
+	return NULL;
+
+ found:
+	ornget(orn);
+	return orn;
+} /* end __task_ornament_find() */
+
+/*****************************************************************************/
+/*
+ * send exit notifications to the current process's ornaments
+ * - this'll be called from exit_notify() in kernel/signal.c
+ * - do_exit() holds the big kernel lock
+ * - the ornaments are removed from the list before they are notified
+ * - addition is prevented by PF_EXITING in current->flags
+ */
+void exit_task_ornaments(int exit_code)
+{
+	struct task_ornament *orn;
+	struct task_struct *tsk = current;
+
+	ktrace("==>exit_task_ornaments()\n");
+
+	/* eat the list */
+	task_lock(tsk);
+	while (!list_empty(&tsk->ornaments)) {
+		orn = list_entry(tsk->ornaments.next,struct task_ornament,to_list);
+		tsk->ornaments.next = orn->to_list.next;
+		task_unlock(tsk);
+
+		if (!task_ornament_valid(orn))
+			panic("Exit: invalid task ornament: %p\n",orn);
+
+		if (orn->to_ops && orn->to_ops->exit)
+			orn->to_ops->exit(orn,exit_code);
+		orn->to_task = NULL;
+
+		ornput(orn);
+		task_lock(tsk);
+	}
+
+	task_unlock(tsk);
+
+	ktrace("<==exit_task_ornaments()\n");
+
+} /* end exit_task_ornaments() */
+
+/*****************************************************************************/
+/*
+ * perform various tasks immediately prior to resuming userspace execution
+ * - deal with pending signals
+ * - poll ornaments that are requesting resumption notification
+ */
+void task_ornament_notify_resume(struct pt_regs *regs, sigset_t *oldset,
+				 struct task_work work_pending)
+{
+	struct task_ornament buoy, *orn;
+	struct task_struct *tsk = current;
+	struct list_head *ptr;
+
+	ktrace("==>task_ornament_notify_resume(%p,%p,%08x)\n",
+	       regs,oldset,*(__u32*)&work_pending);
+
+	/* deal with pending signal delivery */
+	if (work_pending.sigpending)
+		do_signal(regs,oldset);
+
+	/* deal with resumption notification */
+	if (work_pending.notify_resume) {
+		task_ornament_buoy_init(&buoy);
+		tsk->work.notify_resume = 0;
+
+		/* loop through all task ornaments, but be careful in case the
+		 * list is rearranged. The buoy is used as a marker between the current
+		 * position and the next
+		 */
+		task_lock(tsk);
+
+		ptr = tsk->ornaments.next;
+		while (ptr != &tsk->ornaments) {
+			/* find the next ornament with a resume op */
+			orn = list_entry(ptr,struct task_ornament,to_list);
+
+			if (!task_ornament_valid(orn))
+				panic("Resume: invalid task ornament: %p\n",orn);
+
+			if (!orn->to_ops || !orn->to_ops->execve || !orn->to_nfy_resume) {
+				ptr = ptr->next;
+				continue;
+			}
+
+			/* make sure the ornament doesn't evaporate yet */
+			ornget(orn);
+
+			/* mark the queue so we know where our next ornament is */
+			buoy.to_order = orn->to_order;
+			__add_orn(tsk,&buoy,orn);
+			task_unlock(tsk);
+
+			/* call the operation */
+			orn->to_ops->resume(orn);
+			ornput(orn);
+
+			/* remove the marker */
+			task_lock(tsk);
+			ptr = buoy.to_list.next;
+			__remove_orn(tsk,&buoy);
+		}
+
+		task_unlock(tsk);
+	}
+
+	ktrace("<==task_ornament_notify_resume()\n");
+} /* end task_ornament_notify_resume() */
+
+/*****************************************************************************/
+/*
+ * send signal delivery notifications to the current process's ornaments
+ * - returns 0 to keep the signal
+ * - returns -1 to cancel the signal immediately
+ * - returns new signal number to change the signal (and has updated *info)
+ * - this'll be called from notify_parent() in kernel/signal.c
+ * - the list is _not_ locked whilst the notification routine is running
+ *   - a buoy is placed in the list to mark the next ornament to be processed
+ */
+int task_ornament_notify_signal(int signr, siginfo_t *info)
+{
+	struct task_ornament buoy, *orn;
+	struct task_struct *tsk = current;
+	struct list_head *ptr;
+	int action;
+
+	ktrace("==>task_ornament_notify_signal(%d,%p)\n",signr,info);
+
+	task_ornament_buoy_init(&buoy);
+
+	/* loop through all task ornaments, but be careful in case the list is
+	 * rearranged. The buoy is used as a marker between the current
+	 * position and the next
+	 */
+	task_lock(tsk);
+
+	action = 0;
+	ptr = tsk->ornaments.next;
+	while (ptr != &tsk->ornaments) {
+		/* find the next ornament with a signal op */
+		orn = list_entry(ptr,struct task_ornament,to_list);
+
+		if (!task_ornament_valid(orn))
+			panic("Signal: invalid task ornament: %p\n",orn);
+
+		if (!orn->to_ops || !orn->to_ops->signal) {
+			ptr = ptr->next;
+			continue;
+		}
+
+		/* make sure the ornament doesn't evaporate yet */
+		ornget(orn);
+
+		/* mark the queue so we know where our next ornament is */
+		buoy.to_order = orn->to_order;
+		__add_orn(tsk,&buoy,orn);
+		task_unlock(tsk);
+
+		/* call the operation */
+		orn->to_ops->signal(orn,signr,info,&action);
+		ornput(orn);
+
+		/* remove the marker */
+		task_lock(tsk);
+		ptr = buoy.to_list.next;
+		__remove_orn(tsk,&buoy);
+	}
+
+	task_unlock(tsk);
+
+	ktrace("<==task_ornament_notify_signal() = %d\n",action);
+
+	return action;
+} /* end task_ornament_notify_signal() */
+
+/*****************************************************************************/
+/*
+ * notify an ornament of the current process execve'ing itself
+ * - this'll be called from flush_old_exec() in kernel/exec.c
+ * - the list is _not_ locked whilst the notification routine is running
+ *   - a buoy is placed in the list to mark the next ornament to be processed
+ */
+void task_ornament_notify_execve(void)
+{
+	struct task_ornament buoy, *orn;
+	struct task_struct *tsk = current;
+	struct list_head *ptr;
+
+	ktrace("==>task_ornament_notify_execve()\n");
+
+	task_ornament_buoy_init(&buoy);
+
+	/* loop through all task ornaments, but be careful in case the
+	 * list is rearranged. The buoy is used as a marker between the current
+	 * position and the next
+	 */
+	task_lock(tsk);
+
+	ptr = tsk->ornaments.next;
+	while (ptr != &tsk->ornaments) {
+		/* find the next ornament with an execve op */
+		orn = list_entry(ptr,struct task_ornament,to_list);
+
+		if (!task_ornament_valid(orn))
+			panic("Execve: invalid task ornament: %p\n",orn);
+
+		if (!orn->to_ops || !orn->to_ops->execve) {
+			ptr = ptr->next;
+			continue;
+		}
+
+		/* make sure the ornament doesn't evaporate yet */
+		ornget(orn);
+
+		/* mark the queue so we know where our next ornament is */
+		buoy.to_order = orn->to_order;
+		__add_orn(tsk,&buoy,orn);
+		task_unlock(tsk);
+
+		/* call the operation */
+		orn->to_ops->execve(orn);
+		ornput(orn);
+
+		/* remove the marker */
+		task_lock(tsk);
+		ptr = buoy.to_list.next;
+		__remove_orn(tsk,&buoy);
+	}
+
+	task_unlock(tsk);
+
+	ktrace("<==task_ornament_notify_execve()\n");
+
+} /* end task_ornament_notify_execve() */
+
+/*****************************************************************************/
+/*
+ * notify an ornament of the current process forking/cloning itself
+ * - this'll be called from do_fork() in kernel/fork.c
+ * - the list is _not_ locked whilst the notification routine is running
+ *   - a buoy is placed in the list to mark the next ornament to be processed
+ *   - a second buoy is placed at the end of the list to prevent processing of
+ *     ornaments added during processing
+ */
+void task_ornament_notify_fork(struct task_struct *child, unsigned long clone_flags)
+{
+	struct task_ornament buoy, *orn;
+	struct task_struct *tsk = current;
+	struct list_head *ptr;
+
+	ktrace("==>task_ornament_notify_fork(%d,%lu)\n",child->pid,clone_flags);
+
+	task_ornament_buoy_init(&buoy);
+
+	/* loop through all task ornaments, but be careful in case the
+	 * list is rearranged. The buoy is used as a marker between the current
+	 * position and the next
+	 */
+	task_lock(tsk);
+
+	ptr = tsk->ornaments.next;
+	while (ptr != &tsk->ornaments) {
+		/* skip over buoys from other processors */
+		if (ptr==&buoy.to_list)
+			break;
+
+		orn = list_entry(ptr,struct task_ornament,to_list);
+
+		if (!task_ornament_valid(orn))
+			panic("Fork: invalid task ornament: %p\n",orn);
+
+		if (!orn->to_ops || !orn->to_ops->fork) {
+			ptr = ptr->next;
+			break;
+		}
+
+		/* make sure the ornament doesn't evaporate yet */
+		ornget(orn);
+
+		/* mark the queue so we know where our next ornament is */
+		buoy.to_order = orn->to_order;
+		__add_orn(tsk,&buoy,orn);
+		task_unlock(tsk);
+
+		/* call the operation */
+		orn->to_ops->fork(orn,child,clone_flags);
+		ornput(orn);
+
+		/* remove the marker */
+		task_lock(tsk);
+		ptr = buoy.to_list.next;
+ 		__remove_orn(tsk,&buoy);
+	}
+
+	task_unlock(tsk);
+
+	ktrace("<==task_ornament_notify_fork()\n");
+
+} /* end task_ornament_notify_fork() */
+
+/*****************************************************************************/
+/*
+ * notify an ornament of the current process entering or exiting a syscall
+ * - this'll be called from syscall_trace() in arch/xxx/kernel/ptrace.c
+ * - the list is _not_ locked whilst the notification routine is running
+ *   - a buoy is placed in the list to mark the next ornament to be processed
+ *   - a second buoy is placed at the end of the list to prevent processing of
+ *     ornaments added during processing
+ */
+void task_ornament_notify_syscall(struct pt_regs *regs, int entryexit)
+{
+	struct task_ornament buoy, *orn;
+	struct task_struct *tsk = current;
+	struct list_head *ptr;
+
+	ktrace("==>task_ornament_notify_syscall(%d)\n",entryexit);
+
+	task_ornament_buoy_init(&buoy);
+
+	/* loop through all task ornaments, but be careful in case the
+	 * list is rearranged. The buoy is used as a marker between the current
+	 * position and the next
+	 */
+	task_lock(tsk);
+
+	ptr = tsk->ornaments.next;
+	while (ptr != &tsk->ornaments) {
+		if (ptr==&buoy.to_list)
+			break;
+
+		orn = list_entry(ptr,struct task_ornament,to_list);
+
+		if (!task_ornament_valid(orn))
+			panic("SyscallTrace: invalid task ornament: %p\n",orn);
+
+		if (!orn->to_ops || !orn->to_ops->execve) {
+			ptr = ptr->next;
+			continue;
+		}
+
+		/* make sure the ornament doesn't evaporate yet */
+		ornget(orn);
+
+		/* mark the queue so we know where our next ornament is */
+		buoy.to_order = orn->to_order;
+		__add_orn(tsk,&buoy,orn);
+		task_unlock(tsk);
+
+		/* call the operation */
+		orn->to_ops->syscall_trace(orn,regs,entryexit);
+		ornput(orn);
+
+		/* remove the marker */
+		task_lock(tsk);
+		ptr = buoy.to_list.next;
+		__remove_orn(tsk,&buoy);
+	}
+
+	task_unlock(tsk);
+
+	ktrace("<==task_ornament_notify_syscall()\n");
+} /* end task_ornament_notify_syscall() */
+
+/*****************************************************************************/
+/*
+ * request userspace resumption notification service for an ornament on a task
+ */
+int task_ornament_request_resume_service(struct task_ornament *orn)
+{
+	struct task_struct *tsk;
+	int ret = -ESRCH;
+
+	ktrace("==>task_ornament_request_resume_service(%p)\n",orn);
+
+	read_lock(&tasklist_lock);
+
+	tsk = orn->to_task;
+	printk("-- setting flag on %p\n",tsk);
+	if (tsk) {
+		printk("-- (pid %d)\n",tsk->pid);
+		task_lock(tsk);
+		orn->to_nfy_resume = 1;
+		tsk->work.notify_resume = 1;
+		task_unlock(tsk);
+		ret = 0;
+	}
+
+	read_unlock(&tasklist_lock);
+
+	ktrace("<==task_ornament_request_resume_service() = %d\n",ret);
+
+	return ret;
+} /* end task_ornament_request_resume_service() */
+
+/*****************************************************************************/
+/*
+ * read a list of task ornaments attached to a process
+ * - MSW of file offset is ornament index
+ * - LSW of file offset is line position
+ */
+ssize_t proc_pid_read_taskornlist(struct task_struct *tsk, struct file *file,
+				  char *ubuf, size_t count, loff_t *ppos)
+{
+	struct task_ornament *orn;
+	struct list_head *_ptr;
+	char *scratch = NULL, *curr, *buf = NULL;
+	ssize_t ret;
+	loff_t npos;
+	int index, qty, pos;
+
+	/* get some scratch space */
+	ret = -ENOMEM;
+	buf = (char*) __get_free_page(GFP_KERNEL);
+	if (!buf)
+		goto out;
+
+	scratch = (char*) __get_free_page(GFP_KERNEL);
+	if (!scratch)
+		goto out;
+
+	/* get the n'th task ornament next */
+	npos = *ppos;
+	ret = 0;
+	while (count>0) {
+		index = npos >> 16;
+		orn = NULL;
+
+		task_lock(tsk);
+
+		list_for_each(_ptr,&tsk->ornaments) {
+			orn = list_entry(_ptr,struct task_ornament,to_list);
+			if (!orn->to_ops)
+				continue; /* ignore markers inserted into the list */
+			if (index==0)
+				break;
+			index--;
+		}
+
+		if (_ptr==&tsk->ornaments) {
+			task_unlock(tsk);
+			break;
+		}
+
+		/* make sure the ornament doesn't evaporate yet */
+		ornget(orn);
+		task_unlock(tsk);
+
+		/* make notes on this ornament */
+		curr = scratch;
+		curr += sprintf(curr,
+				"%s %p usage=%03d order=%04x\n"
+				"%s",
+				orn->to_ops->name,
+				orn,
+				atomic_read(&orn->to_count),
+				orn->to_order,
+				orn->to_nfy_resume ? " - Resume Service Requested\n" : "");
+
+		/* call the information gathering operation */
+		if (orn->to_ops->proc_read)
+			curr = orn->to_ops->proc_read(orn,curr,scratch+PAGE_SIZE-1);
+		ornput(orn);
+
+		/* distill the appropriate amount to the buffer */
+		qty = curr - scratch;
+		pos = npos & 0xFFFF;
+		npos -= pos;
+		if (pos < qty) {
+			/* some of the current scratch buffer should be transferred */
+			curr = scratch + pos;
+			qty -= pos;
+
+			if (qty > count) {
+				/* partial copy */
+				memcpy(buf+ret,curr,count);
+				ret += count;
+				qty -= count;
+				count = 0;
+			}
+			else {
+				/* complete copy */
+				memcpy(buf+ret,curr,qty);
+				ret += qty;
+				count += qty;
+				qty = 0;
+			}
+
+		}
+		else {
+			/* already read everything this ornament has to offer */
+			qty = 0;
+		}
+
+		if (qty==0)
+			npos += 0x10000;
+		else
+			npos += qty;
+	}
+
+	if (ret>count) BUG();
+
+	/* write the results to userspace */
+	if (ret>0) {
+		if (copy_to_user(ubuf,buf,ret))
+			ret = -EFAULT;
+		else
+			*ppos = npos;
+	}
+
+ out:
+	if (scratch) free_page((unsigned long)scratch);
+	if (buf) free_page((unsigned long)buf);
+	return ret;
+
+} /* end proc_pid_read_taskornlist() */

^ permalink raw reply	[flat|nested] 2+ messages in thread

* [PATCH] task ornaments
@ 2002-02-11 17:31 David Howells
  0 siblings, 0 replies; 2+ messages in thread
From: David Howells @ 2002-02-11 17:31 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel


Hi Linus,

The attached patch does the following:

 * adds task ornaments, which:

   * permit notification of certain major process events (such as signals,
     exec, fork/clone, exit, syscall entry/exit).

   * will permit ptrace() stuff to be done without task reparenting.

   * will make it easier to produce a Wine support module.

   * may make it possible to abstract out the parent signal notification.

   * (mingo@redhat.com has also expressed interest with respect to tux).

   * (hch@caldera.com has also expressed interest with respect to the linux
     ABI stuff).

   * (davidm@hpl.hp.com has also expressed interest with respect to the IA64
     performance monitor).

Most notable are the changes to the following files:

	include/linux/taskornament.h
	kernel/taskornament.c

David

diff -uNr linux-2.5.4/arch/i386/kernel/ptrace.c linux-orn-254/arch/i386/kernel/ptrace.c
--- linux-2.5.4/arch/i386/kernel/ptrace.c	Mon Feb 11 09:41:32 2002
+++ linux-orn-254/arch/i386/kernel/ptrace.c	Mon Feb 11 09:52:36 2002
@@ -13,6 +13,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/taskornament.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -449,6 +450,9 @@
 {
 	if (!test_thread_flag(TIF_SYSCALL_TRACE))
 		return;
+
+	task_ornament_notify_syscall(regs,entryexit);
+
 	if (!(current->ptrace & PT_PTRACED))
 		return;
 	/* the 0x80 provides a way for the tracing parent to distinguish
diff -uNr linux-2.5.4/arch/i386/kernel/signal.c linux-orn-254/arch/i386/kernel/signal.c
--- linux-2.5.4/arch/i386/kernel/signal.c	Mon Feb 11 09:41:32 2002
+++ linux-orn-254/arch/i386/kernel/signal.c	Mon Feb 11 09:44:11 2002
@@ -20,6 +20,7 @@
 #include <linux/stddef.h>
 #include <linux/tty.h>
 #include <linux/personality.h>
+#include <linux/taskornament.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/i387.h>
@@ -606,6 +607,27 @@
 		if (!signr)
 			break;
 
+		if (!list_empty(&current->ornaments)) {
+			int action = task_ornament_notify_signal(signr,&info);
+			switch (action) {
+			case 0: /* no action */
+				break;
+			case -1: /* cancelled */
+				continue;
+				
+			default:
+				/* change of signal
+				 * - if the (new) signal is now blocked, requeue it
+				 */
+				signr = action;
+				if (sigismember(&current->blocked,signr)) {
+					send_sig_info(signr,&info,current);
+					continue;
+				}
+				break;
+			}
+		}
+
 		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
 			/* Let the debugger run.  */
 			current->exit_code = signr;
@@ -724,4 +746,7 @@
 	/* deal with pending signal delivery */
 	if (thread_info_flags & _TIF_SIGPENDING)
 		do_signal(regs,oldset);
+
+	if (thread_info_flags & _TIF_NOTIFY_RESUME)
+		task_ornament_notify_resume(regs);
 }
diff -uNr linux-2.5.4/fs/exec.c linux-orn-254/fs/exec.c
--- linux-2.5.4/fs/exec.c	Mon Feb 11 09:41:34 2002
+++ linux-orn-254/fs/exec.c	Mon Feb 11 09:45:13 2002
@@ -36,6 +36,7 @@
 #include <linux/spinlock.h>
 #include <linux/personality.h>
 #include <linux/binfmts.h>
+#include <linux/taskornament.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 
@@ -549,6 +550,9 @@
 	if (retval) goto mmap_failed;
 
 	/* This is the point of no return */
+	if (!list_empty(&current->ornaments))
+		task_ornament_notify_execve();
+
 	release_old_signals(oldsig);
 
 	current->sas_ss_sp = current->sas_ss_size = 0;
diff -uNr linux-2.5.4/fs/proc/base.c linux-orn-254/fs/proc/base.c
--- linux-2.5.4/fs/proc/base.c	Mon Feb 11 09:41:35 2002
+++ linux-orn-254/fs/proc/base.c	Mon Feb 11 09:44:11 2002
@@ -26,6 +26,7 @@
 #include <linux/seq_file.h>
 #include <linux/namespace.h>
 #include <linux/mm.h>
+#include <linux/taskornament.h>
 
 /*
  * For hysterical raisins we keep the same inumbers as in the old procfs.
@@ -295,6 +296,19 @@
 	release:	mounts_release,
 };
 
+static ssize_t pid_taskornlist_read(struct file * file, char * buf,
+				size_t count, loff_t *ppos)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	struct task_struct *task = proc_task(inode);
+
+	return proc_pid_read_taskornlist(task, file, buf, count, ppos);
+}
+
+static struct file_operations proc_taskornlist_operations = {
+	read:		pid_taskornlist_read,
+};
+
 #define PROC_BLOCK_SIZE	(3*1024)		/* 4K page size but our output routines use some slack for overruns */
 
 static ssize_t proc_info_read(struct file * file, char * buf,
@@ -547,6 +561,7 @@
 	PROC_PID_MAPS,
 	PROC_PID_CPU,
 	PROC_PID_MOUNTS,
+	PROC_PID_TASKORN,
 	PROC_PID_FD_DIR = 0x8000,	/* 0x8000-0xffff */
 };
 
@@ -563,6 +578,7 @@
 #endif
   E(PROC_PID_MAPS,	"maps",		S_IFREG|S_IRUGO),
   E(PROC_PID_MEM,	"mem",		S_IFREG|S_IRUSR|S_IWUSR),
+  E(PROC_PID_TASKORN,	"ornaments",	S_IFREG|S_IRUGO),
   E(PROC_PID_CWD,	"cwd",		S_IFLNK|S_IRWXUGO),
   E(PROC_PID_ROOT,	"root",		S_IFLNK|S_IRWXUGO),
   E(PROC_PID_EXE,	"exe",		S_IFLNK|S_IRWXUGO),
@@ -937,6 +953,9 @@
 			inode->i_op = &proc_mem_inode_operations;
 			inode->i_fop = &proc_mem_operations;
 			break;
+		case PROC_PID_TASKORN:
+			inode->i_fop = &proc_taskornlist_operations;
+			break;
 		case PROC_PID_MOUNTS:
 			inode->i_fop = &proc_mounts_operations;
 			break;
diff -uNr linux-2.5.4/include/linux/init_task.h linux-orn-254/include/linux/init_task.h
--- linux-2.5.4/include/linux/init_task.h	Mon Feb 11 09:41:35 2002
+++ linux-orn-254/include/linux/init_task.h	Mon Feb 11 14:59:41 2002
@@ -76,6 +76,7 @@
     pending:		{ NULL, &tsk.pending.head, {{0}}},		\
     blocked:		{{0}},						\
     alloc_lock:		SPIN_LOCK_UNLOCKED,				\
+    ornaments:		LIST_HEAD_INIT(tsk.ornaments),			\
     journal_info:	NULL,						\
 }
 
diff -uNr linux-2.5.4/include/linux/sched.h linux-orn-254/include/linux/sched.h
--- linux-2.5.4/include/linux/sched.h	Mon Feb 11 09:41:35 2002
+++ linux-orn-254/include/linux/sched.h	Mon Feb 11 14:53:06 2002
@@ -345,6 +345,9 @@
 /* Protection of (de-)allocation: mm, files, fs, tty */
 	spinlock_t alloc_lock;
 
+/* Task ornaments */
+	struct list_head ornaments;	/* must hold alloc_lock to walk/modify */
+
 /* journalling filesystem info */
 	void *journal_info;
 };
diff -uNr linux-2.5.4/include/linux/taskornament.h linux-orn-254/include/linux/taskornament.h
--- linux-2.5.4/include/linux/taskornament.h	Thu Jan  1 01:00:00 1970
+++ linux-orn-254/include/linux/taskornament.h	Mon Feb 11 14:53:08 2002
@@ -0,0 +1,193 @@
+/* taskornament.h: task ornament definitions
+ *
+ * (c) Copyright 2001   David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version
+ */
+
+#ifndef _LINUX_TASKORNAMENT_H
+#define _LINUX_TASKORNAMENT_H
+
+#ifdef __KERNEL__
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <asm/atomic.h>
+
+struct task_ornament_operations;
+struct task_ornament;
+struct task_struct;
+
+/*****************************************************************************/
+/*
+ * ornament that can be strung onto a task to intercept important task events
+ */
+struct task_ornament
+{
+	struct list_head	to_list;
+	struct task_ornament_operations *to_ops;
+	struct task_struct	*to_task;		/* owner task */
+	atomic_t		to_count;
+	int			to_magic;
+	unsigned short		to_order;		/* list ordering priority (lowest first) */
+	unsigned short		to_flags;		/* ornament flags */
+	void			*to_data;
+	void			*to_data2;
+};
+
+#define TOF_REQ_NFY_RESUME	0x0001	/* T if requesting notification of u-space resumption */
+
+/*****************************************************************************/
+/*
+ * the operations that allow an ornament to intercept task events
+ * - all ops but close() and proc_read() will be called in the context of the owner process
+ */
+struct task_ornament_operations
+{
+	/* ornament name */
+	const char *name;
+
+	/* responsible module */
+	struct module *owner;
+
+	/* default ornament sort key */
+	unsigned short def_order;
+
+	/* destructor
+	 * - can sleep
+	 */
+	void (*close)(struct task_ornament *ornament);
+
+	/* ornament specific information request
+	 * - called from /proc/<pid>/ornaments implementation
+	 * - must terminate any text it adds with newline chars
+	 * - should return the next text insertion point
+	 * - can sleep
+	 */
+	char *(*proc_read)(struct task_ornament *ornament, char *ptr, char *end);
+
+	/* notification of exit (status in exit_code)
+	 * - current->flags will have been marked PF_EXITING
+	 * - the big kernel lock will be held by do_exit();
+	 * - can sleep
+	 */
+	void (*exit)(struct task_ornament *ornament, int exit_code);
+
+	/* notification of execve
+	 * - can add/remove ornaments (including itself)
+	 * - can sleep
+	 */
+	void (*execve)(struct task_ornament *ornament);
+
+	/* notification that fork/clone has set up the new process and
+	 * is just about to dispatch it
+	 * - ornaments have to copy themselves to the child
+	 * - can add/remove ornaments (including itself)
+	 * - can sleep
+	 */
+	void (*fork)(struct task_ornament *ornament,
+		     struct task_struct *child,
+		     unsigned long clone_flags);
+
+	/* notification of pending resumption of userspace execution
+	 * - only called if orn->to_work is set and task->ornwork is set
+	 * - can sleep, but preferred not to
+	 * - can add/remove ornaments (including itself)
+	 */
+	void (*resume)(struct task_ornament *ornament);
+
+	/* notification of pending signal delivery
+	 * - set *action to -1 to cancel the signal
+	 * - set *action to new signal number and update *info to change the signal
+	 * - leave *action unchanged otherwise
+	 * - *action and *info may already have been changed by a previous ornament
+	 * - can sleep
+	 * - can add/remove ornaments (including itself)
+	 */
+	void (*signal)(struct task_ornament *ornament, int signr, siginfo_t *info, int *action);
+
+	/* syscall trace hook
+	 * - entryexit is 0 on entry, 1 on exit
+	 */
+	void (*syscall_trace)(struct task_ornament *ornament, struct pt_regs *regs, int entryexit);
+};
+
+#define TASK_ORNAMENT_MAGIC 0x54614572
+
+#define task_ornament_valid(to) ((to)->to_magic==TASK_ORNAMENT_MAGIC)
+
+static __inline__
+void ornget(struct task_ornament *orn)
+{
+	atomic_inc(&orn->to_count);
+}
+
+extern void __ornput(struct task_ornament *orn);
+static __inline__
+void ornput(struct task_ornament *orn)
+{
+	if (atomic_dec_and_test(&orn->to_count))
+		__ornput(orn);
+}
+
+extern void task_ornament_init(void);
+extern struct task_ornament *task_ornament_alloc(struct task_ornament_operations *);
+extern int  __task_ornament_add(struct task_struct *target, struct task_ornament *orn);
+extern void __task_ornament_remove(struct task_struct *target, struct task_ornament *orn);
+extern void exit_task_ornaments(int exit_code);
+extern int  task_ornament_notify_signal(int signr, siginfo_t *info);
+extern void task_ornament_notify_execve(void);
+extern void task_ornament_notify_fork(struct task_struct *child, unsigned long clone_flags);
+extern int  task_ornament_request_notify_resume(struct task_ornament *orn);
+
+extern
+void FASTCALL(task_ornament_notify_syscall(struct pt_regs *regs, int entryexit));
+
+extern
+void FASTCALL(task_ornament_notify_resume(struct pt_regs *regs));
+
+extern struct task_ornament *__task_ornament_find(struct task_struct *target,
+						  const struct task_ornament_operations *type);
+
+static __inline__
+int task_ornament_add(struct task_struct *target, struct task_ornament *orn)
+{
+	int ret;
+	task_lock(target);
+	ret = __task_ornament_add(target,orn);
+	task_unlock(target);
+	return ret;
+}
+
+static __inline__
+void task_ornament_remove(struct task_struct *target, struct task_ornament *orn)
+{
+	task_lock(target);
+	__task_ornament_remove(target,orn);
+	task_unlock(target);
+	ornput(orn);
+}
+
+static __inline__
+struct task_ornament *task_ornament_find(struct task_struct *target,
+					 const struct task_ornament_operations *type)
+{
+	struct task_ornament *result;
+	task_lock(target);
+	result = __task_ornament_find(target,type);
+	task_unlock(target);
+	return result;
+}
+
+extern struct file_operations task_ornament_ptrace_operations;
+extern ssize_t proc_pid_read_taskornlist(struct task_struct *tsk, struct file *file,
+					 char *buf, size_t count, loff_t *ppos);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_TASKORNAMENT_H */
diff -uNr linux-2.5.4/kernel/Makefile linux-orn-254/kernel/Makefile
--- linux-2.5.4/kernel/Makefile	Wed Feb  6 07:56:17 2002
+++ linux-orn-254/kernel/Makefile	Mon Feb 11 09:44:21 2002
@@ -10,12 +10,12 @@
 O_TARGET := kernel.o
 
 export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \
-		printk.o 
+		printk.o taskornament.o
 
 obj-y     = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
 	    sysctl.o acct.o capability.o ptrace.o timer.o user.o \
-	    signal.o sys.o kmod.o context.o 
+	    signal.o sys.o kmod.o context.o taskornament.o
 
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += ksyms.o
diff -uNr linux-2.5.4/kernel/exit.c linux-orn-254/kernel/exit.c
--- linux-2.5.4/kernel/exit.c	Mon Feb 11 09:41:35 2002
+++ linux-orn-254/kernel/exit.c	Mon Feb 11 09:45:44 2002
@@ -19,6 +19,7 @@
 #endif
 #include <linux/file.h>
 #include <linux/binfmts.h>
+#include <linux/taskornament.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -462,7 +463,6 @@
 	 *	as a result of our exiting, and if they have any stopped
 	 *	jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
 	 */
-
 	write_lock_irq(&tasklist_lock);
 	current->state = TASK_ZOMBIE;
 	do_notify_parent(current, current->exit_signal);
@@ -534,6 +534,7 @@
 	if (tsk->binfmt && tsk->binfmt->module)
 		__MOD_DEC_USE_COUNT(tsk->binfmt->module);
 
+	exit_task_ornaments(code);
 	tsk->exit_code = code;
 	exit_notify();
 	schedule();
diff -uNr linux-2.5.4/kernel/fork.c linux-orn-254/kernel/fork.c
--- linux-2.5.4/kernel/fork.c	Mon Feb 11 09:41:35 2002
+++ linux-orn-254/kernel/fork.c	Mon Feb 11 09:46:13 2002
@@ -24,6 +24,7 @@
 #include <linux/file.h>
 #include <linux/binfmts.h>
 #include <linux/fs.h>
+#include <linux/taskornament.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -722,6 +723,13 @@
 	if (retval)
 		goto bad_fork_cleanup_namespace;
 	p->semundo = NULL;
+
+	/*
+	 * tell attached ornaments that they may want to duplicate themselves
+	 */
+	INIT_LIST_HEAD(&p->ornaments);
+	if (!list_empty(&current->ornaments))
+		task_ornament_notify_fork(p,clone_flags);
 	
 	/* Our parent execution domain becomes current domain
 	   These must match for thread signalling to apply */
@@ -874,4 +882,6 @@
 			SLAB_HWCACHE_ALIGN, NULL, NULL);
 	if(!mm_cachep)
 		panic("vma_init: Cannot alloc mm_struct SLAB cache");
+
+	task_ornament_init();
 }
diff -uNr linux-2.5.4/kernel/taskornament.c linux-orn-254/kernel/taskornament.c
--- linux-2.5.4/kernel/taskornament.c	Thu Jan  1 01:00:00 1970
+++ linux-orn-254/kernel/taskornament.c	Mon Feb 11 14:50:24 2002
@@ -0,0 +1,692 @@
+/* taskornament.c: task ornament handling
+ *
+ * Copyright (c) 2001   David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version
+ */
+#include <linux/sched.h>
+#include <linux/taskornament.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+EXPORT_SYMBOL_GPL(__ornput);
+EXPORT_SYMBOL_GPL(task_ornament_alloc);
+EXPORT_SYMBOL_GPL(__task_ornament_add);
+EXPORT_SYMBOL_GPL(__task_ornament_remove);
+EXPORT_SYMBOL_GPL(__task_ornament_find);
+EXPORT_SYMBOL_GPL(task_ornament_request_notify_resume);
+
+//#define ktrace(FMT,...) printk("[%05d] "FMT,current->pid,##__VA_ARGS__)
+#define ktrace(FMT,...)
+
+#define task_ornament_buoy_init(x)				\
+do {								\
+	INIT_LIST_HEAD(&(x)->to_list);				\
+	(x)->to_ops = NULL;					\
+	atomic_set(&(x)->to_count,0x3fffffff);			\
+	(x)->to_magic = TASK_ORNAMENT_MAGIC;			\
+} while(0)
+
+static inline void __add_orn(struct task_struct *target, struct task_ornament *orn,
+			     struct task_ornament *after)
+{
+	list_add(&orn->to_list,&after->to_list);
+}
+
+static inline void __remove_orn(struct task_struct *target, struct task_ornament *orn)
+{
+	list_del(&orn->to_list);
+}
+
+/* SLAB cache for task_ornament structures */
+static kmem_cache_t *task_ornament_cachep;
+
+void __init task_ornament_init(void)
+{
+	task_ornament_cachep =
+		kmem_cache_create("task_ornament", sizeof(struct task_ornament), 0,
+				  0, NULL, NULL);
+	if (!task_ornament_cachep)
+		panic("cannot create task ornament SLAB cache");
+}
+
+/*****************************************************************************/
+/*
+ * allocate a task ornament
+ */
+struct task_ornament *task_ornament_alloc(struct task_ornament_operations *ops)
+{
+	struct task_ornament *orn;
+
+	orn = (struct task_ornament *) kmem_cache_alloc(task_ornament_cachep,SLAB_KERNEL);
+	if (orn) {
+		INIT_LIST_HEAD(&orn->to_list);
+		orn->to_task = NULL;
+		orn->to_ops = ops;
+		if (ops->owner)
+			__MOD_INC_USE_COUNT(ops->owner);
+		atomic_set(&orn->to_count,1);
+		orn->to_magic = TASK_ORNAMENT_MAGIC;
+		orn->to_order = ops->def_order;
+	}
+
+	return orn;
+} /* end task_ornament_alloc() */
+
+/*****************************************************************************/
+/*
+ * destroy an ornament
+ * - to_count should already be zero
+ */
+void __ornput(struct task_ornament *orn)
+{
+	struct task_ornament_operations *ops = orn->to_ops;
+
+	if (ops->close)
+		ops->close(orn);
+	if (ops->owner)
+		__MOD_DEC_USE_COUNT(ops->owner);
+
+	kmem_cache_free(task_ornament_cachep,orn);
+} /* end __ornput() */
+
+/*****************************************************************************/
+/*
+ * add an ornament to a task
+ * - must be called holding task_lock(target)
+ * - returns 0 if successful, -ESRCH if the target process is a zombie or is exiting
+ */
+int __task_ornament_add(struct task_struct *target, struct task_ornament *orn)
+{
+	struct list_head *_ptr;
+	int ret;
+
+	ktrace("==>__task_ornament_add(%d,%p)\n",target->pid,orn);
+
+	if (!task_ornament_valid(orn))
+		panic("Adding invalid task ornament: %p [caller %p]\n",
+		      orn,__builtin_return_address(0));
+
+	ret = -ESRCH;
+	if (target->state!=TASK_ZOMBIE && !(target->flags&PF_EXITING)) {
+		list_for_each(_ptr,&target->ornaments) {
+			struct task_ornament *ptr = list_entry(_ptr,struct task_ornament,to_list);
+			if (ptr->to_order>orn->to_order)
+				break;
+		}
+
+		list_add_tail(&orn->to_list,_ptr);
+		ornget(orn);
+		orn->to_task = target;
+		ret = 0;
+	}
+
+	ktrace("<== __task_ornament_add() = %d\n",ret);
+
+	return ret;
+} /* end __task_ornament_add() */
+
+/*****************************************************************************/
+/*
+ * remove an ornament from a task
+ * - does nothing if the target process is a zombie or is exiting
+ * - doesn't decrement the ornament usage count (since the destructor might sleep)
+ */
+void __task_ornament_remove(struct task_struct *target, struct task_ornament *orn)
+{
+	ktrace("==>__task_ornament_remove(%d,%p)\n",target->pid,orn);
+
+	if (!task_ornament_valid(orn))
+		panic("Removing invalid task ornament: %p [caller %p]\n",
+		      orn,__builtin_return_address(0));
+
+	if (target->state!=TASK_ZOMBIE && !(target->flags&PF_EXITING)) {
+		list_del(&orn->to_list);
+		orn->to_task = NULL;
+	}
+
+	ktrace("<==__task_ornament_remove()\n");
+} /* end __task_ornament_remove() */
+
+/*****************************************************************************/
+/*
+ * find an ornament of a particular type attached to a specific task
+ * - note that if an ornament is returned, then its counter will be incremented
+ * - must be called holding task_lock(target)
+ */
+struct task_ornament *__task_ornament_find(struct task_struct *target,
+					   const struct task_ornament_operations *type)
+{
+	struct task_ornament *orn;
+	struct list_head *ptr;
+
+	if (!type) return NULL;
+
+	for (ptr=target->ornaments.next; ptr!=&target->ornaments; ptr=ptr->next) {
+		orn = list_entry(ptr,struct task_ornament,to_list);
+
+		if (!task_ornament_valid(orn))
+			panic("Find: invalid task ornament: %p [caller %p]\n",
+			      orn,__builtin_return_address(0));
+
+		if (orn->to_ops==type)
+			goto found;
+	}
+
+	return NULL;
+
+ found:
+	ornget(orn);
+	return orn;
+} /* end __task_ornament_find() */
+
+/*****************************************************************************/
+/*
+ * send exit notifications to the current process's ornaments
+ * - this'll be called from exit_notify() in kernel/signal.c
+ * - do_exit() holds the big kernel lock
+ * - the ornaments are removed from the list before they are notified
+ * - addition is prevented by PF_EXITING in current->flags
+ */
+void exit_task_ornaments(int exit_code)
+{
+	struct task_ornament *orn;
+	struct task_struct *tsk = current;
+
+	ktrace("==>exit_task_ornaments()\n");
+
+	/* eat the list */
+	task_lock(tsk);
+	while (!list_empty(&tsk->ornaments)) {
+		orn = list_entry(tsk->ornaments.next,struct task_ornament,to_list);
+		tsk->ornaments.next = orn->to_list.next;
+		task_unlock(tsk);
+
+		if (!task_ornament_valid(orn))
+			panic("Exit: invalid task ornament: %p\n",orn);
+
+		if (orn->to_ops && orn->to_ops->exit)
+			orn->to_ops->exit(orn,exit_code);
+		orn->to_task = NULL;
+
+		ornput(orn);
+		task_lock(tsk);
+	}
+
+	task_unlock(tsk);
+
+	ktrace("<==exit_task_ornaments()\n");
+
+} /* end exit_task_ornaments() */
+
+/*****************************************************************************/
+/*
+ * perform various tasks immediately prior to resuming userspace execution
+ * - poll ornaments that are requesting resumption notification
+ */
+void task_ornament_notify_resume(struct pt_regs *regs)
+{
+	struct task_ornament buoy, *orn;
+	struct task_struct *tsk = current;
+	struct list_head *ptr;
+
+	ktrace("==>task_ornament_notify_resume(%p,%p,%08x)\n",regs,oldset,ti_flags);
+
+	/* deal with resumption notification */
+	task_ornament_buoy_init(&buoy);
+	clear_thread_flag(TIF_NOTIFY_RESUME);
+
+	/* loop through all task ornaments, but be careful in case the
+	 * list is rearranged. The buoy is used as a marker between the current
+	 * position and the next
+	 */
+	task_lock(tsk);
+
+	ptr = tsk->ornaments.next;
+	while (ptr != &tsk->ornaments) {
+		/* find the next ornament with a resume op */
+		orn = list_entry(ptr,struct task_ornament,to_list);
+
+		if (!task_ornament_valid(orn))
+			panic("Resume: invalid task ornament: %p\n",orn);
+
+		if (!(orn->to_flags&TOF_REQ_NFY_RESUME) || !orn->to_ops || !orn->to_ops->resume) {
+			ptr = ptr->next;
+			continue;
+		}
+
+		/* make sure the ornament doesn't evaporate yet */
+		ornget(orn);
+
+		/* mark the queue so we know where our next ornament is */
+		buoy.to_order = orn->to_order;
+		__add_orn(tsk,&buoy,orn);
+		task_unlock(tsk);
+
+		/* call the operation */
+		orn->to_ops->resume(orn);
+		ornput(orn);
+
+		/* remove the marker */
+		task_lock(tsk);
+		ptr = buoy.to_list.next;
+		__remove_orn(tsk,&buoy);
+	}
+
+	task_unlock(tsk);
+
+	ktrace("<==task_ornament_notify_resume()\n");
+} /* end task_ornament_notify_resume() */
+
+/*****************************************************************************/
+/*
+ * send signal delivery notifications to the current process's ornaments
+ * - returns 0 to keep the signal
+ * - returns -1 to cancel the signal immediately
+ * - returns new signal number to change the signal (and has updated *info)
+ * - this'll be called from notify_parent() in kernel/signal.c
+ * - the list is _not_ locked whilst the notification routine is running
+ *   - a buoy is placed in the list to mark the next ornament to be processed
+ */
+int task_ornament_notify_signal(int signr, siginfo_t *info)
+{
+	struct task_ornament buoy, *orn;
+	struct task_struct *tsk = current;
+	struct list_head *ptr;
+	int action;
+
+	ktrace("==>task_ornament_notify_signal(%d,%p)\n",signr,info);
+
+	task_ornament_buoy_init(&buoy);
+
+	/* loop through all task ornaments, but be careful in case the list is
+	 * rearranged. The buoy is used as a marker between the current
+	 * position and the next
+	 */
+	task_lock(tsk);
+
+	action = 0;
+	ptr = tsk->ornaments.next;
+	while (ptr != &tsk->ornaments) {
+		/* find the next ornament with a signal op */
+		orn = list_entry(ptr,struct task_ornament,to_list);
+
+		if (!task_ornament_valid(orn))
+			panic("Signal: invalid task ornament: %p\n",orn);
+
+		if (!orn->to_ops || !orn->to_ops->signal) {
+			ptr = ptr->next;
+			continue;
+		}
+
+		/* make sure the ornament doesn't evaporate yet */
+		ornget(orn);
+
+		/* mark the queue so we know where our next ornament is */
+		buoy.to_order = orn->to_order;
+		__add_orn(tsk,&buoy,orn);
+		task_unlock(tsk);
+
+		/* call the operation */
+		orn->to_ops->signal(orn,signr,info,&action);
+		ornput(orn);
+
+		/* remove the marker */
+		task_lock(tsk);
+		ptr = buoy.to_list.next;
+		__remove_orn(tsk,&buoy);
+	}
+
+	task_unlock(tsk);
+
+	ktrace("<==task_ornament_notify_signal() = %d\n",action);
+
+	return action;
+} /* end task_ornament_notify_signal() */
+
+/*****************************************************************************/
+/*
+ * notify an ornament of the current process execve'ing itself
+ * - this'll be called from flush_old_exec() in kernel/exec.c
+ * - the list is _not_ locked whilst the notification routine is running
+ *   - a buoy is placed in the list to mark the next ornament to be processed
+ */
+void task_ornament_notify_execve(void)
+{
+	struct task_ornament buoy, *orn;
+	struct task_struct *tsk = current;
+	struct list_head *ptr;
+
+	ktrace("==>task_ornament_notify_execve()\n");
+
+	task_ornament_buoy_init(&buoy);
+
+	/* loop through all task ornaments, but be careful in case the
+	 * list is rearranged. The buoy is used as a marker between the current
+	 * position and the next
+	 */
+	task_lock(tsk);
+
+	ptr = tsk->ornaments.next;
+	while (ptr != &tsk->ornaments) {
+		/* find the next ornament with an execve op */
+		orn = list_entry(ptr,struct task_ornament,to_list);
+
+		if (!task_ornament_valid(orn))
+			panic("Execve: invalid task ornament: %p\n",orn);
+
+		if (!orn->to_ops || !orn->to_ops->execve) {
+			ptr = ptr->next;
+			continue;
+		}
+
+		/* make sure the ornament doesn't evaporate yet */
+		ornget(orn);
+
+		/* mark the queue so we know where our next ornament is */
+		buoy.to_order = orn->to_order;
+		__add_orn(tsk,&buoy,orn);
+		task_unlock(tsk);
+
+		/* call the operation */
+		orn->to_ops->execve(orn);
+		ornput(orn);
+
+		/* remove the marker */
+		task_lock(tsk);
+		ptr = buoy.to_list.next;
+		__remove_orn(tsk,&buoy);
+	}
+
+	task_unlock(tsk);
+
+	ktrace("<==task_ornament_notify_execve()\n");
+
+} /* end task_ornament_notify_execve() */
+
+/*****************************************************************************/
+/*
+ * notify an ornament of the current process forking/cloning itself
+ * - this'll be called from do_fork() in kernel/fork.c
+ * - the list is _not_ locked whilst the notification routine is running
+ *   - a buoy is placed in the list to mark the next ornament to be processed
+ *   - a second buoy is placed at the end of the list to prevent processing of
+ *     ornaments added during processing
+ */
+void task_ornament_notify_fork(struct task_struct *child, unsigned long clone_flags)
+{
+	struct task_ornament buoy, *orn;
+	struct task_struct *tsk = current;
+	struct list_head *ptr;
+
+	ktrace("==>task_ornament_notify_fork(%d,%lu)\n",child->pid,clone_flags);
+
+	task_ornament_buoy_init(&buoy);
+
+	/* loop through all task ornaments, but be careful in case the
+	 * list is rearranged. The buoy is used as a marker between the current
+	 * position and the next
+	 */
+	task_lock(tsk);
+
+	ptr = tsk->ornaments.next;
+	while (ptr != &tsk->ornaments) {
+		/* skip over buoys from other processors */
+		if (ptr==&buoy.to_list)
+			break;
+
+		orn = list_entry(ptr,struct task_ornament,to_list);
+
+		if (!task_ornament_valid(orn))
+			panic("Fork: invalid task ornament: %p\n",orn);
+
+		if (!orn->to_ops || !orn->to_ops->fork) {
+			ptr = ptr->next;
+			break;
+		}
+
+		/* make sure the ornament doesn't evaporate yet */
+		ornget(orn);
+
+		/* mark the queue so we know where our next ornament is */
+		buoy.to_order = orn->to_order;
+		__add_orn(tsk,&buoy,orn);
+		task_unlock(tsk);
+
+		/* call the operation */
+		orn->to_ops->fork(orn,child,clone_flags);
+		ornput(orn);
+
+		/* remove the marker */
+		task_lock(tsk);
+		ptr = buoy.to_list.next;
+ 		__remove_orn(tsk,&buoy);
+	}
+
+	task_unlock(tsk);
+
+	ktrace("<==task_ornament_notify_fork()\n");
+
+} /* end task_ornament_notify_fork() */
+
+/*****************************************************************************/
+/*
+ * notify an ornament of the current process entering or exiting a syscall
+ * - this'll be called from syscall_trace() in arch/xxx/kernel/ptrace.c
+ * - the list is _not_ locked whilst the notification routine is running
+ *   - a buoy is placed in the list to mark the next ornament to be processed
+ *   - a second buoy is placed at the end of the list to prevent processing of
+ *     ornaments added during processing
+ */
+void task_ornament_notify_syscall(struct pt_regs *regs, int entryexit)
+{
+	struct task_ornament buoy, *orn;
+	struct task_struct *tsk = current;
+	struct list_head *ptr;
+
+	ktrace("==>task_ornament_notify_syscall(%d)\n",entryexit);
+
+	task_ornament_buoy_init(&buoy);
+
+	/* loop through all task ornaments, but be careful in case the
+	 * list is rearranged. The buoy is used as a marker between the current
+	 * position and the next
+	 */
+	task_lock(tsk);
+
+	ptr = tsk->ornaments.next;
+	while (ptr != &tsk->ornaments) {
+		if (ptr==&buoy.to_list)
+			break;
+
+		orn = list_entry(ptr,struct task_ornament,to_list);
+
+		if (!task_ornament_valid(orn))
+			panic("SyscallTrace: invalid task ornament: %p\n",orn);
+
+		if (!orn->to_ops || !orn->to_ops->execve) {
+			ptr = ptr->next;
+			continue;
+		}
+
+		/* make sure the ornament doesn't evaporate yet */
+		ornget(orn);
+
+		/* mark the queue so we know where our next ornament is */
+		buoy.to_order = orn->to_order;
+		__add_orn(tsk,&buoy,orn);
+		task_unlock(tsk);
+
+		/* call the operation */
+		orn->to_ops->syscall_trace(orn,regs,entryexit);
+		ornput(orn);
+
+		/* remove the marker */
+		task_lock(tsk);
+		ptr = buoy.to_list.next;
+		__remove_orn(tsk,&buoy);
+	}
+
+	task_unlock(tsk);
+
+	ktrace("<==task_ornament_notify_syscall()\n");
+} /* end task_ornament_notify_syscall() */
+
+/*****************************************************************************/
+/*
+ * request userspace resumption notification service for an ornament on a task
+ */
+int task_ornament_request_notify_resume(struct task_ornament *orn)
+{
+	struct task_struct *tsk;
+	int ret = -ESRCH;
+
+	ktrace("==>task_ornament_request_notify_resume(%p)\n",orn);
+
+	read_lock(&tasklist_lock);
+
+	tsk = orn->to_task;
+	printk("-- setting flag on %p\n",tsk);
+	if (tsk) {
+		printk("-- (pid %d)\n",tsk->pid);
+		task_lock(tsk);
+		orn->to_flags |= TOF_REQ_NFY_RESUME;
+		set_tsk_thread_flag(tsk,TIF_NOTIFY_RESUME);
+		task_unlock(tsk);
+		ret = 0;
+	}
+
+	read_unlock(&tasklist_lock);
+
+	ktrace("<==task_ornament_request_notify_resume() = %d\n",ret);
+
+	return ret;
+} /* end task_ornament_request_notify_resume() */
+
+/*****************************************************************************/
+/*
+ * read a list of task ornaments attached to a process
+ * - MSW of file offset is ornament index
+ * - LSW of file offset is line position
+ */
+ssize_t proc_pid_read_taskornlist(struct task_struct *tsk, struct file *file,
+				  char *ubuf, size_t count, loff_t *ppos)
+{
+	struct task_ornament *orn;
+	struct list_head *_ptr;
+	char *scratch = NULL, *curr, *buf = NULL;
+	ssize_t ret;
+	loff_t npos;
+	int index, qty, pos;
+
+	/* get some scratch space */
+	ret = -ENOMEM;
+	buf = (char*) __get_free_page(GFP_KERNEL);
+	if (!buf)
+		goto out;
+
+	scratch = (char*) __get_free_page(GFP_KERNEL);
+	if (!scratch)
+		goto out;
+
+	/* get the n'th task ornament next */
+	npos = *ppos;
+	ret = 0;
+	while (count>0) {
+		index = npos >> 16;
+		orn = NULL;
+
+		task_lock(tsk);
+
+		list_for_each(_ptr,&tsk->ornaments) {
+			orn = list_entry(_ptr,struct task_ornament,to_list);
+			if (!orn->to_ops)
+				continue; /* ignore markers inserted into the list */
+			if (index==0)
+				break;
+			index--;
+		}
+
+		if (_ptr==&tsk->ornaments) {
+			task_unlock(tsk);
+			break;
+		}
+
+		/* make sure the ornament doesn't evaporate yet */
+		ornget(orn);
+		task_unlock(tsk);
+
+		/* make notes on this ornament */
+		curr = scratch;
+		curr += sprintf(curr,
+				"%s %p usage=%03d order=%04x\n"
+				"%s",
+				orn->to_ops->name,
+				orn,
+				atomic_read(&orn->to_count),
+				orn->to_order,
+				orn->to_flags&TOF_REQ_NFY_RESUME ? " - Resume Notify Req\n" : ""
+				);
+
+		/* call the information gathering operation */
+		if (orn->to_ops->proc_read)
+			curr = orn->to_ops->proc_read(orn,curr,scratch+PAGE_SIZE-1);
+		ornput(orn);
+
+		/* distill the appropriate amount to the buffer */
+		qty = curr - scratch;
+		pos = npos & 0xFFFF;
+		npos -= pos;
+		if (pos < qty) {
+			/* some of the current scratch buffer should be transferred */
+			curr = scratch + pos;
+			qty -= pos;
+
+			if (qty > count) {
+				/* partial copy */
+				memcpy(buf+ret,curr,count);
+				ret += count;
+				qty -= count;
+				count = 0;
+			}
+			else {
+				/* complete copy */
+				memcpy(buf+ret,curr,qty);
+				ret += qty;
+				count += qty;
+				qty = 0;
+			}
+
+		}
+		else {
+			/* already read everything this ornament has to offer */
+			qty = 0;
+		}
+
+		if (qty==0)
+			npos += 0x10000;
+		else
+			npos += qty;
+	}
+
+	if (ret>count) BUG();
+
+	/* write the results to userspace */
+	if (ret>0) {
+		if (copy_to_user(ubuf,buf,ret))
+			ret = -EFAULT;
+		else
+			*ppos = npos;
+	}
+
+ out:
+	if (scratch) free_page((unsigned long)scratch);
+	if (buf) free_page((unsigned long)buf);
+	return ret;
+
+} /* end proc_pid_read_taskornlist() */

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2002-02-11 17:31 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-01-25 18:54 [PATCH] task ornaments David Howells
  -- strict thread matches above, loose matches on Subject: below --
2002-02-11 17:31 David Howells

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox