devfs - Add a destroy_dev_alias, remove hotplug
authorAlex Hornung <ahornung@gmail.com>
Mon, 15 Nov 2010 04:06:34 +0000 (04:06 +0000)
committerAlex Hornung <ahornung@gmail.com>
Mon, 15 Nov 2010 18:03:17 +0000 (18:03 +0000)
* Move the wildCmp* functions into devfs_core and expose them to the
  whole of devfs, but renamed as devfs_wildCmp*.

* Add a destroy_dev_alias functionality that will remove specific
  aliases to a cdev that match a given wild string.

* Remove the whole hotplug magic since it was broken already for systems
  with several devfs mount points (it would receive several attaches,
  one for each mount point). It is also redundant now that udev/devattr
  provides that functionality.

sys/kern/kern_conf.c
sys/sys/devfs.h
sys/sys/device.h
sys/vfs/devfs/devfs_core.c
sys/vfs/devfs/devfs_rules.c

index 4ff19cd..661e2ae 100644 (file)
@@ -352,6 +352,22 @@ make_dev_alias(cdev_t target, const char *fmt, ...)
        return 0;
 }
 
+int
+destroy_dev_alias(cdev_t target, const char *fmt, ...)
+{
+       __va_list ap;
+       char *name;
+
+       __va_start(ap, fmt);
+       kvasnrprintf(&name, PATH_MAX, 32, fmt, ap);
+       __va_end(ap);
+
+       devfs_destroy_alias(name, target);
+       kvasfree(&name);
+
+       return 0;
+}
+
 extern struct dev_ops default_dev_ops;
 
 cdev_t
index 7acc794..12d73fe 100644 (file)
@@ -286,6 +286,7 @@ typedef void* (devfs_iterate_callback_t)(struct devfs_node *, void *);
 #define DEVFS_FIND_DEVICE_BY_UDEV      0x0B
 #define DEVFS_FIND_DEVICE_BY_NAME      0x0C
 #define DEVFS_MAKE_ALIAS               0x0D
+#define DEVFS_DESTROY_ALIAS            0x0E
 #define DEVFS_APPLY_RULES              0x0F
 #define        DEVFS_RESET_RULES               0x10
 #define DEVFS_SCAN_CALLBACK            0x11
@@ -388,6 +389,7 @@ struct devfs_node *devfs_create_device_node(struct devfs_node *, cdev_t,
                      char *, char *, ...) __printf0like(4, 5);
 
 int devfs_destroy_device_node(struct devfs_node *, cdev_t);
+int devfs_destroy_node(struct devfs_node *, char *);
 int devfs_destroy_subnames(char *);
 int devfs_destroy_dev_by_ops(struct dev_ops *, int);
 struct devfs_node *devfs_find_device_node_by_name(struct devfs_node *, char *);
@@ -407,6 +409,7 @@ cdev_t devfs_clone(cdev_t, const char *, size_t, int, struct ucred *);
 int devfs_link_dev(cdev_t);
 
 int devfs_make_alias(const char *, cdev_t);
+int devfs_destroy_alias(const char *, cdev_t);
 
 int devfs_alias_create(char *, struct devfs_node *, int);
 
@@ -429,6 +432,10 @@ void *devfs_iterate_topology(struct devfs_node *node,
 
 void *devfs_find_device_node_callback(struct devfs_node *, cdev_t);
 
+
+int devfs_WildCmp(const char *w, const char *s);
+int devfs_WildCaseCmp(const char *w, const char *s);
+
 #endif /* KERNEL */
 
 #define DEVFS_MNT_RULESET      0x01
index 45f4a2f..daf88f0 100644 (file)
@@ -365,6 +365,7 @@ cdev_t make_only_devfs_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
           int perms, const char *fmt, ...) __printflike(6, 7);
 void destroy_only_dev(cdev_t dev);
 int make_dev_alias(cdev_t target, const char *fmt, ...) __printflike(2, 3);
+int destroy_dev_alias(cdev_t target, const char *fmt, ...) __printflike(2, 3);
 cdev_t make_autoclone_dev(struct dev_ops *ops, struct devfs_bitmap *bitmap,
           d_clone_t *nhandler, uid_t uid, gid_t gid, int perms,
           const char *fmt, ...) __printflike(7, 8);
