devfs - Allow clone code to reuse an existing device
authorMatthew Dillon <dillon@apollo.backplane.com>
Mon, 5 Jan 2015 04:54:56 +0000 (20:54 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Mon, 5 Jan 2015 04:54:56 +0000 (20:54 -0800)
* Allow the clone code to set a replacement device which already exists
  in devfs.

* This will allow the sound code to cache virtual channel devices after
  use.

sys/vfs/devfs/devfs_core.c
sys/vfs/devfs/devfs_vnops.c

index 1767864..76b1ad1 100644 (file)
@@ -1430,7 +1430,7 @@ devfs_create_all_dev_worker(struct devfs_node *root)
        KKASSERT(root);
 
        TAILQ_FOREACH(dev, &devfs_dev_list, link) {
-               devfs_create_device_node(root, dev, NULL, NULL);
+               devfs_create_device_node(root, dev, NULL, NULL, NULL);
        }
 
        return 0;
@@ -1965,7 +1965,7 @@ devfs_resolve_name_path(char *fullpath, char *buf, char **pathp, char **namep)
  */
 struct devfs_node *
 devfs_create_device_node(struct devfs_node *root, cdev_t dev,
-                        char *dev_name, char *path_fmt, ...)
+                        int *existsp, char *dev_name, char *path_fmt, ...)
 {
        struct devfs_node *parent, *node = NULL;
        char *path = NULL;
@@ -1978,6 +1978,9 @@ devfs_create_device_node(struct devfs_node *root, cdev_t dev,
 
        name_buf = kmalloc(PATH_MAX, M_TEMP, M_WAITOK);
 
+       if (existsp)
+               *existsp = 0;
+
        if (path_fmt != NULL) {
                __va_start(ap, path_fmt);
                kvasnrprintf(&path, PATH_MAX, 10, path_fmt, ap);
@@ -1995,9 +1998,23 @@ devfs_create_device_node(struct devfs_node *root, cdev_t dev,
                parent = devfs_resolve_or_create_path(parent, create_path, 1);
 
 
-       if (devfs_find_device_node_by_name(parent, name)) {
-               devfs_debug(DEVFS_DEBUG_WARNING, "devfs_create_device_node: "
-                       "DEVICE %s ALREADY EXISTS!!! Ignoring creation request.\n", name);
+       node = devfs_find_device_node_by_name(parent, name);
+       if (node) {
+               if (node->d_dev == dev) {
+                       /*
+                        * Allow case where device caches dev after the
+                        * close and might desire to reuse it.
+                        */
+                       if (existsp)
+                               *existsp = 1;
+               } else {
+                       devfs_debug(DEVFS_DEBUG_WARNING,
+                                   "devfs_create_device_node: "
+                                   "DEVICE %s ALREADY EXISTS!!! "
+                                   "Ignoring creation request.\n",
+                                   name);
+                       node = NULL;
+               }
                goto out;
        }
 
@@ -2175,7 +2192,7 @@ devfs_propagate_dev(cdev_t dev, int attach)
                if (attach) {
                        /* Device is being attached */
                        devfs_create_device_node(mnt->root_node, dev,
-                                                NULL, NULL );
+                                                NULL, NULL, NULL);
                } else {
                        /* Device is being detached */
                        devfs_alias_remove(dev);
index 2430be7..d0894dd 100644 (file)
@@ -865,6 +865,8 @@ devfs_spec_open(struct vop_open_args *ap)
        vn_lock(vp, LK_UPGRADE | LK_RETRY);
 
        if (node && ap->a_fp) {
+               int exists;
+
                devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_spec_open: -1.1-\n");
                lockmgr(&devfs_lock, LK_EXCLUSIVE);
 
@@ -874,12 +876,13 @@ devfs_spec_open(struct vop_open_args *ap)
                if (ndev != NULL) {
                        newnode = devfs_create_device_node(
                                        DEVFS_MNTDATA(vp->v_mount)->root_node,
-                                       ndev, NULL, NULL);
+                                       ndev, &exists, NULL, NULL);
                        /* XXX: possibly destroy device if this happens */
 
                        if (newnode != NULL) {
                                dev = ndev;
-                               devfs_link_dev(dev);
+                               if (exists == 0)
+                                       devfs_link_dev(dev);
 
                                devfs_debug(DEVFS_DEBUG_DEBUG,
                                                "parent here is: %s, node is: |%s|\n",
@@ -891,7 +894,8 @@ devfs_spec_open(struct vop_open_args *ap)
                                                ((struct devfs_node *)(TAILQ_LAST(DEVFS_DENODE_HEAD(node->parent), devfs_node_head)))->d_dir.d_name);
 
                                /*
-                                * orig_vp is set to the original vp if we cloned.
+                                * orig_vp is set to the original vp if we
+                                * cloned.
                                 */
                                /* node->flags |= DEVFS_CLONED; */
                                devfs_allocv(&vp, newnode);
@@ -901,10 +905,10 @@ devfs_spec_open(struct vop_open_args *ap)
                }
                lockmgr(&devfs_lock, LK_RELEASE);
                /*
-                * Synchronize devfs here to make sure that, if the cloned device
-                * creates other device nodes in addition to the cloned one,
-                * all of them are created by the time we return from opening
-                * the cloned one.
+                * Synchronize devfs here to make sure that, if the cloned
+                * device creates other device nodes in addition to the
+                * cloned one, all of them are created by the time we return
+                * from opening the cloned one.
                 */
                if (ndev)
                        devfs_config();