📄 dir.c
字号:
* This fakes mkdir(2) on a default_groups[] entry. It * creates a dentry, attachs it, and then does fixup * on the sd->s_type. * * We could, perhaps, tweak our parent's ->mkdir for a minute and * try using vfs_mkdir. Just a thought. */static int create_default_group(struct config_group *parent_group, struct config_group *group){ int ret; struct qstr name; struct configfs_dirent *sd; /* We trust the caller holds a reference to parent */ struct dentry *child, *parent = parent_group->cg_item.ci_dentry; if (!group->cg_item.ci_name) group->cg_item.ci_name = group->cg_item.ci_namebuf; name.name = group->cg_item.ci_name; name.len = strlen(name.name); name.hash = full_name_hash(name.name, name.len); ret = -ENOMEM; child = d_alloc(parent, &name); if (child) { d_add(child, NULL); ret = configfs_attach_group(&parent_group->cg_item, &group->cg_item, child); if (!ret) { sd = child->d_fsdata; sd->s_type |= CONFIGFS_USET_DEFAULT; } else { d_delete(child); dput(child); } } return ret;}static int populate_groups(struct config_group *group){ struct config_group *new_group; struct dentry *dentry = group->cg_item.ci_dentry; int ret = 0; int i; if (group->default_groups) { /* * FYI, we're faking mkdir here * I'm not sure we need this semaphore, as we're called * from our parent's mkdir. That holds our parent's * i_mutex, so afaik lookup cannot continue through our * parent to find us, let alone mess with our tree. * That said, taking our i_mutex is closer to mkdir * emulation, and shouldn't hurt. */ mutex_lock(&dentry->d_inode->i_mutex); for (i = 0; group->default_groups[i]; i++) { new_group = group->default_groups[i]; ret = create_default_group(group, new_group); if (ret) break; } mutex_unlock(&dentry->d_inode->i_mutex); } if (ret) detach_groups(group); return ret;}/* * All of link_obj/unlink_obj/link_group/unlink_group require that * subsys->su_mutex is held. */static void unlink_obj(struct config_item *item){ struct config_group *group; group = item->ci_group; if (group) { list_del_init(&item->ci_entry); item->ci_group = NULL; item->ci_parent = NULL; /* Drop the reference for ci_entry */ config_item_put(item); /* Drop the reference for ci_parent */ config_group_put(group); }}static void link_obj(struct config_item *parent_item, struct config_item *item){ /* * Parent seems redundant with group, but it makes certain * traversals much nicer. */ item->ci_parent = parent_item; /* * We hold a reference on the parent for the child's ci_parent * link. */ item->ci_group = config_group_get(to_config_group(parent_item)); list_add_tail(&item->ci_entry, &item->ci_group->cg_children); /* * We hold a reference on the child for ci_entry on the parent's * cg_children */ config_item_get(item);}static void unlink_group(struct config_group *group){ int i; struct config_group *new_group; if (group->default_groups) { for (i = 0; group->default_groups[i]; i++) { new_group = group->default_groups[i]; unlink_group(new_group); } } group->cg_subsys = NULL; unlink_obj(&group->cg_item);}static void link_group(struct config_group *parent_group, struct config_group *group){ int i; struct config_group *new_group; struct configfs_subsystem *subsys = NULL; /* gcc is a turd */ link_obj(&parent_group->cg_item, &group->cg_item); if (parent_group->cg_subsys) subsys = parent_group->cg_subsys; else if (configfs_is_root(&parent_group->cg_item)) subsys = to_configfs_subsystem(group); else BUG(); group->cg_subsys = subsys; if (group->default_groups) { for (i = 0; group->default_groups[i]; i++) { new_group = group->default_groups[i]; link_group(group, new_group); } }}/* * The goal is that configfs_attach_item() (and * configfs_attach_group()) can be called from either the VFS or this * module. That is, they assume that the items have been created, * the dentry allocated, and the dcache is all ready to go. * * If they fail, they must clean up after themselves as if they * had never been called. The caller (VFS or local function) will * handle cleaning up the dcache bits. * * configfs_detach_group() and configfs_detach_item() behave similarly on * the way out. They assume that the proper semaphores are held, they * clean up the configfs items, and they expect their callers will * handle the dcache bits. */static int configfs_attach_item(struct config_item *parent_item, struct config_item *item, struct dentry *dentry){ int ret; ret = configfs_create_dir(item, dentry); if (!ret) { ret = populate_attrs(item); if (ret) { configfs_remove_dir(item); d_delete(dentry); } } return ret;}static void configfs_detach_item(struct config_item *item){ detach_attrs(item); configfs_remove_dir(item);}static int configfs_attach_group(struct config_item *parent_item, struct config_item *item, struct dentry *dentry){ int ret; struct configfs_dirent *sd; ret = configfs_attach_item(parent_item, item, dentry); if (!ret) { sd = dentry->d_fsdata; sd->s_type |= CONFIGFS_USET_DIR; ret = populate_groups(to_config_group(item)); if (ret) { configfs_detach_item(item); d_delete(dentry); } } return ret;}static void configfs_detach_group(struct config_item *item){ detach_groups(to_config_group(item)); configfs_detach_item(item);}/* * After the item has been detached from the filesystem view, we are * ready to tear it out of the hierarchy. Notify the client before * we do that so they can perform any cleanup that requires * navigating the hierarchy. A client does not need to provide this * callback. The subsystem semaphore MUST be held by the caller, and * references must be valid for both items. It also assumes the * caller has validated ci_type. */static void client_disconnect_notify(struct config_item *parent_item, struct config_item *item){ struct config_item_type *type; type = parent_item->ci_type; BUG_ON(!type); if (type->ct_group_ops && type->ct_group_ops->disconnect_notify) type->ct_group_ops->disconnect_notify(to_config_group(parent_item), item);}/* * Drop the initial reference from make_item()/make_group() * This function assumes that reference is held on item * and that item holds a valid reference to the parent. Also, it * assumes the caller has validated ci_type. */static void client_drop_item(struct config_item *parent_item, struct config_item *item){ struct config_item_type *type; type = parent_item->ci_type; BUG_ON(!type); /* * If ->drop_item() exists, it is responsible for the * config_item_put(). */ if (type->ct_group_ops && type->ct_group_ops->drop_item) type->ct_group_ops->drop_item(to_config_group(parent_item), item); else config_item_put(item);}#ifdef DEBUGstatic void configfs_dump_one(struct configfs_dirent *sd, int level){ printk(KERN_INFO "%*s\"%s\":\n", level, " ", configfs_get_name(sd));#define type_print(_type) if (sd->s_type & _type) printk(KERN_INFO "%*s %s\n", level, " ", #_type); type_print(CONFIGFS_ROOT); type_print(CONFIGFS_DIR); type_print(CONFIGFS_ITEM_ATTR); type_print(CONFIGFS_ITEM_LINK); type_print(CONFIGFS_USET_DIR); type_print(CONFIGFS_USET_DEFAULT); type_print(CONFIGFS_USET_DROPPING);#undef type_print}static int configfs_dump(struct configfs_dirent *sd, int level){ struct configfs_dirent *child_sd; int ret = 0; configfs_dump_one(sd, level); if (!(sd->s_type & (CONFIGFS_DIR|CONFIGFS_ROOT))) return 0; list_for_each_entry(child_sd, &sd->s_children, s_sibling) { ret = configfs_dump(child_sd, level + 2); if (ret) break; } return ret;}#endif/* * configfs_depend_item() and configfs_undepend_item() * * WARNING: Do not call these from a configfs callback! * * This describes these functions and their helpers. * * Allow another kernel system to depend on a config_item. If this * happens, the item cannot go away until the dependant can live without * it. The idea is to give client modules as simple an interface as * possible. When a system asks them to depend on an item, they just * call configfs_depend_item(). If the item is live and the client * driver is in good shape, we'll happily do the work for them. * * Why is the locking complex? Because configfs uses the VFS to handle * all locking, but this function is called outside the normal * VFS->configfs path. So it must take VFS locks to prevent the * VFS->configfs stuff (configfs_mkdir(), configfs_rmdir(), etc). This is * why you can't call these functions underneath configfs callbacks. * * Note, btw, that this can be called at *any* time, even when a configfs * subsystem isn't registered, or when configfs is loading or unloading. * Just like configfs_register_subsystem(). So we take the same * precautions. We pin the filesystem. We lock each i_mutex _in_order_ * on our way down the tree. If we can find the target item in the * configfs tree, it must be part of the subsystem tree as well, so we * do not need the subsystem semaphore. Holding the i_mutex chain locks * out mkdir() and rmdir(), who might be racing us. *//* * configfs_depend_prep() * * Only subdirectories count here. Files (CONFIGFS_NOT_PINNED) are * attributes. This is similar but not the same to configfs_detach_prep(). * Note that configfs_detach_prep() expects the parent to be locked when it * is called, but we lock the parent *inside* configfs_depend_prep(). We * do that so we can unlock it if we find nothing. * * Here we do a depth-first search of the dentry hierarchy looking for * our object. We take i_mutex on each step of the way down. IT IS * ESSENTIAL THAT i_mutex LOCKING IS ORDERED. If we come back up a branch, * we'll drop the i_mutex. * * If the target is not found, -ENOENT is bubbled up and we have released * all locks. If the target was found, the locks will be cleared by * configfs_depend_rollback(). * * This adds a requirement that all config_items be unique! * * This is recursive because the locking traversal is tricky. There isn't * much on the stack, though, so folks that need this function - be careful * about your stack! Patches will be accepted to make it iterative. */static int configfs_depend_prep(struct dentry *origin, struct config_item *target){ struct configfs_dirent *child_sd, *sd = origin->d_fsdata; int ret = 0; BUG_ON(!origin || !sd); /* Lock this guy on the way down */ mutex_lock(&sd->s_dentry->d_inode->i_mutex); if (sd->s_element == target) /* Boo-yah */ goto out; list_for_each_entry(child_sd, &sd->s_children, s_sibling) { if (child_sd->s_type & CONFIGFS_DIR) { ret = configfs_depend_prep(child_sd->s_dentry, target); if (!ret) goto out; /* Child path boo-yah */ } } /* We looped all our children and didn't find target */ mutex_unlock(&sd->s_dentry->d_inode->i_mutex); ret = -ENOENT;out: return ret;}/* * This is ONLY called if configfs_depend_prep() did its job. So we can * trust the entire path from item back up to origin. * * We walk backwards from item, unlocking each i_mutex. We finish by * unlocking origin. */static void configfs_depend_rollback(struct dentry *origin, struct config_item *item){ struct dentry *dentry = item->ci_dentry; while (dentry != origin) { mutex_unlock(&dentry->d_inode->i_mutex); dentry = dentry->d_parent; } mutex_unlock(&origin->d_inode->i_mutex);}int configfs_depend_item(struct configfs_subsystem *subsys, struct config_item *target){ int ret; struct configfs_dirent *p, *root_sd, *subsys_sd = NULL; struct config_item *s_item = &subsys->su_group.cg_item; /* * Pin the configfs filesystem. This means we can safely access * the root of the configfs filesystem. */ ret = configfs_pin_fs(); if (ret) return ret; /* * Next, lock the root directory. We're going to check that the * subsystem is really registered, and so we need to lock out * configfs_[un]register_subsystem(). */ mutex_lock(&configfs_sb->s_root->d_inode->i_mutex); root_sd = configfs_sb->s_root->d_fsdata; list_for_each_entry(p, &root_sd->s_children, s_sibling) { if (p->s_type & CONFIGFS_DIR) { if (p->s_element == s_item) { subsys_sd = p; break; } } } if (!subsys_sd) { ret = -ENOENT; goto out_unlock_fs; } /* Ok, now we can trust subsys/s_item */ /* Scan the tree, locking i_mutex recursively, return 0 if found */ ret = configfs_depend_prep(subsys_sd->s_dentry, target); if (ret) goto out_unlock_fs; /* We hold all i_mutexes from the subsystem down to the target */ p = target->ci_dentry->d_fsdata; p->s_dependent_count += 1; configfs_depend_rollback(subsys_sd->s_dentry, target);out_unlock_fs: mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex); /* * If we succeeded, the fs is pinned via other methods. If not, * we're done with it anyway. So release_fs() is always right. */ configfs_release_fs(); return ret;}EXPORT_SYMBOL(configfs_depend_item);/* * Release the dependent linkage. This is much simpler than * configfs_depend_item() because we know that that the client driver is * pinned, thus the subsystem is pinned, and therefore configfs is pinned. */void configfs_undepend_item(struct configfs_subsystem *subsys, struct config_item *target){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -