From: Matthew Dillon Date: Tue, 4 Aug 2009 04:23:30 +0000 (-0700) Subject: DEVFS - Rollup X-Git-Tag: v2.4.0~375 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/ca8d7677b7d28d7b85590e5ad8572db1f3d96bf3 DEVFS - Rollup * Use a dynamically sized dirent structure for devfs_nodes, saving a lot of memory. * Fix m_* lexical space overloading issues. * Fix issues with numerous uninitialized fields. * Completely initialize the devfs_node before making it visible to userland. * Properly invalidate negative entries in the namecache when adding new devfs nodes. Also properly recycle disconnected vnodes. * Properly disassociate a devfs node from its vnode when freeing the devfs node. * Clarify device reference counts and fix a bug or two. * Get reprobes working. Sniff writes and automatically reprobe the whole disk or a particular slice on close() if the MBR or label area is modified. * Fix memory leak when mounting/umounting devfs. Submitted-by: Alex Hornung --- diff --git a/sys/vfs/devfs/devfs.h b/sys/vfs/devfs/devfs.h index 9199227868..2163ed708b 100644 --- a/sys/vfs/devfs/devfs.h +++ b/sys/vfs/devfs/devfs.h @@ -84,11 +84,18 @@ struct devfs_dev { }; */ +struct devfs_dirent { + ino_t d_ino; /* file number of entry */ + uint16_t d_namlen; /* strlen(d_name) */ + uint8_t d_type; /* file type */ + char *d_name; +}; + struct devfs_node { cdev_t d_dev; /* device assoicated with this node */ struct mount *mp; /* mount point of this node */ - struct dirent d_dir; /* dirent data (name, inode, ...) */ + struct devfs_dirent d_dir; /* dirent data (name, inode, ...) */ struct vnode *v_node; /* assoicated vnode */ struct devfs_node *parent; /* parent of this node */ devfs_nodetype node_type; /* devfs node type */ @@ -113,8 +120,6 @@ struct devfs_node { struct timespec mtime; /* time of last modification */ struct timespec ctime; /* time file changed */ - - /* Other members */ TAILQ_ENTRY(devfs_node) link; TAILQ_HEAD(, devfs_node) list; /* linked list of children */ @@ -207,20 +212,25 @@ typedef struct devfs_msg { struct dev_ops *ops; int minor; } __m_ops; + struct { + char *name; + uint32_t flag; + } __m_flags; } __m_u; -#define m_chandler __m_u.__m_chandler -#define m_mnt __m_u.__m_mnt.mnt -#define m_load __m_u.__m_gen.load -#define m_response __m_u.__m_resp.resp -#define m_dev __m_u.__m_dev -#define m_link __m_u.__m_link -#define m_udev __m_u.__m_udev.udev -#define m_cdev __m_u.__m_cdev.cdev -#define m_name __m_u.__m_name.name -#define m_clone __m_u.__m_clone -#define m_node __m_u.__m_node.node -#define m_ops __m_u.__m_ops +#define mdv_chandler __m_u.__m_chandler +#define mdv_mnt __m_u.__m_mnt.mnt +#define mdv_load __m_u.__m_gen.load +#define mdv_response __m_u.__m_resp.resp +#define mdv_dev __m_u.__m_dev +#define mdv_link __m_u.__m_link +#define mdv_udev __m_u.__m_udev.udev +#define mdv_cdev __m_u.__m_cdev.cdev +#define mdv_name __m_u.__m_name.name +#define mdv_clone __m_u.__m_clone +#define mdv_node __m_u.__m_node.node +#define mdv_ops __m_u.__m_ops +#define mdv_flags __m_u.__m_flags } *devfs_msg_t; @@ -277,19 +287,21 @@ typedef void (devfs_scan_t)(cdev_t); #define DEVFS_APPLY_RULES 0x0F #define DEVFS_RESET_RULES 0x10 #define DEVFS_SCAN_CALLBACK 0x11 +#define DEVFS_CLR_SUBNAMES_FLAG 0x12 +#define DEVFS_DESTROY_SUBNAMES_WO_FLAG 0x13 #define DEVFS_SYNC 0x99 /* * Node flags */ -#define DEVFS_NODE_LINKED 0x01 /* Node is linked into topology */ +#define DEVFS_NODE_LINKED 0x01 /* Linked into topology */ #define DEVFS_USER_CREATED 0x02 /* Node was user-created */ -#define DEVFS_NO_TRACE 0x04 /* Don't trace orphanage */ -#define DEVFS_CLONED 0x08 /* Node was created by the clone code */ +#define DEVFS_ORPHANED 0x04 /* on orphan list */ +#define DEVFS_CLONED 0x08 /* Created by cloning code */ #define DEVFS_HIDDEN 0x10 /* Makes node inaccessible, apart from already allocated vnodes*/ #define DEVFS_INVISIBLE 0x20 /* Makes node invisible in a readdir() */ -#define DEVFS_PTY 0x40 /* Node is linked to a PTY device */ -//#define DEVFS_LINK 0x20 +#define DEVFS_PTY 0x40 /* PTY device */ +#define DEVFS_DESTROYED 0x80 /* Sanity check */ /* @@ -394,7 +406,6 @@ struct devfs_node *devfs_find_device_node(struct devfs_node *, cdev_t); struct devfs_node *devfs_find_device_node_by_name(struct devfs_node *, char *); cdev_t devfs_new_cdev(struct dev_ops *, int); -int devfs_destroy_cdev(cdev_t); cdev_t devfs_find_device_by_name(const char *, ...); cdev_t devfs_find_device_by_udev(udev_t); @@ -404,7 +415,6 @@ int devfs_clone_handler_del(char *); int devfs_clone(char *, size_t *, cdev_t *, int, struct ucred *); int devfs_link_dev(cdev_t); -int devfs_unlink_dev(cdev_t); int devfs_make_alias(char *, cdev_t); @@ -416,5 +426,8 @@ int devfs_reset_rules(char *); int devfs_scan_callback(devfs_scan_t *); int devfs_node_to_path(struct devfs_node *, char *); +int devfs_clr_subnames_flag(char *, uint32_t); +int devfs_destroy_subnames_without_flag(char *, uint32_t); + void devfs_config(void *); #endif /* _VFS_DEVFS_H_ */ diff --git a/sys/vfs/devfs/devfs_core.c b/sys/vfs/devfs/devfs_core.c index 2a03517ed5..44aef4494f 100644 --- a/sys/vfs/devfs/devfs_core.c +++ b/sys/vfs/devfs/devfs_core.c @@ -104,6 +104,7 @@ static int devfs_destroy_dev_worker(cdev_t); static int devfs_destroy_subnames_worker(char *); static int devfs_destroy_dev_by_ops_worker(struct dev_ops *, int); static int devfs_propagate_dev(cdev_t, int); +static int devfs_unlink_dev(cdev_t dev); static int devfs_chandler_add_worker(char *, d_clone_t *); static int devfs_chandler_del_worker(char *); @@ -128,6 +129,9 @@ static int devfs_alias_propagate(struct devfs_alias *); static int devfs_alias_apply(struct devfs_node *, struct devfs_alias *); static int devfs_alias_check_create(struct devfs_node *); +static int devfs_clr_subnames_flag_worker(char *, uint32_t); +static int devfs_destroy_subnames_without_flag_worker(char *, uint32_t); + /* * devfs_debug() is a SYSCTL and TUNABLE controlled debug output function using kvprintf */ @@ -145,12 +149,14 @@ devfs_debug(int level, char *fmt, ...) } /* - * devfs_allocp() Allocates a new devfs node with the specified parameters. The node is also automatically linked - * into the topology if a parent is specified. It also calls the rule and alias stuff to be applied on the new - * node + * devfs_allocp() Allocates a new devfs node with the specified + * parameters. The node is also automatically linked into the topology + * if a parent is specified. It also calls the rule and alias stuff to + * be applied on the new node */ struct devfs_node * -devfs_allocp(devfs_nodetype devfsnodetype, char *name, struct devfs_node *parent, struct mount *mp, cdev_t dev) +devfs_allocp(devfs_nodetype devfsnodetype, char *name, + struct devfs_node *parent, struct mount *mp, cdev_t dev) { struct devfs_node *node = NULL; size_t namlen = strlen(name); @@ -158,12 +164,14 @@ devfs_allocp(devfs_nodetype devfsnodetype, char *name, struct devfs_node *parent node = objcache_get(devfs_node_cache, M_WAITOK); + bzero(node, sizeof(*node)); + atomic_add_int(&(DEVFS_MNTDATA(mp)->leak_count), 1); + node->d_dev = NULL; node->nchildren = 1; node->mp = mp; node->d_dir.d_ino = devfs_fetch_ino(); - node->flags = 0; node->cookie_jar = 2; /* Leave 0 and 1 for '.' and '..', respectively */ /* Access Control members */ @@ -171,14 +179,6 @@ devfs_allocp(devfs_nodetype devfsnodetype, char *name, struct devfs_node *parent node->uid = DEVFS_DEFAULT_UID; /* owner user id */ node->gid = DEVFS_DEFAULT_GID; /* owner group id */ - /* Null the symlink */ - node->symlink_name = NULL; - node->symlink_namelen = 0; - node->link_target = NULL; - - /* Null the count of links to this node */ - node->nlinks = 0; - switch (devfsnodetype) { case Proot: node->flags |= DEVFS_NODE_LINKED; //Make sure we don't recycle the root vnode @@ -218,7 +218,10 @@ devfs_allocp(devfs_nodetype devfsnodetype, char *name, struct devfs_node *parent node->node_type = devfsnodetype; /* Init the dirent structure of each devfs vnode */ + KKASSERT(namlen < 256); + node->d_dir.d_namlen = namlen; + node->d_dir.d_name = kmalloc(namlen+1, M_DEVFS, M_WAITOK); memcpy(node->d_dir.d_name, name, namlen); node->d_dir.d_name[namlen] = '\0'; @@ -228,24 +231,28 @@ devfs_allocp(devfs_nodetype devfsnodetype, char *name, struct devfs_node *parent /* Apply rules */ devfs_rule_check_apply(node); - /* If there is a parent, increment the number of his children and add the new - * child to the parent's list of children */ + /* xtime members */ + nanotime(&node->atime); + node->mtime = node->ctime = node->atime; + + /* + * Associate with parent as last step, clean out namecache + * reference. + */ devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocp: about to insert node\n"); if ((parent != NULL) && - ((parent->node_type == Proot) || (parent->node_type == Pdir))) { - TAILQ_INSERT_TAIL(DEVFS_DENODE_HEAD(parent), node, link); - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocp: node inserted\n"); + ((parent->node_type == Proot) || (parent->node_type == Pdir))) { + devfs_debug(DEVFS_DEBUG_DEBUG, + "devfs_allocp: node inserted %p\n", + node); parent->nchildren++; node->cookie = parent->cookie_jar++; node->flags |= DEVFS_NODE_LINKED; - } - - /* xtime members */ - nanotime(&node->atime); - node->mtime = node->ctime = node->atime; + TAILQ_INSERT_TAIL(DEVFS_DENODE_HEAD(parent), node, link); - /* Null out open references to this "file" */ - node->refs = 0; + /* This forces negative namecache lookups to clear */ + ++mp->mnt_namecache_gen; + } devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_allocp -end:2-\n"); return node; @@ -362,15 +369,22 @@ devfs_allocvp(struct mount *mp, struct vnode **vpp, devfs_nodetype devfsnodetype } /* - * devfs_freep frees a devfs node *ONLY* if it is the root node or the node is not linked - * into the topology anymore. It also calls the tracer helper to keep track of possible - * orphans. + * Destroy the devfs_node. The node must be unlinked from the topology. + * + * This function will also destroy any vnode association with the node + * and device. + * + * The cdev_t itself remains intact. */ int devfs_freep(struct devfs_node *node) { + struct vnode *vp; + KKASSERT(node); - KKASSERT(((node->flags & DEVFS_NODE_LINKED) == 0) || (node->node_type == Proot)); + KKASSERT(((node->flags & DEVFS_NODE_LINKED) == 0) || + (node->node_type == Proot)); + KKASSERT((node->flags & DEVFS_DESTROYED) == 0); atomic_subtract_int(&(DEVFS_MNTDATA(node->mp)->leak_count), 1); if (node->symlink_name) { @@ -378,20 +392,36 @@ devfs_freep(struct devfs_node *node) node->symlink_name = NULL; } - if ((node->flags & DEVFS_NO_TRACE) == 0) + /* + * Remove the node from the orphan list if it is still on it. + */ + if (node->flags & DEVFS_ORPHANED) devfs_tracer_del_orphan(node); - //XXX: Add something to make sure that no vnode is associated with this devfs node + /* + * Disassociate the vnode from the node. This also prevents the + * vnode's reclaim code from double-freeing the node. + */ + if ((vp = node->v_node) != NULL) { + vp->v_rdev = NULL; + vp->v_data = NULL; + node->v_node = NULL; + } + if (node->d_dir.d_name) + kfree(node->d_dir.d_name, M_DEVFS); + node->flags |= DEVFS_DESTROYED; + objcache_put(devfs_node_cache, node); return 0; } /* - * devfs_unlinkp unlinks a devfs node out of the topology and adds the node - * to the orphan list. It is later removed by freep. - * If a vnode is still associated to the devfs node, then the vnode's rdev - * is NULLed. + * Unlink the devfs node from the topology and add it to the orphan list. + * The node will later be destroyed by freep. + * + * Any vnode association, including the v_rdev and v_data, remains intact + * until the freep. */ int devfs_unlinkp(struct devfs_node *node) @@ -400,10 +430,13 @@ devfs_unlinkp(struct devfs_node *node) KKASSERT(node); devfs_tracer_add_orphan(node); - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_unlinkp for %s\n", node->d_dir.d_name); + devfs_debug(DEVFS_DEBUG_DEBUG, + "devfs_unlinkp for %s\n", node->d_dir.d_name); parent = node->parent; - /* If the parent is known we can unlink the node out of the topology */ + /* + * If the parent is known we can unlink the node out of the topology + */ if (parent) { TAILQ_REMOVE(DEVFS_DENODE_HEAD(parent), node, link); parent->nchildren--; @@ -411,33 +444,29 @@ devfs_unlinkp(struct devfs_node *node) node->flags &= ~DEVFS_NODE_LINKED; } node->parent = NULL; - - /* Invalidate vnode as a device node */ - if (node->v_node) - node->v_node->v_rdev = NULL; - return 0; } /* - * devfs_reaperp() is a recursive function that iterates through all the topology, - * unlinking and freeing all devfs nodes. + * devfs_reaperp() is a recursive function that iterates through all the + * topology, unlinking and freeing all devfs nodes. */ int devfs_reaperp(struct devfs_node *node) { struct devfs_node *node1, *node2; - //devfs_debug(DEVFS_DEBUG_DEBUG, "This node is called %s\n", node->d_dir.d_name); if ((node->node_type == Proot) || (node->node_type == Pdir)) { - devfs_debug(DEVFS_DEBUG_DEBUG, "This node is Pdir or Proot; has %d children\n", node->nchildren); + devfs_debug(DEVFS_DEBUG_DEBUG, + "This node is Pdir or Proot; has %d children\n", + node->nchildren); if (node->nchildren > 2) { - TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node), link, node2) { + TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node), + link, node2) { devfs_reaperp(node1); } } } - //devfs_debug(DEVFS_DEBUG_DEBUG, "This node is called %s and it is being freed\n", node->d_dir.d_name); devfs_unlinkp(node); devfs_freep(node); @@ -445,9 +474,9 @@ devfs_reaperp(struct devfs_node *node) } /* - * devfs_gc() is devfs garbage collector. It takes care of unlinking and freeing a - * node, but also removes empty directories and links that link via devfs auto-link - * mechanism to the node being deleted. + * devfs_gc() is devfs garbage collector. It takes care of unlinking and + * freeing a node, but also removes empty directories and links that link + * via devfs auto-link mechanism to the node being deleted. */ int devfs_gc(struct devfs_node *node) @@ -472,18 +501,21 @@ devfs_gc_dirs(struct devfs_node *node) { struct devfs_node *node1, *node2; - //devfs_debug(DEVFS_DEBUG_DEBUG, "This node is called %s\n", node->d_dir.d_name); - if ((node->node_type == Proot) || (node->node_type == Pdir)) { - devfs_debug(DEVFS_DEBUG_DEBUG, "This node is Pdir or Proot; has %d children\n", node->nchildren); + devfs_debug(DEVFS_DEBUG_DEBUG, + "This node is Pdir or Proot; has %d children\n", + node->nchildren); if (node->nchildren > 2) { - TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node), link, node2) { + TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node), + link, node2) { devfs_gc_dirs(node1); } } if (node->nchildren == 2) { - devfs_debug(DEVFS_DEBUG_DEBUG, "This node is called %s and it is empty\n", node->d_dir.d_name); + devfs_debug(DEVFS_DEBUG_DEBUG, + "This node is called %s and it is empty\n", + node->d_dir.d_name); devfs_unlinkp(node); devfs_freep(node); } @@ -497,7 +529,8 @@ devfs_gc_dirs(struct devfs_node *node) * eauto-linked nodes linking to the node being deleted. */ static int -devfs_gc_links(struct devfs_node *node, struct devfs_node *target, size_t nlinks) +devfs_gc_links(struct devfs_node *node, struct devfs_node *target, + size_t nlinks) { struct devfs_node *node1, *node2; @@ -522,22 +555,30 @@ devfs_gc_links(struct devfs_node *node, struct devfs_node *target, size_t nlinks } /* - * devfs_create_dev() is the asynchronous entry point for device creation. It - * just sends a message with the relevant details to the devfs core. + * devfs_create_dev() is the asynchronous entry point for device creation. + * It just sends a message with the relevant details to the devfs core. + * + * This function will reference the passed device. The reference is owned + * by devfs and represents all of the device's node associations. */ int devfs_create_dev(cdev_t dev, uid_t uid, gid_t gid, int perms) { __uint64_t id; - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_create_dev -1-, name: %s (%p)\n", dev->si_name, dev); + devfs_debug(DEVFS_DEBUG_DEBUG, + "devfs_create_dev -1-, name: %s (%p)\n", + dev->si_name, dev); + reference_dev(dev); id = devfs_msg_send_dev(DEVFS_DEVICE_CREATE, dev, uid, gid, perms); - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_create_dev -end:2- (unique id: %x) / (%p)\n", id, dev); + devfs_debug(DEVFS_DEBUG_DEBUG, + "devfs_create_dev -end:2- (unique id: %x) / (%p)\n", + id, dev); return 0; } /* - * devfs_destroy_dev() is the asynchronous entry point for device destruction. It - * just sends a message with the relevant details to the devfs core. + * devfs_destroy_dev() is the asynchronous entry point for device destruction. + * It just sends a message with the relevant details to the devfs core. */ int devfs_destroy_dev(cdev_t dev) @@ -547,8 +588,9 @@ devfs_destroy_dev(cdev_t dev) } /* - * devfs_mount_add() is the synchronous entry point for adding a new devfs mount. - * It sends a synchronous message with the relevant details to the devfs core. + * devfs_mount_add() is the synchronous entry point for adding a new devfs + * mount. It sends a synchronous message with the relevant details to the + * devfs core. */ int devfs_mount_add(struct devfs_mnt_data *mnt) @@ -556,7 +598,7 @@ devfs_mount_add(struct devfs_mnt_data *mnt) devfs_msg_t msg; msg = devfs_msg_get(); - msg->m_mnt = mnt; + msg->mdv_mnt = mnt; msg = devfs_msg_send_sync(DEVFS_MOUNT_ADD, msg); devfs_msg_put(msg); @@ -573,7 +615,7 @@ devfs_mount_del(struct devfs_mnt_data *mnt) devfs_msg_t msg; msg = devfs_msg_get(); - msg->m_mnt = mnt; + msg->mdv_mnt = mnt; msg = devfs_msg_send_sync(DEVFS_MOUNT_DEL, msg); devfs_msg_put(msg); @@ -581,19 +623,53 @@ devfs_mount_del(struct devfs_mnt_data *mnt) } /* - * devfs_destroy_subnames() is the asynchronous entry point for device destruction + * devfs_destroy_subnames() is the synchronous entry point for device destruction * by subname. It just sends a message with the relevant details to the devfs core. */ int devfs_destroy_subnames(char *name) { - devfs_msg_send_generic(DEVFS_DESTROY_SUBNAMES, name); + devfs_msg_t msg; + + msg = devfs_msg_get(); + msg->mdv_load = name; + msg = devfs_msg_send_sync(DEVFS_DESTROY_SUBNAMES, msg); + devfs_msg_put(msg); + return 0; +} + +int +devfs_clr_subnames_flag(char *name, uint32_t flag) +{ + devfs_msg_t msg; + + msg = devfs_msg_get(); + msg->mdv_flags.name = name; + msg->mdv_flags.flag = flag; + msg = devfs_msg_send_sync(DEVFS_CLR_SUBNAMES_FLAG, msg); + devfs_msg_put(msg); + + return 0; +} + +int +devfs_destroy_subnames_without_flag(char *name, uint32_t flag) +{ + devfs_msg_t msg; + + msg = devfs_msg_get(); + msg->mdv_flags.name = name; + msg->mdv_flags.flag = flag; + msg = devfs_msg_send_sync(DEVFS_DESTROY_SUBNAMES_WO_FLAG, msg); + devfs_msg_put(msg); + return 0; } /* - * devfs_create_all_dev is the asynchronous entry point to trigger device node creation. - * It just sends a message with the relevant details to the devfs core. + * devfs_create_all_dev is the asynchronous entry point to trigger device + * node creation. It just sends a message with the relevant details to + * the devfs core. */ int devfs_create_all_dev(struct devfs_node *root) @@ -603,9 +679,9 @@ devfs_create_all_dev(struct devfs_node *root) } /* - * devfs_destroy_dev_by_ops is the asynchronous entry point to destroy all devices with - * a specific set of dev_ops and minor. - * It just sends a message with the relevant details to the devfs core. + * devfs_destroy_dev_by_ops is the asynchronous entry point to destroy all + * devices with a specific set of dev_ops and minor. It just sends a + * message with the relevant details to the devfs core. */ int devfs_destroy_dev_by_ops(struct dev_ops *ops, int minor) @@ -615,32 +691,45 @@ devfs_destroy_dev_by_ops(struct dev_ops *ops, int minor) } /* - * devfs_clone_handler_add is the asynchronous entry point to add a new clone handler. - * It just sends a message with the relevant details to the devfs core. + * devfs_clone_handler_add is the synchronous entry point to add a new + * clone handler. It just sends a message with the relevant details to + * the devfs core. */ int devfs_clone_handler_add(char *name, d_clone_t *nhandler) { - devfs_msg_send_chandler(DEVFS_CHANDLER_ADD, name, nhandler); + devfs_msg_t msg; + + msg = devfs_msg_get(); + msg->mdv_chandler.name = name; + msg->mdv_chandler.nhandler = nhandler; + msg = devfs_msg_send_sync(DEVFS_CHANDLER_ADD, msg); + devfs_msg_put(msg); return 0; } /* - * devfs_clone_handler_del is the asynchronous entry point to remove a clone handler. - * It just sends a message with the relevant details to the devfs core. + * devfs_clone_handler_del is the synchronous entry point to remove a + * clone handler. It just sends a message with the relevant details to + * the devfs core. */ int devfs_clone_handler_del(char *name) { - devfs_msg_send_chandler(DEVFS_CHANDLER_DEL, name, NULL); + devfs_msg_t msg; + + msg = devfs_msg_get(); + msg->mdv_chandler.name = name; + msg->mdv_chandler.nhandler = NULL; + msg = devfs_msg_send_sync(DEVFS_CHANDLER_DEL, msg); + devfs_msg_put(msg); return 0; } /* - * devfs_find_device_by_name is the synchronous entry point to find a device given - * its name. - * It sends a synchronous message with the relevant details to the devfs core and - * returns the answer. + * devfs_find_device_by_name is the synchronous entry point to find a + * device given its name. It sends a synchronous message with the + * relevant details to the devfs core and returns the answer. */ cdev_t devfs_find_device_by_name(const char *fmt, ...) @@ -663,9 +752,9 @@ devfs_find_device_by_name(const char *fmt, ...) devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_find_device_by_name: %s -1-\n", target); msg = devfs_msg_get(); - msg->m_name = target; + msg->mdv_name = target; msg = devfs_msg_send_sync(DEVFS_FIND_DEVICE_BY_NAME, msg); - found = msg->m_cdev; + found = msg->mdv_cdev; devfs_msg_put(msg); devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_find_device_by_name found? %s -end:2-\n", (found)?"YES":"NO"); @@ -673,10 +762,9 @@ devfs_find_device_by_name(const char *fmt, ...) } /* - * devfs_find_device_by_udev is the synchronous entry point to find a device given - * its udev number. - * It sends a synchronous message with the relevant details to the devfs core and - * returns the answer. + * devfs_find_device_by_udev is the synchronous entry point to find a + * device given its udev number. It sends a synchronous message with + * the relevant details to the devfs core and returns the answer. */ cdev_t devfs_find_device_by_udev(udev_t udev) @@ -685,23 +773,28 @@ devfs_find_device_by_udev(udev_t udev) devfs_msg_t msg; msg = devfs_msg_get(); - msg->m_udev = udev; + msg->mdv_udev = udev; msg = devfs_msg_send_sync(DEVFS_FIND_DEVICE_BY_UDEV, msg); - found = msg->m_cdev; + found = msg->mdv_cdev; devfs_msg_put(msg); - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_find_device_by_udev found? %s -end:3-\n", (found)?found->si_name:"NO"); + devfs_debug(DEVFS_DEBUG_DEBUG, + "devfs_find_device_by_udev found? %s -end:3-\n", + ((found) ? found->si_name:"NO")); return found; } /* - * devfs_make_alias is the asynchronous entry point to register an alias for a device. - * It just sends a message with the relevant details to the devfs core. + * devfs_make_alias is the asynchronous entry point to register an alias + * for a device. It just sends a message with the relevant details to the + * devfs core. */ int devfs_make_alias(char *name, cdev_t dev_target) { - struct devfs_alias *alias = kmalloc(sizeof(struct devfs_alias), M_DEVFS, M_WAITOK); + struct devfs_alias *alias; + + alias = kmalloc(sizeof(struct devfs_alias), M_DEVFS, M_WAITOK); memcpy(alias->name, name, strlen(name) + 1); alias->dev_target = dev_target; @@ -710,8 +803,9 @@ devfs_make_alias(char *name, cdev_t dev_target) } /* - * 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. + * 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. */ int devfs_apply_rules(char *mntto) @@ -764,7 +858,7 @@ devfs_scan_callback(devfs_scan_t *callback) KKASSERT(sizeof(callback) == sizeof(void *)); msg = devfs_msg_get(); - msg->m_load = callback; + msg->mdv_load = callback; msg = devfs_msg_send_sync(DEVFS_SCAN_CALLBACK, msg); devfs_msg_put(msg); @@ -851,7 +945,7 @@ __uint32_t devfs_msg_send_generic(uint32_t cmd, void *load) { devfs_msg_t devfs_msg = devfs_msg_get(); - devfs_msg->m_load = load; + devfs_msg->mdv_load = load; devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_send_generic -1- (%p)\n", load); @@ -865,7 +959,7 @@ __uint32_t devfs_msg_send_name(uint32_t cmd, char *name) { devfs_msg_t devfs_msg = devfs_msg_get(); - devfs_msg->m_name = name; + devfs_msg->mdv_name = name; return devfs_msg_send(cmd, devfs_msg); } @@ -877,7 +971,7 @@ __uint32_t devfs_msg_send_mount(uint32_t cmd, struct devfs_mnt_data *mnt) { devfs_msg_t devfs_msg = devfs_msg_get(); - devfs_msg->m_mnt = mnt; + devfs_msg->mdv_mnt = mnt; devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_send_mp -1- (%p)\n", mnt); @@ -891,8 +985,8 @@ __uint32_t devfs_msg_send_ops(uint32_t cmd, struct dev_ops *ops, int minor) { devfs_msg_t devfs_msg = devfs_msg_get(); - devfs_msg->m_ops.ops = ops; - devfs_msg->m_ops.minor = minor; + devfs_msg->mdv_ops.ops = ops; + devfs_msg->mdv_ops.minor = minor; return devfs_msg_send(cmd, devfs_msg); } @@ -904,8 +998,8 @@ __uint32_t devfs_msg_send_chandler(uint32_t cmd, char *name, d_clone_t handler) { devfs_msg_t devfs_msg = devfs_msg_get(); - devfs_msg->m_chandler.name = name; - devfs_msg->m_chandler.nhandler = handler; + devfs_msg->mdv_chandler.name = name; + devfs_msg->mdv_chandler.nhandler = handler; return devfs_msg_send(cmd, devfs_msg); } @@ -917,10 +1011,10 @@ __uint32_t devfs_msg_send_dev(uint32_t cmd, cdev_t dev, uid_t uid, gid_t gid, int perms) { devfs_msg_t devfs_msg = devfs_msg_get(); - devfs_msg->m_dev.dev = dev; - devfs_msg->m_dev.uid = uid; - devfs_msg->m_dev.gid = gid; - devfs_msg->m_dev.perms = perms; + devfs_msg->mdv_dev.dev = dev; + devfs_msg->mdv_dev.uid = uid; + devfs_msg->mdv_dev.gid = gid; + devfs_msg->mdv_dev.perms = perms; devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_send_dev -1- (%p)\n", dev); @@ -935,9 +1029,9 @@ __uint32_t devfs_msg_send_link(uint32_t cmd, char *name, char *target, struct mount *mp) { devfs_msg_t devfs_msg = devfs_msg_get(); - devfs_msg->m_link.name = name; - devfs_msg->m_link.target = target; - devfs_msg->m_link.mp = mp; + devfs_msg->mdv_link.name = name; + devfs_msg->mdv_link.target = target; + devfs_msg->mdv_link.mp = mp; return devfs_msg_send(cmd, devfs_msg); @@ -951,8 +1045,8 @@ devfs_msg_send_link(uint32_t cmd, char *name, char *target, struct mount *mp) static void devfs_msg_core(void *arg) { - uint8_t run = 1; - devfs_msg_t msg; + uint8_t run = 1; + devfs_msg_t msg; cdev_t dev; struct devfs_mnt_data *mnt; struct devfs_node *node; @@ -963,59 +1057,66 @@ devfs_msg_core(void *arg) wakeup(td_core/*devfs_id*/); devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_core -3-\n"); - while (run) { + while (run) { devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_core -loop:4-\n"); - msg = (devfs_msg_t)lwkt_waitport(&devfs_msg_port, 0); + msg = (devfs_msg_t)lwkt_waitport(&devfs_msg_port, 0); devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_core, new msg: %x (unique id: %x)\n", (unsigned int)msg->hdr.u.ms_result, msg->id); lockmgr(&devfs_lock, LK_EXCLUSIVE); - switch (msg->hdr.u.ms_result) { - - case DEVFS_DEVICE_CREATE: - dev = msg->m_dev.dev; - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_core device create msg %s (%p)\n", dev->si_name, dev); - devfs_create_dev_worker(dev, msg->m_dev.uid, msg->m_dev.gid, msg->m_dev.perms); + switch (msg->hdr.u.ms_result) { + + case DEVFS_DEVICE_CREATE: + dev = msg->mdv_dev.dev; + devfs_debug(DEVFS_DEBUG_DEBUG, + "devfs_msg_core device create msg %s(%p)\n", + dev->si_name, dev); + devfs_create_dev_worker(dev, + msg->mdv_dev.uid, + msg->mdv_dev.gid, + msg->mdv_dev.perms); break; case DEVFS_DEVICE_DESTROY: - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_core device destroy msg\n"); - dev = msg->m_dev.dev; + devfs_debug(DEVFS_DEBUG_DEBUG, + "devfs_msg_core device destroy msg\n"); + dev = msg->mdv_dev.dev; devfs_destroy_dev_worker(dev); - break; + break; case DEVFS_DESTROY_SUBNAMES: - devfs_destroy_subnames_worker(msg->m_load); + devfs_destroy_subnames_worker(msg->mdv_load); break; case DEVFS_DESTROY_DEV_BY_OPS: - devfs_destroy_dev_by_ops_worker(msg->m_ops.ops, msg->m_ops.minor); + devfs_destroy_dev_by_ops_worker(msg->mdv_ops.ops, + msg->mdv_ops.minor); break; case DEVFS_CREATE_ALL_DEV: devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_core device create ALL msg\n"); - node = (struct devfs_node *)msg->m_load; + node = (struct devfs_node *)msg->mdv_load; devfs_create_all_dev_worker(node); break; case DEVFS_MOUNT_ADD: - mnt = msg->m_mnt; + mnt = msg->mdv_mnt; TAILQ_INSERT_TAIL(&devfs_mnt_list, mnt, link); devfs_create_all_dev_worker(mnt->root_node); break; case DEVFS_MOUNT_DEL: - mnt = msg->m_mnt; + mnt = msg->mdv_mnt; TAILQ_REMOVE(&devfs_mnt_list, mnt, link); - devfs_debug(DEVFS_DEBUG_DEBUG, "There are still %d devfs_node elements!!!\n", mnt->leak_count); + devfs_debug(DEVFS_DEBUG_SHOW, "There are still %d devfs_node elements!!!\n", mnt->leak_count); devfs_reaperp(mnt->root_node); - devfs_debug(DEVFS_DEBUG_DEBUG, "Leaked %d devfs_node elements!!!\n", mnt->leak_count); + devfs_debug(DEVFS_DEBUG_SHOW, "Leaked %d devfs_node elements!!!\n", mnt->leak_count); break; case DEVFS_CHANDLER_ADD: - devfs_chandler_add_worker(msg->m_chandler.name, msg->m_chandler.nhandler); + devfs_chandler_add_worker(msg->mdv_chandler.name, msg->mdv_chandler.nhandler); break; case DEVFS_CHANDLER_DEL: - devfs_chandler_del_worker(msg->m_chandler.name); + devfs_chandler_del_worker(msg->mdv_chandler.name); break; case DEVFS_FIND_DEVICE_BY_NAME: @@ -1027,35 +1128,46 @@ devfs_msg_core(void *arg) break; case DEVFS_MAKE_ALIAS: - devfs_make_alias_worker((struct devfs_alias *)msg->m_load); + devfs_make_alias_worker((struct devfs_alias *)msg->mdv_load); break; case DEVFS_APPLY_RULES: - devfs_apply_reset_rules_caller(msg->m_name, 1); + devfs_apply_reset_rules_caller(msg->mdv_name, 1); break; case DEVFS_RESET_RULES: - devfs_apply_reset_rules_caller(msg->m_name, 0); + devfs_apply_reset_rules_caller(msg->mdv_name, 0); break; case DEVFS_SCAN_CALLBACK: - devfs_scan_callback_worker((devfs_scan_t *)msg->m_load); + devfs_scan_callback_worker((devfs_scan_t *)msg->mdv_load); break; - case DEVFS_TERMINATE_CORE: - run = 0; - break; + case DEVFS_CLR_SUBNAMES_FLAG: + devfs_clr_subnames_flag_worker(msg->mdv_flags.name, + msg->mdv_flags.flag); + break; - case DEVFS_SYNC: + case DEVFS_DESTROY_SUBNAMES_WO_FLAG: + devfs_destroy_subnames_without_flag_worker(msg->mdv_flags.name, + msg->mdv_flags.flag); break; - default: - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_msg_core: unknown message received at core\n"); - } + case DEVFS_TERMINATE_CORE: + run = 0; + break; + case DEVFS_SYNC: + break; + default: + devfs_debug(DEVFS_DEBUG_DEBUG, + "devfs_msg_core: unknown message " + "received at core\n"); + break; + } lockmgr(&devfs_lock, LK_RELEASE); - lwkt_replymsg((lwkt_msg_t)msg, 0); - } + lwkt_replymsg((lwkt_msg_t)msg, 0); + } wakeup(td_core/*devfs_id*/); lwkt_exit(); } @@ -1064,19 +1176,23 @@ devfs_msg_core(void *arg) * Worker function to insert a new dev into the dev list and initialize its * permissions. It also calls devfs_propagate_dev which in turn propagates * the change to all mount points. + * + * The passed dev is already referenced. This reference is eaten by this + * function and represents the dev's linkage into devfs_dev_list. */ static int devfs_create_dev_worker(cdev_t dev, uid_t uid, gid_t gid, int perms) { KKASSERT(dev); - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_create_dev_worker -1- -%s- (%p)\n", dev->si_name, dev); + devfs_debug(DEVFS_DEBUG_DEBUG, + "devfs_create_dev_worker -1- -%s- (%p)\n", + dev->si_name, dev); dev->si_uid = uid; dev->si_gid = gid; dev->si_perms = perms; devfs_link_dev(dev); - reference_dev(dev); devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_create_dev_worker -2-\n"); devfs_propagate_dev(dev, 1); @@ -1092,15 +1208,18 @@ devfs_create_dev_worker(cdev_t dev, uid_t uid, gid_t gid, int perms) static int devfs_destroy_dev_worker(cdev_t dev) { + int error; + KKASSERT(dev); KKASSERT((lockstatus(&devfs_lock, curthread)) == LK_EXCLUSIVE); devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_destroy_dev_worker -1- %s\n", dev->si_name); - devfs_unlink_dev(dev); + error = devfs_unlink_dev(dev); devfs_propagate_dev(dev, 0); + if (error == 0) + release_dev(dev); /* link ref */ release_dev(dev); release_dev(dev); - //objcache_put(devfs_dev_cache, dev); devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_destroy_dev_worker -end:5-\n"); return 0; @@ -1114,15 +1233,51 @@ static int devfs_destroy_subnames_worker(char *name) { cdev_t dev, dev1; - //cdev_t found = NULL; size_t len = strlen(name); - TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) { + TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) { if (!strncmp(dev->si_name, name, len)) { - if (dev->si_name[len] != '\0') + if (dev->si_name[len] != '\0') { devfs_destroy_dev_worker(dev); + /* release_dev(dev); */ + } } - } + } + return 0; +} + +static int +devfs_clr_subnames_flag_worker(char *name, uint32_t flag) +{ + cdev_t dev, dev1; + size_t len = strlen(name); + + TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) { + if (!strncmp(dev->si_name, name, len)) { + if (dev->si_name[len] != '\0') { + dev->si_flags &= ~flag; + } + } + } + + return 0; +} + +static int +devfs_destroy_subnames_without_flag_worker(char *name, uint32_t flag) +{ + cdev_t dev, dev1; + size_t len = strlen(name); + + TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) { + if (!strncmp(dev->si_name, name, len)) { + if (dev->si_name[len] != '\0') { + if (!(dev->si_flags & flag)) { + devfs_destroy_dev_worker(dev); + } + } + } + } return 0; } @@ -1158,21 +1313,22 @@ devfs_destroy_dev_by_ops_worker(struct dev_ops *ops, int minor) cdev_t dev, dev1; KKASSERT(ops); - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_destroy_dev_by_ops_worker -1-\n"); - - TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) { - if (dev->si_ops == ops) { - if ((minor < 0) || (dev->si_uminor == minor)) { - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_destroy_dev_by_ops_worker -loop:2- -%s-\n", dev->si_name); - //TAILQ_REMOVE(&devfs_dev_list, dev, link); - devfs_unlink_dev(dev); - devfs_propagate_dev(dev, 0); - release_dev(dev); - //objcache_put(devfs_dev_cache, dev); - } + devfs_debug(DEVFS_DEBUG_DEBUG, + "devfs_destroy_dev_by_ops_worker -1-\n"); + + TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) { + if (dev->si_ops != ops) + continue; + if ((minor < 0) || (dev->si_uminor == minor)) { + devfs_debug(DEVFS_DEBUG_DEBUG, + "devfs_destroy_dev_by_ops_worker " + "-loop:2- -%s-\n", + dev->si_name); + devfs_destroy_dev_worker(dev); } - } - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_destroy_dev_by_ops_worker -end:3-\n"); + } + devfs_debug(DEVFS_DEBUG_DEBUG, + "devfs_destroy_dev_by_ops_worker -end:3-\n"); return 0; } @@ -1185,10 +1341,10 @@ devfs_chandler_add_worker(char *name, d_clone_t *nhandler) struct devfs_clone_handler *chandler = NULL; u_char len = strlen(name); - if (!len) + if (len == 0) return 1; - TAILQ_FOREACH(chandler, &devfs_chandler_list, link) { + TAILQ_FOREACH(chandler, &devfs_chandler_list, link) { if (chandler->namlen == len) { if (!memcmp(chandler->name, name, len)) { /* Clonable basename already exists */ @@ -1197,7 +1353,7 @@ devfs_chandler_add_worker(char *name, d_clone_t *nhandler) } } - chandler = kmalloc(sizeof(struct devfs_clone_handler), M_DEVFS, M_WAITOK); + chandler = kmalloc(sizeof(*chandler), M_DEVFS, M_WAITOK | M_ZERO); memcpy(chandler->name, name, len+1); chandler->namlen = len; chandler->nhandler = nhandler; @@ -1216,17 +1372,16 @@ devfs_chandler_del_worker(char *name) struct devfs_clone_handler *chandler, *chandler2; u_char len = strlen(name); - if (!len) + if (len == 0) return 1; - TAILQ_FOREACH_MUTABLE(chandler, &devfs_chandler_list, link, chandler2) { - if (chandler->namlen == len) { - if (!memcmp(chandler->name, name, len)) { - TAILQ_REMOVE(&devfs_chandler_list, chandler, link); - kfree(chandler, M_DEVFS); - //break; - } - } + TAILQ_FOREACH_MUTABLE(chandler, &devfs_chandler_list, link, chandler2) { + if (chandler->namlen != len) + continue; + if (memcmp(chandler->name, name, len)) + continue; + TAILQ_REMOVE(&devfs_chandler_list, chandler, link); + kfree(chandler, M_DEVFS); } return 0; @@ -1242,16 +1397,14 @@ devfs_find_device_by_name_worker(devfs_msg_t devfs_msg) { cdev_t dev, dev1; cdev_t found = NULL; - //devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_find_device_by_name: %s -1-\n", target); - TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) { - //devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_find_device_by_name -loop:2- -%s-\n", dev->si_name); - if (!strcmp(devfs_msg->m_name, dev->si_name)) { + TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) { + if (!strcmp(devfs_msg->mdv_name, dev->si_name)) { found = dev; break; } - } - devfs_msg->m_cdev = found; + } + devfs_msg->mdv_cdev = found; return 0; } @@ -1266,16 +1419,14 @@ devfs_find_device_by_udev_worker(devfs_msg_t devfs_msg) { cdev_t dev, dev1; cdev_t found = NULL; - //devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_find_device_by_name: %s -1-\n", target); - TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) { - //devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_find_device_by_name -loop:2- -%s-\n", dev->si_name); - if (((udev_t)dev->si_inode) == devfs_msg->m_udev) { + TAILQ_FOREACH_MUTABLE(dev, &devfs_dev_list, link, dev1) { + if (((udev_t)dev->si_inode) == devfs_msg->mdv_udev) { found = dev; break; } - } - devfs_msg->m_cdev = found; + } + devfs_msg->mdv_cdev = found; return 0; } @@ -1303,7 +1454,9 @@ devfs_make_alias_worker(struct devfs_alias *alias) TAILQ_INSERT_TAIL(&devfs_alias_list, alias, link); devfs_alias_propagate(alias); } else { - devfs_debug(DEVFS_DEBUG_DEBUG, "Warning: duplicate devfs_make_alias for %s\n", alias->name); + devfs_debug(DEVFS_DEBUG_DEBUG, + "Warning: duplicate devfs_make_alias for %s\n", + alias->name); kfree(alias, M_DEVFS); } @@ -1372,7 +1525,7 @@ devfs_alias_apply(struct devfs_node *node, struct devfs_alias *alias) if ((node->node_type == Proot) || (node->node_type == Pdir)) { devfs_debug(DEVFS_DEBUG_DEBUG, "This node is Pdir or Proot; has %d children\n", node->nchildren); if (node->nchildren > 2) { - TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node), link, node2) { + TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node), link, node2) { devfs_alias_apply(node1, alias); } } @@ -1410,12 +1563,9 @@ devfs_alias_create(char *name_orig, struct devfs_node *target) struct mount *mp = target->mp; struct devfs_node *parent = DEVFS_MNTDATA(mp)->root_node; struct devfs_node *linknode; - - //char *path = NULL; char *create_path = NULL; char *name, name_buf[PATH_MAX]; - //XXX: possibly put this in many worker functions (at least those with ext. API) KKASSERT((lockstatus(&devfs_lock, curthread)) == LK_EXCLUSIVE); devfs_resolve_name_path(name_orig, name_buf, &create_path, &name); @@ -1425,7 +1575,10 @@ devfs_alias_create(char *name_orig, struct devfs_node *target) if (devfs_find_device_node_by_name(parent, name)) { - devfs_debug(DEVFS_DEBUG_DEBUG, "Node already exists: %s (devfs_make_alias_worker)!\n", name); + devfs_debug(DEVFS_DEBUG_DEBUG, + "Node already exists: %s " + "(devfs_make_alias_worker)!\n", + name); return 1; } @@ -1524,7 +1677,8 @@ devfs_scan_callback_worker(devfs_scan_t *callback) * found and creation requested, creates the given directory. */ static struct devfs_node * -devfs_resolve_or_create_dir(struct devfs_node *parent, char *dir_name, size_t name_len, int create) +devfs_resolve_or_create_dir(struct devfs_node *parent, char *dir_name, + size_t name_len, int create) { struct devfs_node *node, *found = NULL; @@ -1615,12 +1769,15 @@ devfs_resolve_name_path(char *fullpath, char *buf, char **pathp, char **namep) } /* - * This function creates a new devfs node for a given device. It can + * This function creates a new devfs node for a given device. It can * handle a complete path as device name, and accordingly creates * the path and the final device node. + * + * The reference count on the passed dev remains unchanged. */ struct devfs_node * -devfs_create_device_node(struct devfs_node *root, cdev_t dev, char *dev_name, char *path_fmt, ...) +devfs_create_device_node(struct devfs_node *root, cdev_t dev, + char *dev_name, char *path_fmt, ...) { struct devfs_node *parent, *node = NULL; char *path = NULL; @@ -1631,9 +1788,6 @@ devfs_create_device_node(struct devfs_node *root, cdev_t dev, char *dev_name, ch char *create_path = NULL; char *names = "pqrsPQRS"; - - //devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_create_device_node : -%s- (%p)\n", dev->si_name, dev); - if (path_fmt != NULL) { path = kmalloc(PATH_MAX+1, M_DEVFS, M_WAITOK); @@ -1646,9 +1800,6 @@ devfs_create_device_node(struct devfs_node *root, cdev_t dev, char *dev_name, ch parent = devfs_resolve_or_create_path(root, path, 1); KKASSERT(parent); - if (dev) - reference_dev(dev); - devfs_resolve_name_path(((dev_name == NULL) && (dev))?(dev->si_name):(dev_name), name_buf, &create_path, &name); if (create_path) @@ -1690,8 +1841,6 @@ devfs_create_device_node(struct devfs_node *root, cdev_t dev, char *dev_name, ch out: if (path_fmt != NULL) kfree(path, M_DEVFS); - if (dev) - release_dev(dev); return node; } @@ -1743,24 +1892,18 @@ devfs_find_device_node_by_name(struct devfs_node *parent, char *target) } /* - * This function takes a cdev and destroys its devfs node in the - * given topology. + * This function takes a cdev and removes its devfs node in the + * given topology. The cdev remains intact. */ int devfs_destroy_device_node(struct devfs_node *root, cdev_t target) { struct devfs_node *node, *parent; - char *name, name_buf[PATH_MAX]; - //__va_list ap; - //int i; - char *create_path = NULL; KKASSERT(target); - - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_destroy_device_node\n"); memcpy(name_buf, target->si_name, strlen(target->si_name)+1); @@ -1777,10 +1920,11 @@ devfs_destroy_device_node(struct devfs_node *root, cdev_t target) return 1; devfs_debug(DEVFS_DEBUG_DEBUG, "->d_dir.d_name=%s\n", parent->d_dir.d_name); node = devfs_find_device_node_by_name(parent, name); - devfs_debug(DEVFS_DEBUG_DEBUG, "->d_dir.d_name=%s\n", (node)?(node->d_dir.d_name):"SHIT!"); - if (node) { + devfs_debug(DEVFS_DEBUG_DEBUG, + "->d_dir.d_name=%s\n", + ((node) ? (node->d_dir.d_name) : "SHIT!")); + if (node) devfs_gc(node); - } return 0; } @@ -1811,14 +1955,14 @@ devfs_propagate_dev(cdev_t dev, int attach) devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_propagate_dev -1-\n"); TAILQ_FOREACH(mnt, &devfs_mnt_list, link) { - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_propagate_dev -loop:2-\n"); + devfs_debug(DEVFS_DEBUG_DEBUG, + "devfs_propagate_dev -loop:2-\n"); if (attach) { /* Device is being attached */ - //devfs_create_device_node(struct devfs_node *root, struct devfs_dev *dev, char *dev_name, char *path_fmt, ...) - devfs_create_device_node(mnt->root_node, dev, NULL, NULL ); + devfs_create_device_node(mnt->root_node, dev, + NULL, NULL ); } else { /* Device is being detached */ - //devfs_destroy_device_node(struct devfs_node *root, struct devfs_dev *target) devfs_alias_remove(dev); devfs_destroy_device_node(mnt->root_node, dev); } @@ -1922,6 +2066,8 @@ devfs_tracer_add_orphan(struct devfs_node *node) orphan = kmalloc(sizeof(struct devfs_orphan), M_DEVFS, M_WAITOK); orphan->node = node; + KKASSERT((node->flags & DEVFS_ORPHANED) == 0); + node->flags |= DEVFS_ORPHANED; TAILQ_INSERT_TAIL(DEVFS_ORPHANLIST(node->mp), orphan, link); } @@ -1937,6 +2083,7 @@ devfs_tracer_del_orphan(struct devfs_node *node) TAILQ_FOREACH(orphan, DEVFS_ORPHANLIST(node->mp), link) { if (orphan->node == node) { + node->flags &= ~DEVFS_ORPHANED; TAILQ_REMOVE(DEVFS_ORPHANLIST(node->mp), orphan, link); kfree(orphan, M_DEVFS); break; @@ -1958,9 +2105,9 @@ devfs_tracer_orphan_count(struct mount *mp, int cleanup) TAILQ_FOREACH_MUTABLE(orphan, DEVFS_ORPHANLIST(mp), link, orphan2) { count++; if (cleanup) { - orphan->node->flags |= DEVFS_NO_TRACE; - devfs_freep(orphan->node); TAILQ_REMOVE(DEVFS_ORPHANLIST(mp), orphan, link); + orphan->node->flags &= ~DEVFS_ORPHANED; + devfs_freep(orphan->node); kfree(orphan, M_DEVFS); } } @@ -1991,13 +2138,12 @@ devfs_fetch_ino(void) cdev_t devfs_new_cdev(struct dev_ops *ops, int minor) { -// cdev_t dev = objcache_get(devfs_dev_cache, M_WAITOK); -// memset(dev, 0, sizeof(struct cdev)); - cdev_t dev = sysref_alloc(&cdev_sysref_class); sysref_activate(&dev->si_sysref); reference_dev(dev); - devfs_debug(DEVFS_DEBUG_DEBUG, "new_cdev: clearing first %d bytes\n", offsetof(struct cdev, si_sysref)); + devfs_debug(DEVFS_DEBUG_DEBUG, + "new_cdev: clearing first %d bytes\n", + offsetof(struct cdev, si_sysref)); memset(dev, 0, offsetof(struct cdev, si_sysref)); dev->si_uid = 0; @@ -2017,8 +2163,8 @@ devfs_new_cdev(struct dev_ops *ops, int minor) return dev; } - -static void devfs_cdev_terminate(cdev_t dev) +static void +devfs_cdev_terminate(cdev_t dev) { int locked = 0; @@ -2041,23 +2187,13 @@ static void devfs_cdev_terminate(cdev_t dev) sysref_put(&dev->si_sysref); } -/* - * Frees a given cdev - */ -int -devfs_destroy_cdev(cdev_t dev) -{ - release_dev(dev); - //objcache_put(devfs_dev_cache, dev); - return 0; -} - /* * Links a given cdev into the dev list. */ int devfs_link_dev(cdev_t dev) { + KKASSERT((dev->si_flags & SI_DEVFS_LINKED) == 0); dev->si_flags |= SI_DEVFS_LINKED; TAILQ_INSERT_TAIL(&devfs_dev_list, dev, link); @@ -2065,17 +2201,20 @@ devfs_link_dev(cdev_t dev) } /* - * Removes a given cdev from the dev list. + * Removes a given cdev from the dev list. The caller is responsible for + * releasing the reference on the device associated with the linkage. + * + * Returns EALREADY if the dev has already been unlinked. */ -int +static int devfs_unlink_dev(cdev_t dev) { if ((dev->si_flags & SI_DEVFS_LINKED)) { TAILQ_REMOVE(&devfs_dev_list, dev, link); dev->si_flags &= ~SI_DEVFS_LINKED; + return (0); } - - return 0; + return (EALREADY); } void diff --git a/sys/vfs/devfs/devfs_helper.c b/sys/vfs/devfs/devfs_helper.c index 2d635c0065..48eac48e98 100644 --- a/sys/vfs/devfs/devfs_helper.c +++ b/sys/vfs/devfs/devfs_helper.c @@ -120,7 +120,7 @@ devfs_clone_bitmap_init(struct devfs_bitmap *bitmap) void devfs_clone_bitmap_uninit(struct devfs_bitmap *bitmap) { - kfree(bitmap, M_DEVFS); + kfree(bitmap->bitmap, M_DEVFS); } diff --git a/sys/vfs/devfs/devfs_vfsops.c b/sys/vfs/devfs/devfs_vfsops.c index 1141a06057..9bdd43ab95 100644 --- a/sys/vfs/devfs/devfs_vfsops.c +++ b/sys/vfs/devfs/devfs_vfsops.c @@ -61,6 +61,7 @@ int devfs_root(struct mount *mp, struct vnode **vpp); static int devfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) { + struct devfs_mnt_data *mnt; size_t size; devfs_debug(DEVFS_DEBUG_DEBUG, "(vfsops) devfs_mount() called!\n"); @@ -71,7 +72,7 @@ devfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) mp->mnt_flag |= MNT_LOCAL; mp->mnt_kern_flag |= MNTK_NOSTKMNT; - mp->mnt_data = 0; + mp->mnt_data = NULL; vfs_getnewfsid(mp); size = sizeof("devfs") - 1; @@ -80,22 +81,24 @@ devfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) devfs_statfs(mp, &mp->mnt_stat, cred); //XXX: save other mount info passed from userland or so. - mp->mnt_data = kmalloc(sizeof(struct devfs_mnt_data), M_DEVFS, M_WAITOK); + mnt = kmalloc(sizeof(*mnt), M_DEVFS, M_WAITOK | M_ZERO); lockmgr(&devfs_lock, LK_EXCLUSIVE); - DEVFS_MNTDATA(mp)->jailed = jailed(cred); - DEVFS_MNTDATA(mp)->mntonnamelen = strlen(mp->mnt_stat.f_mntonname); - DEVFS_MNTDATA(mp)->leak_count = 0; - DEVFS_MNTDATA(mp)->root_node = devfs_allocp(Proot, "", NULL, mp, NULL); - KKASSERT(DEVFS_MNTDATA(mp)->root_node); - TAILQ_INIT(DEVFS_ORPHANLIST(mp)); + mp->mnt_data = (qaddr_t)mnt; + mnt->jailed = jailed(cred); + mnt->leak_count = 0; + mnt->mp = mp; + TAILQ_INIT(&mnt->orphan_list); + mnt->mntonnamelen = strlen(mp->mnt_stat.f_mntonname); + mnt->root_node = devfs_allocp(Proot, "", NULL, mp, NULL); + KKASSERT(mnt->root_node); lockmgr(&devfs_lock, LK_RELEASE); vfs_add_vnodeops(mp, &devfs_vnode_norm_vops, &mp->mnt_vn_norm_ops); vfs_add_vnodeops(mp, &devfs_vnode_dev_vops, &mp->mnt_vn_spec_ops); devfs_debug(DEVFS_DEBUG_DEBUG, "calling devfs_mount_add\n"); - devfs_mount_add(DEVFS_MNTDATA(mp)); + devfs_mount_add(mnt); return (0); } @@ -119,10 +122,15 @@ devfs_unmount(struct mount *mp, int mntflags) if (error) return (error); - devfs_debug(DEVFS_DEBUG_DEBUG, "There were %d devfs_node orphans left\n", devfs_tracer_orphan_count(mp, 1)); - devfs_debug(DEVFS_DEBUG_DEBUG, "There are %d devfs_node orphans left\n", devfs_tracer_orphan_count(mp, 0)); + devfs_debug(DEVFS_DEBUG_SHOW, + "There were %d devfs_node orphans left\n", + devfs_tracer_orphan_count(mp, 1)); + devfs_debug(DEVFS_DEBUG_SHOW, + "There are %d devfs_node orphans left\n", + devfs_tracer_orphan_count(mp, 0)); devfs_mount_del(DEVFS_MNTDATA(mp)); kfree(mp->mnt_data, M_DEVFS); + mp->mnt_data = NULL; return (0); } diff --git a/sys/vfs/devfs/devfs_vnops.c b/sys/vfs/devfs/devfs_vnops.c index 77ca18ad41..7439b59847 100644 --- a/sys/vfs/devfs/devfs_vnops.c +++ b/sys/vfs/devfs/devfs_vnops.c @@ -219,16 +219,10 @@ devfs_access(struct vop_access_args *ap) static int devfs_inactive(struct vop_inactive_args *ap) { - //devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_inactive() called!\n"); - - /* Check if the devfs_node is not linked anymore into the topology. - * If this is the case, we suggest that the vnode is recycled. */ - if (DEVFS_NODE(ap->a_vp)) { - if ((DEVFS_NODE(ap->a_vp)->flags & DEVFS_NODE_LINKED) == 0) { - vrecycle(ap->a_vp); - } - } + struct devfs_node *node = DEVFS_NODE(ap->a_vp); + if (node == NULL || (node->flags & DEVFS_NODE_LINKED) == 0) + vrecycle(ap->a_vp); return 0; } @@ -287,6 +281,11 @@ devfs_readdir(struct vop_readdir_args *ap) if ((error = vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY)) != 0) return (error); + if (DEVFS_NODE(ap->a_vp) == NULL) + return ENOENT; + + lockmgr(&devfs_lock, LK_EXCLUSIVE); + saveoff = ap->a_uio->uio_offset; if (ap->a_ncookies) { @@ -367,6 +366,7 @@ devfs_readdir(struct vop_readdir_args *ap) } done: + lockmgr(&devfs_lock, LK_RELEASE); vn_unlock(ap->a_vp); ap->a_uio->uio_offset = saveoff; @@ -402,6 +402,9 @@ devfs_nresolve(struct vop_nresolve_args *ap) ncp = ap->a_nch->ncp; len = ncp->nc_nlen; + if (DEVFS_NODE(ap->a_dvp) == NULL) + return ENOENT; + lockmgr(&devfs_lock, LK_EXCLUSIVE); if ((DEVFS_NODE(ap->a_dvp)->node_type != Proot) && @@ -437,10 +440,12 @@ search: //devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_nresolve -3- %c%c%c\n", ncp->nc_name[0], ncp->nc_name[1], ncp->nc_name[2]); if (vp == NULL) { devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_nresolve vp==NULL \n"); +#if 0 /* XXX: len is int, devfs_clone expects size_t*, not int* */ if ((!hidden) && (!devfs_clone(ncp->nc_name, &len, NULL, 0, ap->a_cred))) { goto search; } +#endif devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_nresolve -4- \n"); error = ENOENT; cache_setvp(ap->a_nch, NULL); @@ -486,7 +491,11 @@ devfs_getattr(struct vop_getattr_args *ap) struct devfs_node *node = DEVFS_NODE(ap->a_vp); int error = 0; + if (node == NULL) + return ENOENT; + devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_getattr() called for %s!\n", DEVFS_NODE(ap->a_vp)->d_dir.d_name); + lockmgr(&devfs_lock, LK_EXCLUSIVE); /* start by zeroing out the attributes */ VATTR_NULL(vap); @@ -520,7 +529,6 @@ devfs_getattr(struct vop_getattr_args *ap) (DEVFS_NODE(ap->a_vp)->d_dev)) { devfs_debug(DEVFS_DEBUG_DEBUG, "getattr: dev is: %p\n", DEVFS_NODE(ap->a_vp)->d_dev); reference_dev(DEVFS_NODE(ap->a_vp)->d_dev); - vap->va_fsid = dev2udev(DEVFS_NODE(ap->a_vp)->d_dev); vap->va_rminor = DEVFS_NODE(ap->a_vp)->d_dev->si_uminor; release_dev(DEVFS_NODE(ap->a_vp)->d_dev); } @@ -530,6 +538,7 @@ devfs_getattr(struct vop_getattr_args *ap) vap->va_size = DEVFS_NODE(ap->a_vp)->symlink_namelen; } nanotime(&node->atime); + lockmgr(&devfs_lock, LK_RELEASE); return (error); //XXX: set error usefully } @@ -541,12 +550,15 @@ devfs_setattr(struct vop_setattr_args *ap) struct vattr *vap; int error = 0; + node = DEVFS_NODE(ap->a_vp); + + if (node == NULL) + return ENOENT; devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_setattr() called!\n"); lockmgr(&devfs_lock, LK_EXCLUSIVE); vap = ap->a_vap; - node = DEVFS_NODE(ap->a_vp); if (vap->va_uid != (uid_t)VNOVAL) { if ((ap->a_cred->cr_uid != node->uid) && @@ -594,10 +606,18 @@ static int devfs_readlink(struct vop_readlink_args *ap) { struct devfs_node *node = DEVFS_NODE(ap->a_vp); + int ret; + + if (node == NULL) + return ENOENT; devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_readlink() called!\n"); - return (uiomove(node->symlink_name, node->symlink_namelen, ap->a_uio)); + lockmgr(&devfs_lock, LK_EXCLUSIVE); + ret = uiomove(node->symlink_name, node->symlink_namelen, ap->a_uio); + lockmgr(&devfs_lock, LK_RELEASE); + + return ret; } @@ -622,6 +642,9 @@ devfs_nsymlink(struct vop_nsymlink_args *ap) ap->a_vap->va_type = VLNK; + if (DEVFS_NODE(ap->a_dvp) == NULL) + return ENOENT; + if ((DEVFS_NODE(ap->a_dvp)->node_type != Proot) && (DEVFS_NODE(ap->a_dvp)->node_type != Pdir)) { devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_nsymlink: ap->a_dvp is not a dir!!!\n"); @@ -661,6 +684,9 @@ devfs_nremove(struct vop_nremove_args *ap) ncp = ap->a_nch->ncp; + if (DEVFS_NODE(ap->a_dvp) == NULL) + return ENOENT; + lockmgr(&devfs_lock, LK_EXCLUSIVE); if ((DEVFS_NODE(ap->a_dvp)->node_type != Proot) && @@ -704,6 +730,7 @@ static int devfs_spec_open(struct vop_open_args *ap) { struct vnode *vp = ap->a_vp; + struct vnode *orig_vp = NULL; cdev_t dev, ndev = NULL; struct devfs_node *node = NULL; int error = 0; @@ -729,20 +756,19 @@ devfs_spec_open(struct vop_open_args *ap) devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_spec_open: -1.2- |%s|\n", ndev->si_name); dev = ndev; - reference_dev(dev); devfs_link_dev(dev); node = devfs_create_device_node(DEVFS_MNTDATA(vp->v_mount)->root_node, dev, NULL, NULL); - //node = devfs_allocp(Pdev, ndev->si_name, DEVFS_NODE(vp)->parent, vp->v_mount, dev); devfs_debug(DEVFS_DEBUG_DEBUG, "parent here is: %s, node is: |%s|\n", (DEVFS_NODE(vp)->parent->node_type == Proot)?"ROOT!":DEVFS_NODE(vp)->parent->d_dir.d_name, node->d_dir.d_name); devfs_debug(DEVFS_DEBUG_DEBUG, "test: %s\n", ((struct devfs_node *)(TAILQ_LAST(DEVFS_DENODE_HEAD(DEVFS_NODE(vp)->parent), devfs_node_head)))->d_dir.d_name); - node->flags |= DEVFS_CLONED; + /* + * orig_vp is set to the original vp if we cloned. + */ + /* node->flags |= DEVFS_CLONED; */ devfs_allocv(&vp, node); - + orig_vp = ap->a_vp; ap->a_vp = vp; - - //XXX: propagate to other devfs mounts? } lockmgr(&devfs_lock, LK_RELEASE); } @@ -761,10 +787,17 @@ devfs_spec_open(struct vop_open_args *ap) error = dev_dopen(dev, ap->a_mode, S_IFCHR, ap->a_cred); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + /* + * Clean up any cloned vp if we error out. + */ if (error) { - devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_spec_open() error out: %x\n", error); - if (DEVFS_NODE(vp) && ((DEVFS_NODE(vp)->flags & DEVFS_CLONED) == DEVFS_CLONED)) + devfs_debug(DEVFS_DEBUG_DEBUG, + "devfs_spec_open() error out: %x\n", error); + if (orig_vp) { vput(vp); + ap->a_vp = orig_vp; + /* orig_vp = NULL; */ + } return error; } @@ -791,7 +824,7 @@ devfs_spec_open(struct vop_open_args *ap) if (DEVFS_NODE(vp)) nanotime(&DEVFS_NODE(vp)->atime); - if (DEVFS_NODE(vp) && ((DEVFS_NODE(vp)->flags & DEVFS_CLONED) == DEVFS_CLONED)) + if (orig_vp) vn_unlock(vp); /* Ugly pty magic, to make pty devices appear once they are opened */ @@ -859,14 +892,13 @@ devfs_spec_close(struct vop_close_args *ap) vn_unlock(vp); } error = dev_dclose(dev, ap->a_fflag, S_IFCHR); +#if 0 if (DEVFS_NODE(vp) && (DEVFS_NODE(vp)->flags & DEVFS_CLONED) == DEVFS_CLONED) { devfs_debug(DEVFS_DEBUG_DEBUG, "devfs_spec_close: last of the cloned ones, so delete node %s\n", dev->si_name); devfs_unlinkp(DEVFS_NODE(vp)); devfs_freep(DEVFS_NODE(vp)); - devfs_unlink_dev(dev); - release_dev(dev); - devfs_destroy_cdev(dev); } +#endif /* Ugly pty magic, to make pty devices disappear again once they are closed */ if (DEVFS_NODE(vp) && ((DEVFS_NODE(vp)->flags & DEVFS_PTY) == DEVFS_PTY)) DEVFS_NODE(vp)->flags |= DEVFS_INVISIBLE; @@ -1128,7 +1160,7 @@ devfs_specf_stat(struct file *fp, struct stat *sb, struct ucred *cred) sb->st_nlink = vap->va_nlink; sb->st_uid = vap->va_uid; sb->st_gid = vap->va_gid; - sb->st_rdev = 0; + sb->st_rdev = dev2udev(DEVFS_NODE(vp)->d_dev); sb->st_size = vap->va_size; sb->st_atimespec = vap->va_atime; sb->st_mtimespec = vap->va_mtime;