index e1821c0..eaa1dba 100644 (file)
@@ -45,7 +45,6 @@
 #include <sys/systm.h>
 #include <sys/devfs.h>
 #include <sys/devfs_rules.h>
-#include <sys/hotplug.h>
 #include <sys/udev.h>
 
 #include <sys/msgport2.h>
@@ -136,9 +135,10 @@ static struct devfs_node *devfs_resolve_or_create_dir(struct devfs_node *,
                char *, size_t, int);
 
 static int devfs_make_alias_worker(struct devfs_alias *);
+static int devfs_destroy_alias_worker(struct devfs_alias *);
 static int devfs_alias_remove(cdev_t);
 static int devfs_alias_reap(void);
-static int devfs_alias_propagate(struct devfs_alias *);
+static int devfs_alias_propagate(struct devfs_alias *, int);
 static int devfs_alias_apply(struct devfs_node *, struct devfs_alias *);
 static int devfs_alias_check_create(struct devfs_node *);
 
@@ -151,10 +151,6 @@ static void *devfs_gc_links_callback(struct devfs_node *, struct devfs_node *);
 static void *
 devfs_inode_to_vnode_worker_callback(struct devfs_node *, ino_t *);
 
-/* hotplug */
-void (*devfs_node_added)(struct hotplug_device*) = NULL;
-void (*devfs_node_removed)(struct hotplug_device*) = NULL;
-
 /*
  * devfs_debug() is a SYSCTL and TUNABLE controlled debug output function
  * using kvprintf
@@ -465,7 +461,6 @@ int
 devfs_unlinkp(struct devfs_node *node)
 {
        struct devfs_node *parent;
-       struct hotplug_device *hpdev;
        KKASSERT(node);
 
        /*
@@ -484,15 +479,7 @@ devfs_unlinkp(struct devfs_node *node)
                parent->nchildren--;
                node->flags &= ~DEVFS_NODE_LINKED;
        }
-       /* hotplug handler */
-       if(devfs_node_removed) {
-               hpdev = kmalloc(sizeof(struct hotplug_device), M_TEMP, M_WAITOK);
-               hpdev->dev = node->d_dev;
-               if(hpdev->dev)
-                       hpdev->name = node->d_dev->si_name;
-               devfs_node_removed(hpdev);
-               kfree(hpdev, M_TEMP);
-       }
+
        node->parent = NULL;
        return 0;
 }
@@ -842,6 +829,28 @@ devfs_make_alias(const char *name, cdev_t dev_target)
 }
 
 /*
+ * devfs_destroy_alias is the asynchronous entry point to deregister an alias
+ * for a device.  It just sends a message with the relevant details to the
+ * devfs core.
+ */
+int
+devfs_destroy_alias(const char *name, cdev_t dev_target)
+{
+       struct devfs_alias *alias;
+       size_t len;
+
+       len = strlen(name);
+
+       alias = kmalloc(sizeof(struct devfs_alias), M_DEVFS, M_WAITOK);
+       alias->name = kstrdup(name, M_DEVFS);
+       alias->namlen = len;
+       alias->dev_target = dev_target;
+
+       devfs_msg_send_generic(DEVFS_DESTROY_ALIAS, alias);
+       return 0;
+}
+
+/*
  * devfs_apply_rules is the asynchronous entry point to trigger application
  * of all rules.  It just sends a message with the relevant details to the
  * devfs core.
@@ -1164,6 +1173,9 @@ devfs_msg_exec(devfs_msg_t msg)
        case DEVFS_MAKE_ALIAS:
                devfs_make_alias_worker((struct devfs_alias *)msg->mdv_load);
                break;
+       case DEVFS_DESTROY_ALIAS:
+               devfs_destroy_alias_worker((struct devfs_alias *)msg->mdv_load);
+               break;
        case DEVFS_APPLY_RULES:
                devfs_apply_reset_rules_caller(msg->mdv_name, 1);
                break;
@@ -1486,7 +1498,7 @@ devfs_make_alias_worker(struct devfs_alias *alias)
                 * The alias doesn't exist yet, so we add it to the alias list
                 */
                TAILQ_INSERT_TAIL(&devfs_alias_list, alias, link);
-               devfs_alias_propagate(alias);
+               devfs_alias_propagate(alias, 0);
                udev_event_attach(alias->dev_target, alias->name, 1);
        } else {
                devfs_debug(DEVFS_DEBUG_WARNING,
@@ -1500,6 +1512,49 @@ devfs_make_alias_worker(struct devfs_alias *alias)
 }
 
 /*
+ * Worker function that delete a given alias from the
+ * alias list, and propagates the removal to all mount
+ * points.
+ */
+static int
+devfs_destroy_alias_worker(struct devfs_alias *alias)
+{
+       struct devfs_alias *alias2;
+       int found = 0;
+
+       TAILQ_FOREACH(alias2, &devfs_alias_list, link) {
+               if (alias->dev_target != alias2->dev_target)
+                       continue;
+
+               if (devfs_WildCmp(alias->name, alias2->name) == 0) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found) {
+               devfs_debug(DEVFS_DEBUG_WARNING,
+                   "Warning: devfs_destroy_alias for inexistant alias: %s\n",
+                   alias->name);
+               kfree(alias->name, M_DEVFS);
+               kfree(alias, M_DEVFS);
+       } else {
+               /*
+                * The alias exists, so we delete it from the alias list
+                */
+               TAILQ_REMOVE(&devfs_alias_list, alias2, link);
+               devfs_alias_propagate(alias2, 1);
+               udev_event_detach(alias2->dev_target, alias2->name, 1);
+               kfree(alias->name, M_DEVFS);
+               kfree(alias, M_DEVFS);
+               kfree(alias2->name, M_DEVFS);
+               kfree(alias2, M_DEVFS);
+       }
+
+       return 0;
+}
+
+/*
  * Function that removes and frees all aliases.
  */
 static int
@@ -1509,6 +1564,7 @@ devfs_alias_reap(void)
 
        TAILQ_FOREACH_MUTABLE(alias, &devfs_alias_list, link, alias2) {
                TAILQ_REMOVE(&devfs_alias_list, alias, link);
+               kfree(alias->name, M_DEVFS);
                kfree(alias, M_DEVFS);
        }
        return 0;
@@ -1527,6 +1583,7 @@ devfs_alias_remove(cdev_t dev)
                if (alias->dev_target == dev) {
                        TAILQ_REMOVE(&devfs_alias_list, alias, link);
                        udev_event_detach(alias->dev_target, alias->name, 1);
+                       kfree(alias->name, M_DEVFS);
                        kfree(alias, M_DEVFS);
                }
        }
@@ -1534,15 +1591,20 @@ devfs_alias_remove(cdev_t dev)
 }
 
 /*
- * This function propagates a new alias to all mount points.
+ * This function propagates an alias addition or removal to
+ * all mount points.
  */
 static int
-devfs_alias_propagate(struct devfs_alias *alias)
+devfs_alias_propagate(struct devfs_alias *alias, int remove)
 {
        struct devfs_mnt_data *mnt;
 
        TAILQ_FOREACH(mnt, &devfs_mnt_list, link) {
-               devfs_alias_apply(mnt->root_node, alias);
+               if (remove) {
+                       devfs_destroy_node(mnt->root_node, alias->name);
+               } else {
+                       devfs_alias_apply(mnt->root_node, alias);
+               }
        }
        return 0;
 }
@@ -1599,7 +1661,6 @@ devfs_alias_create(char *name_orig, struct devfs_node *target, int rule_based)
        struct mount *mp = target->mp;
        struct devfs_node *parent = DEVFS_MNTDATA(mp)->root_node;
        struct devfs_node *linknode;
-       struct hotplug_device *hpdev;
        char *create_path = NULL;
        char *name;
        char *name_buf;
@@ -1636,14 +1697,6 @@ devfs_alias_create(char *name_orig, struct devfs_node *target, int rule_based)
                linknode->flags |= DEVFS_RULE_CREATED;
 
 done:
-       /* hotplug handler */
-       if(devfs_node_added) {
-               hpdev = kmalloc(sizeof(struct hotplug_device), M_TEMP, M_WAITOK);
-               hpdev->dev = target->d_dev;
-               hpdev->name = name_orig;
-               devfs_node_added(hpdev);
-               kfree(hpdev, M_TEMP);
-       }
        kfree(name_buf, M_TEMP);
        return (result);
 }
