On Mon, 2005-02-07 at 15:46 -0800, Andrew Morton wrote:
> Guillaume Thouvenin <[EMAIL PROTECTED]> wrote:
> >
> > Hello,
> >     
> >    This module sends a signal to one or several processes (in user
> > space) when a fork occurs in the kernel. It relays information about
> > forks (parent and child pid) to a user space application.
> >
> So this permits ELSA to maintain a complete picture of the process/thread
> hierarchy?  I guess that fits into the "do it in userspace" mantra -
> certainly hooking into fork() is a minimal way of doing this, although I
> wonder what the limitations are.
> 
> Implementation-wise: there's a lot of code there and the interface is a bit
> awkward.  Why not just feed that kobject you have there into
> kobject_uevent()?

  Like Andrew suggested, I wrote a new patch (tested on 2.6.11-rc3-mm2)
that notifies to user space application the creation of a new process
when kernel forks by using the kobject_uevent() routine. This funtion
sends a new event (KOBJ_FORK) through the netlink interface. This new
event needs an environment (parent pid and child pid) so I used
send_uevent() like it is done in kobject_hotplug(). 

  I tested this patch on a 2.6.11-rc3-mm2 kernel and there is a little
overhead when I compile a Linux kernel:

   #time sh -c 'make O=/home/guill/build/k2610 bzImage && 
   make O=/home/guill/build/k2610 modules'

   with a vanilla kernel: real    8m10.797s
                          user    7m29.652s
                          sys     0m49.275s
   
   with the forkuevent patch : real    8m16.189s
                               user    7m28.841s
                               sys     0m49.155s

  I paste the diff at the end of the mail with wrap line disabled. is it
better to wrap the patch to 80 characters or is it ok like this?

  Every comments are welcome. For exemple is it better to use a
structure instead of two pid_t parameters? I also like to know if this
is useful for someone else... thus, any feedback will be appreciate.
 
 
Regards,
Guillaume

[EMAIL PROTECTED] $ diffstat linux-2.6.11-rc3-mm2-forkuevent.patch
 include/linux/kobject.h        |    2 +
 include/linux/kobject_uevent.h |    1
 kernel/fork.c                  |   13 ++++++++
 lib/kobject_uevent.c           |   63 ++++++++++++++...++++++++++++
 4 files changed, 79 insertions(+)

Signed-off-by: Guillaume Thouvenin <[EMAIL PROTECTED]>

diff -uprN -X dontdiff linux-2.6.11-rc3-mm2/include/linux/kobject.h 
linux-2.6.11-rc3-mm2-forkuevent/include/linux/kobject.h
--- linux-2.6.11-rc3-mm2/include/linux/kobject.h        2005-02-03 
02:54:59.000000000 +0100
+++ linux-2.6.11-rc3-mm2-forkuevent/include/linux/kobject.h     2005-02-11 
08:38:25.000000000 +0100
@@ -253,5 +253,7 @@ static inline int add_hotplug_env_var(ch
 { return 0; }
 #endif
 
+extern void kobject_fork(struct kobject *, pid_t, pid_t);
+
 #endif /* __KERNEL__ */
 #endif /* _KOBJECT_H_ */
diff -uprN -X dontdiff linux-2.6.11-rc3-mm2/include/linux/kobject_uevent.h 
linux-2.6.11-rc3-mm2-forkuevent/include/linux/kobject_uevent.h
--- linux-2.6.11-rc3-mm2/include/linux/kobject_uevent.h 2005-02-03 
02:54:38.000000000 +0100
+++ linux-2.6.11-rc3-mm2-forkuevent/include/linux/kobject_uevent.h      
2005-02-11 08:38:25.000000000 +0100
@@ -29,6 +29,7 @@ enum kobject_action {
        KOBJ_UMOUNT     = (__force kobject_action_t) 0x05,      /* umount event 
for block devices */
        KOBJ_OFFLINE    = (__force kobject_action_t) 0x06,      /* offline 
event for hotplug devices */
        KOBJ_ONLINE     = (__force kobject_action_t) 0x07,      /* online event 
for hotplug devices */
+       KOBJ_FORK       = (__force kobject_action_t) 0x08,      /* a child 
process has been created */
 };
 
 
diff -uprN -X dontdiff linux-2.6.11-rc3-mm2/kernel/fork.c 
linux-2.6.11-rc3-mm2-forkuevent/kernel/fork.c
--- linux-2.6.11-rc3-mm2/kernel/fork.c  2005-02-11 08:37:48.000000000 +0100
+++ linux-2.6.11-rc3-mm2-forkuevent/kernel/fork.c       2005-02-11 
08:39:33.000000000 +0100
@@ -41,6 +41,7 @@
 #include <linux/profile.h>
 #include <linux/rmap.h>
 #include <linux/acct.h>
+#include <linux/kobject.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -57,6 +58,9 @@ int nr_threads;               /* The idle threads do
 
 int max_threads;               /* tunable limit on nr_threads */
 
+/* kobject used to notify user space application when a fork occurs */
+struct kobject fork_kobj;
+                       
 DEFINE_PER_CPU(unsigned long, process_counts) = 0;
 
  __cacheline_aligned DEFINE_RWLOCK(tasklist_lock);  /* outer */
@@ -148,6 +152,13 @@ void __init fork_init(unsigned long memp
 
        init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
        init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
+
+       /*
+        * We init the fork_kobj which is the event sends when a fork
+        * occurs.
+        */
+       kobject_init(&fork_kobj);
+       kobject_set_name(&fork_kobj, "fork_kobj");
 }
 
 static struct task_struct *dup_task_struct(struct task_struct *orig)
@@ -1238,6 +1249,8 @@ long do_fork(unsigned long clone_flags,
                        if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE))
                                ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | 
