Loading fs/configfs/configfs_internal.h +4 −15 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ struct configfs_dirent { int s_dependent_count; struct list_head s_sibling; struct list_head s_children; struct list_head s_links; int s_links; void * s_element; int s_type; umode_t s_mode; Loading Loading @@ -84,7 +84,6 @@ extern int configfs_setattr(struct dentry *dentry, struct iattr *iattr); extern struct dentry *configfs_pin_fs(void); extern void configfs_release_fs(void); extern struct rw_semaphore configfs_rename_sem; extern const struct file_operations configfs_dir_operations; extern const struct file_operations configfs_file_operations; extern const struct file_operations configfs_bin_file_operations; Loading @@ -97,14 +96,8 @@ extern int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); extern int configfs_unlink(struct inode *dir, struct dentry *dentry); struct configfs_symlink { struct list_head sl_list; struct config_item *sl_target; }; extern int configfs_create_link(struct configfs_symlink *sl, struct dentry *parent, struct dentry *dentry); int configfs_create_link(struct configfs_dirent *target, struct dentry *parent, struct dentry *dentry, char *body); static inline struct config_item * to_item(struct dentry * dentry) { Loading Loading @@ -132,10 +125,6 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry spin_lock(&dentry->d_lock); if (!d_unhashed(dentry)) { struct configfs_dirent * sd = dentry->d_fsdata; if (sd->s_type & CONFIGFS_ITEM_LINK) { struct configfs_symlink * sl = sd->s_element; item = config_item_get(sl->sl_target); } else item = config_item_get(sd->s_element); } spin_unlock(&dentry->d_lock); Loading fs/configfs/dir.c +6 −46 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ #include <linux/configfs.h> #include "configfs_internal.h" DECLARE_RWSEM(configfs_rename_sem); /* * Protects mutations of configfs_dirent linkage together with proper i_mutex * Also protects mutations of symlinks linkage to target configfs_dirent Loading Loading @@ -191,7 +190,6 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent *paren return ERR_PTR(-ENOMEM); atomic_set(&sd->s_count, 1); INIT_LIST_HEAD(&sd->s_links); INIT_LIST_HEAD(&sd->s_children); sd->s_element = element; sd->s_type = type; Loading Loading @@ -353,17 +351,16 @@ int configfs_dirent_is_ready(struct configfs_dirent *sd) return ret; } int configfs_create_link(struct configfs_symlink *sl, struct dentry *parent, struct dentry *dentry) int configfs_create_link(struct configfs_dirent *target, struct dentry *parent, struct dentry *dentry, char *body) { int err = 0; umode_t mode = S_IFLNK | S_IRWXUGO; struct configfs_dirent *p = parent->d_fsdata; struct inode *inode; err = configfs_make_dirent(p, dentry, sl, mode, CONFIGFS_ITEM_LINK, p->s_frag); err = configfs_make_dirent(p, dentry, target, mode, CONFIGFS_ITEM_LINK, p->s_frag); if (err) return err; Loading @@ -371,6 +368,7 @@ int configfs_create_link(struct configfs_symlink *sl, if (IS_ERR(inode)) goto out_remove; inode->i_link = body; inode->i_op = &configfs_symlink_inode_operations; d_instantiate(dentry, inode); dget(dentry); /* pin link dentries in core */ Loading Loading @@ -517,7 +515,7 @@ static int configfs_detach_prep(struct dentry *dentry, struct dentry **wait) parent_sd->s_type |= CONFIGFS_USET_DROPPING; ret = -EBUSY; if (!list_empty(&parent_sd->s_links)) if (parent_sd->s_links) goto out; ret = 0; Loading Loading @@ -1575,44 +1573,6 @@ const struct inode_operations configfs_root_inode_operations = { .setattr = configfs_setattr, }; #if 0 int configfs_rename_dir(struct config_item * item, const char *new_name) { int error = 0; struct dentry * new_dentry, * parent; if (!strcmp(config_item_name(item), new_name)) return -EINVAL; if (!item->parent) return -EINVAL; down_write(&configfs_rename_sem); parent = item->parent->dentry; inode_lock(d_inode(parent)); new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); if (!IS_ERR(new_dentry)) { if (d_really_is_negative(new_dentry)) { error = config_item_set_name(item, "%s", new_name); if (!error) { d_add(new_dentry, NULL); d_move(item->dentry, new_dentry); } else d_delete(new_dentry); } else error = -EEXIST; dput(new_dentry); } inode_unlock(d_inode(parent)); up_write(&configfs_rename_sem); return error; } #endif static int configfs_dir_open(struct inode *inode, struct file *file) { struct dentry * dentry = file->f_path.dentry; Loading fs/configfs/mount.c +9 −0 Original line number Diff line number Diff line Loading @@ -28,9 +28,18 @@ static struct vfsmount *configfs_mount = NULL; struct kmem_cache *configfs_dir_cachep; static int configfs_mnt_count = 0; static void configfs_free_inode(struct inode *inode) { if (S_ISLNK(inode->i_mode)) kfree(inode->i_link); free_inode_nonrcu(inode); } static const struct super_operations configfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, .free_inode = configfs_free_inode, }; static struct config_group configfs_root_group = { Loading fs/configfs/symlink.c +54 −110 Original line number Diff line number Diff line Loading @@ -55,41 +55,63 @@ static void fill_item_path(struct config_item * item, char * buffer, int length) } } static int configfs_get_target_path(struct config_item *item, struct config_item *target, char *path) { int depth, size; char *s; depth = item_depth(item); size = item_path_length(target) + depth * 3 - 1; if (size > PATH_MAX) return -ENAMETOOLONG; pr_debug("%s: depth = %d, size = %d\n", __func__, depth, size); for (s = path; depth--; s += 3) strcpy(s,"../"); fill_item_path(target, path, size); pr_debug("%s: path = '%s'\n", __func__, path); return 0; } static int create_link(struct config_item *parent_item, struct config_item *item, struct dentry *dentry) { struct configfs_dirent *target_sd = item->ci_dentry->d_fsdata; struct configfs_symlink *sl; char *body; int ret; ret = -ENOENT; if (!configfs_dirent_is_ready(target_sd)) goto out; ret = -ENOMEM; sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL); if (sl) { return -ENOENT; body = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!body) return -ENOMEM; configfs_get(target_sd); spin_lock(&configfs_dirent_lock); if (target_sd->s_type & CONFIGFS_USET_DROPPING) { spin_unlock(&configfs_dirent_lock); kfree(sl); configfs_put(target_sd); kfree(body); return -ENOENT; } sl->sl_target = config_item_get(item); list_add(&sl->sl_list, &target_sd->s_links); target_sd->s_links++; spin_unlock(&configfs_dirent_lock); ret = configfs_create_link(sl, parent_item->ci_dentry, dentry); ret = configfs_get_target_path(item, item, body); if (!ret) ret = configfs_create_link(target_sd, parent_item->ci_dentry, dentry, body); if (ret) { spin_lock(&configfs_dirent_lock); list_del_init(&sl->sl_list); target_sd->s_links--; spin_unlock(&configfs_dirent_lock); config_item_put(item); kfree(sl); } configfs_put(target_sd); kfree(body); } out: return ret; } Loading Loading @@ -131,9 +153,8 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna * Fake invisibility if dir belongs to a group/default groups hierarchy * being attached */ ret = -ENOENT; if (!configfs_dirent_is_ready(sd)) goto out; return -ENOENT; parent_item = configfs_get_config_item(dentry->d_parent); type = parent_item->ci_type; Loading Loading @@ -193,15 +214,12 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna out_put: config_item_put(parent_item); out: return ret; } int configfs_unlink(struct inode *dir, struct dentry *dentry) { struct configfs_dirent *sd = dentry->d_fsdata; struct configfs_symlink *sl; struct configfs_dirent *sd = dentry->d_fsdata, *target_sd; struct config_item *parent_item; const struct config_item_type *type; int ret; Loading @@ -210,7 +228,7 @@ int configfs_unlink(struct inode *dir, struct dentry *dentry) if (!(sd->s_type & CONFIGFS_ITEM_LINK)) goto out; sl = sd->s_element; target_sd = sd->s_element; parent_item = configfs_get_config_item(dentry->d_parent); type = parent_item->ci_type; Loading @@ -224,21 +242,18 @@ int configfs_unlink(struct inode *dir, struct dentry *dentry) /* * drop_link() must be called before * list_del_init(&sl->sl_list), so that the order of * decrementing target's ->s_links, so that the order of * drop_link(this, target) and drop_item(target) is preserved. */ if (type && type->ct_item_ops && type->ct_item_ops->drop_link) type->ct_item_ops->drop_link(parent_item, sl->sl_target); target_sd->s_element); spin_lock(&configfs_dirent_lock); list_del_init(&sl->sl_list); target_sd->s_links--; spin_unlock(&configfs_dirent_lock); /* Put reference from create_link() */ config_item_put(sl->sl_target); kfree(sl); configfs_put(target_sd); config_item_put(parent_item); Loading @@ -248,79 +263,8 @@ out: return ret; } static int configfs_get_target_path(struct config_item * item, struct config_item * target, char *path) { char * s; int depth, size; depth = item_depth(item); size = item_path_length(target) + depth * 3 - 1; if (size > PATH_MAX) return -ENAMETOOLONG; pr_debug("%s: depth = %d, size = %d\n", __func__, depth, size); for (s = path; depth--; s += 3) strcpy(s,"../"); fill_item_path(target, path, size); pr_debug("%s: path = '%s'\n", __func__, path); return 0; } static int configfs_getlink(struct dentry *dentry, char * path) { struct config_item *item, *target_item; int error = 0; item = configfs_get_config_item(dentry->d_parent); if (!item) return -EINVAL; target_item = configfs_get_config_item(dentry); if (!target_item) { config_item_put(item); return -EINVAL; } down_read(&configfs_rename_sem); error = configfs_get_target_path(item, target_item, path); up_read(&configfs_rename_sem); config_item_put(item); config_item_put(target_item); return error; } static const char *configfs_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { char *body; int error; if (!dentry) return ERR_PTR(-ECHILD); body = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!body) return ERR_PTR(-ENOMEM); error = configfs_getlink(dentry, body); if (!error) { set_delayed_call(done, kfree_link, body); return body; } kfree(body); return ERR_PTR(error); } const struct inode_operations configfs_symlink_inode_operations = { .get_link = configfs_get_link, .get_link = simple_get_link, .setattr = configfs_setattr, }; Loading
fs/configfs/configfs_internal.h +4 −15 Original line number Diff line number Diff line Loading @@ -34,7 +34,7 @@ struct configfs_dirent { int s_dependent_count; struct list_head s_sibling; struct list_head s_children; struct list_head s_links; int s_links; void * s_element; int s_type; umode_t s_mode; Loading Loading @@ -84,7 +84,6 @@ extern int configfs_setattr(struct dentry *dentry, struct iattr *iattr); extern struct dentry *configfs_pin_fs(void); extern void configfs_release_fs(void); extern struct rw_semaphore configfs_rename_sem; extern const struct file_operations configfs_dir_operations; extern const struct file_operations configfs_file_operations; extern const struct file_operations configfs_bin_file_operations; Loading @@ -97,14 +96,8 @@ extern int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); extern int configfs_unlink(struct inode *dir, struct dentry *dentry); struct configfs_symlink { struct list_head sl_list; struct config_item *sl_target; }; extern int configfs_create_link(struct configfs_symlink *sl, struct dentry *parent, struct dentry *dentry); int configfs_create_link(struct configfs_dirent *target, struct dentry *parent, struct dentry *dentry, char *body); static inline struct config_item * to_item(struct dentry * dentry) { Loading Loading @@ -132,10 +125,6 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry spin_lock(&dentry->d_lock); if (!d_unhashed(dentry)) { struct configfs_dirent * sd = dentry->d_fsdata; if (sd->s_type & CONFIGFS_ITEM_LINK) { struct configfs_symlink * sl = sd->s_element; item = config_item_get(sl->sl_target); } else item = config_item_get(sd->s_element); } spin_unlock(&dentry->d_lock); Loading
fs/configfs/dir.c +6 −46 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ #include <linux/configfs.h> #include "configfs_internal.h" DECLARE_RWSEM(configfs_rename_sem); /* * Protects mutations of configfs_dirent linkage together with proper i_mutex * Also protects mutations of symlinks linkage to target configfs_dirent Loading Loading @@ -191,7 +190,6 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent *paren return ERR_PTR(-ENOMEM); atomic_set(&sd->s_count, 1); INIT_LIST_HEAD(&sd->s_links); INIT_LIST_HEAD(&sd->s_children); sd->s_element = element; sd->s_type = type; Loading Loading @@ -353,17 +351,16 @@ int configfs_dirent_is_ready(struct configfs_dirent *sd) return ret; } int configfs_create_link(struct configfs_symlink *sl, struct dentry *parent, struct dentry *dentry) int configfs_create_link(struct configfs_dirent *target, struct dentry *parent, struct dentry *dentry, char *body) { int err = 0; umode_t mode = S_IFLNK | S_IRWXUGO; struct configfs_dirent *p = parent->d_fsdata; struct inode *inode; err = configfs_make_dirent(p, dentry, sl, mode, CONFIGFS_ITEM_LINK, p->s_frag); err = configfs_make_dirent(p, dentry, target, mode, CONFIGFS_ITEM_LINK, p->s_frag); if (err) return err; Loading @@ -371,6 +368,7 @@ int configfs_create_link(struct configfs_symlink *sl, if (IS_ERR(inode)) goto out_remove; inode->i_link = body; inode->i_op = &configfs_symlink_inode_operations; d_instantiate(dentry, inode); dget(dentry); /* pin link dentries in core */ Loading Loading @@ -517,7 +515,7 @@ static int configfs_detach_prep(struct dentry *dentry, struct dentry **wait) parent_sd->s_type |= CONFIGFS_USET_DROPPING; ret = -EBUSY; if (!list_empty(&parent_sd->s_links)) if (parent_sd->s_links) goto out; ret = 0; Loading Loading @@ -1575,44 +1573,6 @@ const struct inode_operations configfs_root_inode_operations = { .setattr = configfs_setattr, }; #if 0 int configfs_rename_dir(struct config_item * item, const char *new_name) { int error = 0; struct dentry * new_dentry, * parent; if (!strcmp(config_item_name(item), new_name)) return -EINVAL; if (!item->parent) return -EINVAL; down_write(&configfs_rename_sem); parent = item->parent->dentry; inode_lock(d_inode(parent)); new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); if (!IS_ERR(new_dentry)) { if (d_really_is_negative(new_dentry)) { error = config_item_set_name(item, "%s", new_name); if (!error) { d_add(new_dentry, NULL); d_move(item->dentry, new_dentry); } else d_delete(new_dentry); } else error = -EEXIST; dput(new_dentry); } inode_unlock(d_inode(parent)); up_write(&configfs_rename_sem); return error; } #endif static int configfs_dir_open(struct inode *inode, struct file *file) { struct dentry * dentry = file->f_path.dentry; Loading
fs/configfs/mount.c +9 −0 Original line number Diff line number Diff line Loading @@ -28,9 +28,18 @@ static struct vfsmount *configfs_mount = NULL; struct kmem_cache *configfs_dir_cachep; static int configfs_mnt_count = 0; static void configfs_free_inode(struct inode *inode) { if (S_ISLNK(inode->i_mode)) kfree(inode->i_link); free_inode_nonrcu(inode); } static const struct super_operations configfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, .free_inode = configfs_free_inode, }; static struct config_group configfs_root_group = { Loading
fs/configfs/symlink.c +54 −110 Original line number Diff line number Diff line Loading @@ -55,41 +55,63 @@ static void fill_item_path(struct config_item * item, char * buffer, int length) } } static int configfs_get_target_path(struct config_item *item, struct config_item *target, char *path) { int depth, size; char *s; depth = item_depth(item); size = item_path_length(target) + depth * 3 - 1; if (size > PATH_MAX) return -ENAMETOOLONG; pr_debug("%s: depth = %d, size = %d\n", __func__, depth, size); for (s = path; depth--; s += 3) strcpy(s,"../"); fill_item_path(target, path, size); pr_debug("%s: path = '%s'\n", __func__, path); return 0; } static int create_link(struct config_item *parent_item, struct config_item *item, struct dentry *dentry) { struct configfs_dirent *target_sd = item->ci_dentry->d_fsdata; struct configfs_symlink *sl; char *body; int ret; ret = -ENOENT; if (!configfs_dirent_is_ready(target_sd)) goto out; ret = -ENOMEM; sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL); if (sl) { return -ENOENT; body = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!body) return -ENOMEM; configfs_get(target_sd); spin_lock(&configfs_dirent_lock); if (target_sd->s_type & CONFIGFS_USET_DROPPING) { spin_unlock(&configfs_dirent_lock); kfree(sl); configfs_put(target_sd); kfree(body); return -ENOENT; } sl->sl_target = config_item_get(item); list_add(&sl->sl_list, &target_sd->s_links); target_sd->s_links++; spin_unlock(&configfs_dirent_lock); ret = configfs_create_link(sl, parent_item->ci_dentry, dentry); ret = configfs_get_target_path(item, item, body); if (!ret) ret = configfs_create_link(target_sd, parent_item->ci_dentry, dentry, body); if (ret) { spin_lock(&configfs_dirent_lock); list_del_init(&sl->sl_list); target_sd->s_links--; spin_unlock(&configfs_dirent_lock); config_item_put(item); kfree(sl); } configfs_put(target_sd); kfree(body); } out: return ret; } Loading Loading @@ -131,9 +153,8 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna * Fake invisibility if dir belongs to a group/default groups hierarchy * being attached */ ret = -ENOENT; if (!configfs_dirent_is_ready(sd)) goto out; return -ENOENT; parent_item = configfs_get_config_item(dentry->d_parent); type = parent_item->ci_type; Loading Loading @@ -193,15 +214,12 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna out_put: config_item_put(parent_item); out: return ret; } int configfs_unlink(struct inode *dir, struct dentry *dentry) { struct configfs_dirent *sd = dentry->d_fsdata; struct configfs_symlink *sl; struct configfs_dirent *sd = dentry->d_fsdata, *target_sd; struct config_item *parent_item; const struct config_item_type *type; int ret; Loading @@ -210,7 +228,7 @@ int configfs_unlink(struct inode *dir, struct dentry *dentry) if (!(sd->s_type & CONFIGFS_ITEM_LINK)) goto out; sl = sd->s_element; target_sd = sd->s_element; parent_item = configfs_get_config_item(dentry->d_parent); type = parent_item->ci_type; Loading @@ -224,21 +242,18 @@ int configfs_unlink(struct inode *dir, struct dentry *dentry) /* * drop_link() must be called before * list_del_init(&sl->sl_list), so that the order of * decrementing target's ->s_links, so that the order of * drop_link(this, target) and drop_item(target) is preserved. */ if (type && type->ct_item_ops && type->ct_item_ops->drop_link) type->ct_item_ops->drop_link(parent_item, sl->sl_target); target_sd->s_element); spin_lock(&configfs_dirent_lock); list_del_init(&sl->sl_list); target_sd->s_links--; spin_unlock(&configfs_dirent_lock); /* Put reference from create_link() */ config_item_put(sl->sl_target); kfree(sl); configfs_put(target_sd); config_item_put(parent_item); Loading @@ -248,79 +263,8 @@ out: return ret; } static int configfs_get_target_path(struct config_item * item, struct config_item * target, char *path) { char * s; int depth, size; depth = item_depth(item); size = item_path_length(target) + depth * 3 - 1; if (size > PATH_MAX) return -ENAMETOOLONG; pr_debug("%s: depth = %d, size = %d\n", __func__, depth, size); for (s = path; depth--; s += 3) strcpy(s,"../"); fill_item_path(target, path, size); pr_debug("%s: path = '%s'\n", __func__, path); return 0; } static int configfs_getlink(struct dentry *dentry, char * path) { struct config_item *item, *target_item; int error = 0; item = configfs_get_config_item(dentry->d_parent); if (!item) return -EINVAL; target_item = configfs_get_config_item(dentry); if (!target_item) { config_item_put(item); return -EINVAL; } down_read(&configfs_rename_sem); error = configfs_get_target_path(item, target_item, path); up_read(&configfs_rename_sem); config_item_put(item); config_item_put(target_item); return error; } static const char *configfs_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { char *body; int error; if (!dentry) return ERR_PTR(-ECHILD); body = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!body) return ERR_PTR(-ENOMEM); error = configfs_getlink(dentry, body); if (!error) { set_delayed_call(done, kfree_link, body); return body; } kfree(body); return ERR_PTR(error); } const struct inode_operations configfs_symlink_inode_operations = { .get_link = configfs_get_link, .get_link = simple_get_link, .setattr = configfs_setattr, };