Skip to contentSkip to conversation

devfsd hangs on restart - is_devfsd_or_child() problem

PATCH New Andrey Borzenkov 1 participant 2 messages Jul 11, 2003 – Jul 12, 2003

lore
Share & tools
lore
#0 lore raw

I cannot believe it is so fragile ...

is_devfsd_or_child() simplemindedly checks for pgrp:

static int is_devfsd_or_child (struct fs_info *fs_info)

{
    if (current == fs_info->devfsd_task) return (TRUE);
    if (current->pgrp == fs_info->devfsd_pgrp) return (TRUE);
    return (FALSE);
}   /*  End Function is_devfsd_or_child  */

unfortunately, bash (I do not know if it does it always or not) resets pgrp on startup. I.e. if your action is using shell it is no more considered devfsd descendant ... and it will attempt in turn start devfsd action while devfsd is waiting for it ot finish.

Thierry, i refer mostly to dynamics scripts currently. Every time I update devfsd it hangs in one of them. And actually it is enough to do service devfsd restart to trigger this. It may be 2.5 specific again in that it is not as easily seen under 2.4.

I have no idea what can be done. Is there any way in kernel to find out if one task is descendant of other task? Even rewriting devfsd to use non-blocking calls and request queue does not help as it apprently just results in endless loop (action triggering action triggering action ...)

-andrey

#1 lore raw

PATCH 1/1 [2.5.75] devfsd hangs on restart - is_devfsd_or_child() problem

Quoted 11 lines · Andrey Borzenkov

I cannot believe it is so fragile ...

is_devfsd_or_child() simplemindedly checks for pgrp:

static int is_devfsd_or_child (struct fs_info *fs_info)

{
    if (current == fs_info->devfsd_task) return (TRUE);
    if (current->pgrp == fs_info->devfsd_pgrp) return (TRUE);
    return (FALSE);
}   /*  End Function is_devfsd_or_child  */

Andrew, one more for your collection :)

The code that did proper check existed in 2.4 and was removed in 2.5 for whatever reason. The patch restores it slightly modified as below.

2.4 code looks somewhat unclean in that

- it traverses task list without lock.
- is starts from current->real_parent but nothing prevents current be init_task itself. This hung for me on 2.5 during boot. May be 2.4 does something differently.

Comments?

regards

-andrey

This is trivially reproduced under 2.5 by using devfsd.conf lines

LOOKUP  ^foo$   EXECUTE /home/bor/tmp/devfsd/handler /dev/bar
LOOKUP  ^bar$   EXECUTE /home/bor/tmp/devfsd/handler /dev/foo

and handler like

-------- cut here ----------
#include <unistd.h>

int
main(int argc, char **argv, char **envp)

{
        if (argc <= 1)
                return 0;

        setpgrp();
        return access(argv[1], R_OK);
}

-------- cut here ----------

and doing ls /dev/foo

fs/devfs/base.c renamed from fs/devfs/base.c.devfsd_child +15 -2
@@ -676,6 +676,7 @@
 #include <linux/smp.h>
 #include <linux/version.h>
 #include <linux/rwsem.h>
+#include <linux/sched.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -1325,8 +1326,20 @@ static void free_dentry (struct devfs_en
 
 static int is_devfsd_or_child (struct fs_info *fs_info)
 {
-    if (current == fs_info->devfsd_task) return (TRUE);
-    if (current->pgrp == fs_info->devfsd_pgrp) return (TRUE);
+    struct task_struct *p = current;
+
+    if (p == fs_info->devfsd_task) return (TRUE);
+    if (p->pgrp == fs_info->devfsd_pgrp) return (TRUE);
+    read_lock(&tasklist_lock);
+    for ( ; p != &init_task; p = p->real_parent)
+    {
+	if (p == fs_info->devfsd_task)
+	{
+	    read_unlock (&tasklist_lock);
+	    return (TRUE);
+	}
+    }
+    read_unlock (&tasklist_lock);
     return (FALSE);
 }   /*  End Function is_devfsd_or_child  */