SIGTRAP);
                }
+
+               kobject_fork(&fork_kobj, current->pid, p->pid);
        } else {
                free_pidmap(pid);
                pid = PTR_ERR(p);
diff -uprN -X dontdiff linux-2.6.11-rc3-mm2/lib/kobject_uevent.c 
linux-2.6.11-rc3-mm2-forkuevent/lib/kobject_uevent.c
--- linux-2.6.11-rc3-mm2/lib/kobject_uevent.c   2005-02-11 08:37:48.000000000 
+0100
+++ linux-2.6.11-rc3-mm2-forkuevent/lib/kobject_uevent.c        2005-02-11 
08:38:25.000000000 +0100
@@ -46,6 +46,8 @@ static char *action_to_string(enum kobje
                return "offline";
        case KOBJ_ONLINE:
                return "online";
+       case KOBJ_FORK:
+               return "fork";
        default:
                return NULL;
        }
@@ -433,3 +435,64 @@ int add_hotplug_env_var(char **envp, int
 EXPORT_SYMBOL(add_hotplug_env_var);
 
 #endif /* CONFIG_HOTPLUG */
+
+/* 
+ * The buffer will contain 1 integer which has 20 digits for
+ * 64 bits integer. So a size of 32 is large enough...
+ */
+#define FORK_BUFFER_SIZE       32
+
+/* 
+ * number of env pointers is set to FORK_BUFFER_NB 
+ *     env[0] - Not used
+ *     env[1] - Not used
+ *     env[2] - parent pid
+ *     env[3] - child pid
+ *     env[4] - NULL
+ */
+#define FORK_BUFFER_NB         5
+
+/**
+ * kobject_fork - notify userspace when forking
+ *
+ * @kobj: struct kobject that the action is happening to
+ */
+void kobject_fork(struct kobject *kobj, pid_t parent, pid_t child)
+{
+       char *kobj_path = NULL;
+       char *action_string = NULL;
+       char **envp = NULL;
+       char ppid_string[FORK_BUFFER_SIZE];
+       char cpid_string[FORK_BUFFER_SIZE];
+
+       action_string = action_to_string(KOBJ_FORK);
+       if (!action_string)
+               return;
+       
+       kobj_path = kobject_get_path(kobj, GFP_KERNEL);
+       if (!kobj_path)
+               return;
+
+       envp = kmalloc(FORK_BUFFER_NB * sizeof (char *), GFP_KERNEL);
+       if (!envp) {
+               kfree(kobj_path);
+               return;
+       }
+       memset (envp, 0x0, FORK_BUFFER_NB * sizeof (char *));
+
+       snprintf(ppid_string, FORK_BUFFER_SIZE, "%i", parent);
+       snprintf(cpid_string, FORK_BUFFER_SIZE, "%i", child);
+       
+       envp[0] = "Not used";
+       envp[1] = "Not used";
+       envp[2] = ppid_string;
+       envp[3] = cpid_string;
+       envp[4] = NULL;
+       
+       send_uevent(action_string, kobj_path, envp, GFP_KERNEL);
+
+       kfree(envp);
+       kfree(kobj_path);
+       return;
+}
+EXPORT_SYMBOL(kobject_fork);


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to