static int devfs_run;
static ino_t devfs_fetch_ino(void);
-static int devfs_gc_dirs(struct devfs_node *);
-static int devfs_gc_links(struct devfs_node *, struct devfs_node *, size_t);
static int devfs_create_all_dev_worker(struct devfs_node *);
static int devfs_create_dev_worker(cdev_t, uid_t, gid_t, int);
static int devfs_destroy_dev_worker(cdev_t);
static int devfs_find_device_by_name_worker(devfs_msg_t);
static int devfs_find_device_by_udev_worker(devfs_msg_t);
-static struct vnode *devfs_inode_to_vnode_worker(struct devfs_node *, ino_t);
-
static int devfs_apply_reset_rules_caller(char *, int);
-static int devfs_apply_reset_rules_worker(struct devfs_node *, int);
static int devfs_scan_callback_worker(devfs_scan_t *);
static int devfs_clr_subnames_flag_worker(char *, uint32_t);
static int devfs_destroy_subnames_without_flag_worker(char *, uint32_t);
+static void *devfs_reaperp_callback(struct devfs_node *, void *);
+static void *devfs_gc_dirs_callback(struct devfs_node *, void *);
+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 *);
+
/*
* devfs_debug() is a SYSCTL and TUNABLE controlled debug output function
* using kvprintf
node->parent = parent;
/* Apply rules */
- devfs_rule_check_apply(node);
+ devfs_rule_check_apply(node, NULL);
/* Initialize *time members */
nanotime(&node->atime);
return 0;
}
-/*
- * 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)
+void *
+devfs_iterate_topology(struct devfs_node *node,
+ devfs_iterate_callback_t *callback, void *arg1)
{
struct devfs_node *node1, *node2;
+ void *ret = NULL;
if ((node->node_type == Proot) || (node->node_type == Pdir)) {
if (node->nchildren > 2) {
TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node),
link, node2) {
- devfs_reaperp(node1);
+ if ((ret = devfs_iterate_topology(node1, callback, arg1)))
+ return ret;
}
}
}
- devfs_unlinkp(node);
- devfs_freep(node);
- return 0;
+ ret = callback(node, arg1);
+ return ret;
}
/*
- * 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_reaperp() is a recursive function that iterates through all the
+ * topology, unlinking and freeing all devfs nodes.
*/
-int
-devfs_gc(struct devfs_node *node)
+static void *
+devfs_reaperp_callback(struct devfs_node *node, void *unused)
{
- struct devfs_node *root_node = DEVFS_MNTDATA(node->mp)->root_node;
-
- devfs_gc_links(root_node, node, node->nlinks);
devfs_unlinkp(node);
- devfs_gc_dirs(root_node);
-
devfs_freep(node);
- return 0;
+ return NULL;
}
-/*
- * devfs_gc_dirs() is a helper function for devfs_gc, unlinking and freeing
- * empty directories.
- */
-static int
-devfs_gc_dirs(struct devfs_node *node)
+static void *
+devfs_gc_dirs_callback(struct devfs_node *node, void *unused)
{
- struct devfs_node *node1, *node2;
-
- if ((node->node_type == Proot) || (node->node_type == Pdir)) {
- if (node->nchildren > 2) {
- TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node),
- link, node2) {
- devfs_gc_dirs(node1);
- }
- }
-
+ if (node->node_type == Pdir) {
if (node->nchildren == 2) {
devfs_unlinkp(node);
devfs_freep(node);
}
}
- return 0;
+ return NULL;
+}
+
+static void *
+devfs_gc_links_callback(struct devfs_node *node, struct devfs_node *target)
+{
+ if ((node->node_type == Plink) && (node->link_target == target)) {
+ devfs_unlinkp(node);
+ devfs_freep(node);
+ }
+
+ return NULL;
}
/*
- * devfs_gc_links() is a helper function for devfs_gc, unlinking and freeing
- * eauto-linked nodes linking 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.
*/
-static int
-devfs_gc_links(struct devfs_node *node, struct devfs_node *target,
- size_t nlinks)
+int
+devfs_gc(struct devfs_node *node)
{
- struct devfs_node *node1, *node2;
+ struct devfs_node *root_node = DEVFS_MNTDATA(node->mp)->root_node;
- if (nlinks > 0) {
- if ((node->node_type == Proot) || (node->node_type == Pdir)) {
- if (node->nchildren > 2) {
- TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node),
- link, node2) {
- nlinks = devfs_gc_links(node1, target, nlinks);
- }
- }
- } else if (node->link_target == target) {
- nlinks--;
- devfs_unlinkp(node);
- devfs_freep(node);
- }
- }
+ if (node->nlinks > 0)
+ devfs_iterate_topology(root_node,
+ (devfs_iterate_callback_t *)devfs_gc_links_callback, node);
- KKASSERT(nlinks >= 0);
+ devfs_unlinkp(node);
+ devfs_iterate_topology(root_node,
+ (devfs_iterate_callback_t *)devfs_gc_dirs_callback, NULL);
+
+ devfs_freep(node);
- return nlinks;
+ return 0;
}
/*
case DEVFS_MOUNT_DEL:
mnt = msg->mdv_mnt;
TAILQ_REMOVE(&devfs_mnt_list, mnt, link);
- devfs_reaperp(mnt->root_node);
+ devfs_iterate_topology(mnt->root_node, devfs_reaperp_callback,
+ NULL);
if (mnt->leak_count) {
devfs_debug(DEVFS_DEBUG_SHOW,
"Leaked %d devfs_node elements!\n",
msg->mdv_flags.flag);
break;
case DEVFS_INODE_TO_VNODE:
- msg->mdv_ino.vp = devfs_inode_to_vnode_worker(
- DEVFS_MNTDATA(msg->mdv_ino.mp)->root_node,
- msg->mdv_ino.ino);
+ msg->mdv_ino.vp = devfs_iterate_topology(
+ DEVFS_MNTDATA(msg->mdv_ino.mp)->root_node,
+ (devfs_iterate_callback_t *)devfs_inode_to_vnode_worker_callback,
+ &msg->mdv_ino.ino);
break;
case DEVFS_TERMINATE_CORE:
devfs_run = 0;
if (mountto[0] == '*') {
TAILQ_FOREACH(mnt, &devfs_mnt_list, link) {
- devfs_apply_reset_rules_worker(mnt->root_node, apply);
+ devfs_iterate_topology(mnt->root_node,
+ (apply)?(devfs_rule_check_apply):(devfs_rule_reset_node),
+ NULL);
}
} else {
TAILQ_FOREACH(mnt, &devfs_mnt_list, link) {
continue;
if (!memcmp(mnt->mp->mnt_stat.f_mntonname, mountto, len)) {
- devfs_apply_reset_rules_worker(mnt->root_node, apply);
+ devfs_iterate_topology(mnt->root_node,
+ (apply)?(devfs_rule_check_apply):(devfs_rule_reset_node),
+ NULL);
break;
}
}
}
/*
- * This worker function applies or resets, depending on the arguments, a rule
- * to the whole given topology. *RECURSIVE*
- */
-static int
-devfs_apply_reset_rules_worker(struct devfs_node *node, int apply)
-{
- struct devfs_node *node1, *node2;
-
- if ((node->node_type == Proot) || (node->node_type == Pdir)) {
- if (node->nchildren > 2) {
- TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node), link, node2) {
- devfs_apply_reset_rules_worker(node1, apply);
- }
- }
- }
-
- if (apply)
- devfs_rule_check_apply(node);
- else
- devfs_rule_reset_node(node);
-
- return 0;
-}
-
-
-/*
* This function calls a given callback function for
* every dev node in the devfs dev list.
*/
return 0;
}
-
/*
* This function tries to resolve a given directory, or if not
* found and creation requested, creates the given directory.
* This function finds a given device node in the topology with a given
* cdev.
*/
-struct devfs_node *
-devfs_find_device_node(struct devfs_node *node, cdev_t target)
+void *
+devfs_find_device_node_callback(struct devfs_node *node, cdev_t target)
{
- struct devfs_node *node1, *node2, *found = NULL;
-
- if ((node->node_type == Proot) || (node->node_type == Pdir)) {
- if (node->nchildren > 2) {
- TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node), link, node2) {
- if ((found = devfs_find_device_node(node1, target)))
- return found;
- }
- }
- } else if (node->node_type == Pdev) {
- if (node->d_dev == target)
- return node;
+ if ((node->node_type == Pdev) && (node->d_dev == target)) {
+ return node;
}
return NULL;
}
/*
- * This function finds a device node in the topology by its
+ * This function finds a device node in the given parent directory by its
* name and returns it.
*/
struct devfs_node *
return found;
}
-static struct vnode*
-devfs_inode_to_vnode_worker(struct devfs_node *node, ino_t target)
+static void *
+devfs_inode_to_vnode_worker_callback(struct devfs_node *node, ino_t *inop)
{
- struct devfs_node *node1, *node2;
- struct vnode* vp;
-
- if ((node->node_type == Proot) || (node->node_type == Pdir)) {
- if (node->nchildren > 2) {
- TAILQ_FOREACH_MUTABLE(node1, DEVFS_DENODE_HEAD(node), link, node2) {
- if ((vp = devfs_inode_to_vnode_worker(node1, target)))
- return vp;
- }
- }
- }
+ struct vnode *vp = NULL;
+ ino_t target = *inop;
if (node->d_dir.d_ino == target) {
if (node->v_node) {
devfs_allocv(&vp, node);
vn_unlock(vp);
}
- return vp;
}
- return NULL;
+ return vp;
}
/*