@@ -1811,7 +1864,6 @@ devfs_create_device_node(struct devfs_node *root, cdev_t dev,
                         char *dev_name, char *path_fmt, ...)
 {
        struct devfs_node *parent, *node = NULL;
-       struct hotplug_device *hpdev;
        char *path = NULL;
        char *name;
        char *name_buf;
@@ -1875,14 +1927,6 @@ devfs_create_device_node(struct devfs_node *root, cdev_t dev,
                if (found)
                        node->flags |= (DEVFS_PTY | DEVFS_INVISIBLE);
        }
-       /* hotplug handler */
-       if(devfs_node_added) {
-               hpdev = kmalloc(sizeof(struct hotplug_device), M_TEMP, M_WAITOK);
-               hpdev->dev = node->d_dev;
-               hpdev->name = node->d_dev->si_name;
-               devfs_node_added(hpdev);
-               kfree(hpdev, M_TEMP);
-       }
 
 out:
        kfree(name_buf, M_TEMP);
@@ -1954,6 +1998,17 @@ devfs_inode_to_vnode_worker_callback(struct devfs_node *node, ino_t *inop)
 int
 devfs_destroy_device_node(struct devfs_node *root, cdev_t target)
 {
+       KKASSERT(target != NULL);
+       return devfs_destroy_node(root, target->si_name);
+}
+
+/*
+ * This function takes a path to a devfs node, resolves it and
+ * removes the devfs node from the given topology.
+ */
+int
+devfs_destroy_node(struct devfs_node *root, char *target)
+{
        struct devfs_node *node, *parent;
        char *name;
        char *name_buf;
@@ -1962,9 +2017,9 @@ devfs_destroy_device_node(struct devfs_node *root, cdev_t target)
        KKASSERT(target);
 
        name_buf = kmalloc(PATH_MAX, M_TEMP, M_WAITOK);
-       ksnprintf(name_buf, PATH_MAX, "%s", target->si_name);
+       ksnprintf(name_buf, PATH_MAX, "%s", target);
 
-       devfs_resolve_name_path(target->si_name, name_buf, &create_path, &name);
+       devfs_resolve_name_path(target, name_buf, &create_path, &name);
 
        if (create_path)
                parent = devfs_resolve_or_create_path(root, create_path, 0);
@@ -2488,3 +2543,168 @@ SYSINIT(vfs_devfs_register, SI_SUB_PRE_DRIVERS, SI_ORDER_FIRST,
                devfs_init, NULL);
 SYSUNINIT(vfs_devfs_register, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY,
                devfs_uninit, NULL);
+
+/*
+ * WildCmp() - compare wild string to sane string
+ *
+ *     Returns 0 on success, -1 on failure.
+ */
+static int
+wildCmp(const char **mary, int d, const char *w, const char *s)
+{
+    int i;
+
+    /*
+     * skip fixed portion
+     */
+    for (;;) {
+       switch(*w) {
+       case '*':
+           /*
+            * optimize terminator
+            */
+           if (w[1] == 0)
+               return(0);
+           if (w[1] != '?' && w[1] != '*') {
+               /*
+                * optimize * followed by non-wild
+                */
+               for (i = 0; s + i < mary[d]; ++i) {
+                   if (s[i] == w[1] && wildCmp(mary, d + 1, w + 1, s + i) == 0)
+                       return(0);
+               }
+           } else {
+               /*
+                * less-optimal
+                */
+               for (i = 0; s + i < mary[d]; ++i) {
+                   if (wildCmp(mary, d + 1, w + 1, s + i) == 0)
+                       return(0);
+               }
+           }
+           mary[d] = s;
+           return(-1);
+       case '?':
+           if (*s == 0)
+               return(-1);
+           ++w;
+           ++s;
+           break;
+       default:
+           if (*w != *s)
+               return(-1);
+           if (*w == 0)        /* terminator */
+               return(0);
+           ++w;
+           ++s;
+           break;
+       }
+    }
+    /* not reached */
+    return(-1);
+}
+
+
+/*
+ * WildCaseCmp() - compare wild string to sane string, case insensitive
+ *
+ *     Returns 0 on success, -1 on failure.
+ */
+static int
+wildCaseCmp(const char **mary, int d, const char *w, const char *s)
+{
+    int i;
+
+    /*
+     * skip fixed portion
+     */
+    for (;;) {
+       switch(*w) {
+       case '*':
+           /*
+            * optimize terminator
+            */
+           if (w[1] == 0)
+               return(0);
+           if (w[1] != '?' && w[1] != '*') {
+               /*
+                * optimize * followed by non-wild
+                */
+               for (i = 0; s + i < mary[d]; ++i) {
+                   if (s[i] == w[1] && wildCaseCmp(mary, d + 1, w + 1, s + i) == 0)
+                       return(0);
+               }
+           } else {
+               /*
+                * less-optimal
+                */
+               for (i = 0; s + i < mary[d]; ++i) {
+                   if (wildCaseCmp(mary, d + 1, w + 1, s + i) == 0)
+                       return(0);
+               }
+           }
+           mary[d] = s;
+           return(-1);
+       case '?':
+           if (*s == 0)
+               return(-1);
+           ++w;
+           ++s;
+           break;
+       default:
+           if (*w != *s) {
+#define tolower(x)     ((x >= 'A' && x <= 'Z')?(x+('a'-'A')):(x))
+               if (tolower(*w) != tolower(*s))
+                   return(-1);
+           }
+           if (*w == 0)        /* terminator */
+               return(0);
+           ++w;
+           ++s;
+           break;
+       }
+    }
+    /* not reached */
+    return(-1);
+}
+
+int
+devfs_WildCmp(const char *w, const char *s)
+{
+    int i;
+    int c;
+    int slen = strlen(s);
+    const char **mary;
+
+    for (i = c = 0; w[i]; ++i) {
+       if (w[i] == '*')
+           ++c;
+    }
+    mary = kmalloc(sizeof(char *) * (c + 1), M_DEVFS, M_WAITOK);
+    for (i = 0; i < c; ++i)
+       mary[i] = s + slen;
+    i = wildCmp(mary, 0, w, s);
+    kfree(mary, M_DEVFS);
+    return(i);
+}
+
+int
+devfs_WildCaseCmp(const char *w, const char *s)
+{
+    int i;
+    int c;
+    int slen = strlen(s);
+    const char **mary;
+
+    for (i = c = 0; w[i]; ++i) {
+       if (w[i] == '*')
+           ++c;
+    }
+    mary = kmalloc(sizeof(char *) * (c + 1), M_DEVFS, M_WAITOK);
+    for (i = 0; i < c; ++i)
+       mary[i] = s + slen;
+    i = wildCaseCmp(mary, 0, w, s);
+    kfree(mary, M_DEVFS);
+    return(i);
+}
+
index 434336c..bfdce5c 100644 (file)
 
 MALLOC_DECLARE(M_DEVFS);
 
-#if 0
-static int WildCmp(const char *w, const char *s);
-#endif
-static int WildCaseCmp(const char *w, const char *s);
-static int wildCmp(const char **mary, int d, const char *w, const char *s);
-static int wildCaseCmp(const char **mary, int d, const char *w, const char *s);
-
 static d_open_t      devfs_dev_open;
 static d_close_t     devfs_dev_close;
 static d_ioctl_t     devfs_dev_ioctl;
@@ -389,7 +382,7 @@ devfs_rule_checkname(struct devfs_rule *rule, struct devfs_node *node)
                no_match = memcmp(name, node->d_dir.d_name, strlen(name));
        else
 #endif
-       no_match = WildCaseCmp(name, node->d_dir.d_name);
+       no_match = devfs_WildCaseCmp(name, node->d_dir.d_name);
 
        return !no_match;
 }
@@ -496,170 +489,3 @@ devfs_dev_uninit(void *unused)
 SYSINIT(devfsdev,SI_SUB_DRIVERS,SI_ORDER_FIRST,devfs_dev_init,NULL)
 SYSUNINIT(devfsdev, SI_SUB_DRIVERS,SI_ORDER_FIRST,devfs_dev_uninit, NULL);
 
-#if 0
-
-static int
-WildCmp(const char *w, const char *s)
-{
-    int i;
-    int c;
-    int slen = strlen(s);
-    const char **mary;
-
-    for (i = c = 0; w[i]; ++i) {
-       if (w[i] == '*')
-           ++c;
-    }
-    mary = kmalloc(sizeof(char *) * (c + 1), M_DEVFS, M_WAITOK);
-    for (i = 0; i < c; ++i)
-       mary[i] = s + slen;
-    i = wildCmp(mary, 0, w, s);
-    kfree(mary, M_DEVFS);
-    return(i);
-}
-
-#endif
-
-static int
-WildCaseCmp(const char *w, const char *s)
-{
-    int i;
-    int c;
-    int slen = strlen(s);
-    const char **mary;
-
-    for (i = c = 0; w[i]; ++i) {
-       if (w[i] == '*')
-           ++c;
-    }
-    mary = kmalloc(sizeof(char *) * (c + 1), M_DEVFS, M_WAITOK);
-    for (i = 0; i < c; ++i)
-       mary[i] = s + slen;
-    i = wildCaseCmp(mary, 0, w, s);
-    kfree(mary, M_DEVFS);
-    return(i);
-}
-
-/*
- * WildCmp() - compare wild string to sane string
- *
- *     Returns 0 on success, -1 on failure.
- */
-static int
-wildCmp(const char **mary, int d, const char *w, const char *s)
-{
-    int i;
-
-    /*
-     * skip fixed portion
-     */
-    for (;;) {
-       switch(*w) {
-       case '*':
-           /*
-            * optimize terminator
-            */
-           if (w[1] == 0)
-               return(0);
-           if (w[1] != '?' && w[1] != '*') {
-               /*
-                * optimize * followed by non-wild
-                */
-               for (i = 0; s + i < mary[d]; ++i) {
-                   if (s[i] == w[1] && wildCmp(mary, d + 1, w + 1, s + i) == 0)
-                       return(0);
-               }
-           } else {
-               /*
-                * less-optimal
-                */
-               for (i = 0; s + i < mary[d]; ++i) {
-                   if (wildCmp(mary, d + 1, w + 1, s + i) == 0)
-                       return(0);
-               }
-           }
-           mary[d] = s;
-           return(-1);
-       case '?':
-           if (*s == 0)
-               return(-1);
-           ++w;
-           ++s;
-           break;
-       default:
-           if (*w != *s)
-               return(-1);
-           if (*w == 0)        /* terminator */
-               return(0);
-           ++w;
-           ++s;
-           break;
-       }
-    }
-    /* not reached */
-    return(-1);
-}
-
-
-/*
- * WildCaseCmp() - compare wild string to sane string, case insensitive
- *
- *     Returns 0 on success, -1 on failure.
- */
-static int
-wildCaseCmp(const char **mary, int d, const char *w, const char *s)
-{
-    int i;
-
-    /*
-     * skip fixed portion
-     */
-    for (;;) {
-       switch(*w) {
-       case '*':
-           /*
-            * optimize terminator
-            */
-           if (w[1] == 0)
-               return(0);
-           if (w[1] != '?' && w[1] != '*') {
-               /*
-                * optimize * followed by non-wild
-                */
-               for (i = 0; s + i < mary[d]; ++i) {
-                   if (s[i] == w[1] && wildCaseCmp(mary, d + 1, w + 1, s + i) == 0)
-                       return(0);
-               }
-           } else {
-               /*
-                * less-optimal
-                */
-               for (i = 0; s + i < mary[d]; ++i) {
-                   if (wildCaseCmp(mary, d + 1, w + 1, s + i) == 0)
-                       return(0);
-               }
-           }
-           mary[d] = s;
-           return(-1);
-       case '?':
-           if (*s == 0)
-               return(-1);
-           ++w;
-           ++s;
-           break;
-       default:
-           if (*w != *s) {
-#define tolower(x)     ((x >= 'A' && x <= 'Z')?(x+('a'-'A')):(x))
-               if (tolower(*w) != tolower(*s))
-                   return(-1);
-           }
-           if (*w == 0)        /* terminator */
-               return(0);
-           ++w;
-           ++s;
-           break;
-       }
-    }
-    /* not reached */
-    return(-1);
-}