int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { int ret; struct path path; struct configfs_dirent *sd; struct config_item *parent_item; struct config_item *target_item = NULL; struct config_item_type *type; ret = -EPERM; /* What lack-of-symlink returns */ if (dentry->d_parent == configfs_sb->s_root) goto out; sd = dentry->d_parent->d_fsdata; /* * Fake invisibility if dir belongs to a group/default groups hierarchy * being attached */ ret = -ENOENT; if (!configfs_dirent_is_ready(sd)) goto out; parent_item = configfs_get_config_item(dentry->d_parent); type = parent_item->ci_type; ret = -EPERM; if (!type || !type->ct_item_ops || !type->ct_item_ops->allow_link) goto out_put; ret = get_target(symname, &path, &target_item); if (ret) goto out_put; ret = type->ct_item_ops->allow_link(parent_item, target_item); if (!ret) { mutex_lock(&configfs_symlink_mutex); ret = create_link(parent_item, target_item, dentry); mutex_unlock(&configfs_symlink_mutex); if (ret && type->ct_item_ops->drop_link) type->ct_item_ops->drop_link(parent_item, target_item); } config_item_put(target_item); path_put(&path); 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 config_item *parent_item; struct config_item_type *type; int ret; ret = -EPERM; /* What lack-of-symlink returns */ if (!(sd->s_type & CONFIGFS_ITEM_LINK)) goto out; BUG_ON(dentry->d_parent == configfs_sb->s_root); sl = sd->s_element; parent_item = configfs_get_config_item(dentry->d_parent); type = parent_item->ci_type; spin_lock(&configfs_dirent_lock); list_del_init(&sd->s_sibling); spin_unlock(&configfs_dirent_lock); configfs_drop_dentry(sd, dentry->d_parent); dput(dentry); configfs_put(sd); /* * drop_link() must be called before * list_del_init(&sl->sl_list), 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); spin_lock(&configfs_dirent_lock); list_del_init(&sl->sl_list); spin_unlock(&configfs_dirent_lock); /* Put reference from create_link() */ config_item_put(sl->sl_target); kfree(sl); config_item_put(parent_item); ret = 0; out: return ret; }
int configfs_unlink(struct inode *dir, struct dentry *dentry) { struct configfs_dirent *sd = dentry->d_fsdata; struct configfs_symlink *sl; struct config_item *parent_item; struct config_item_type *type; int ret; ret = -EPERM; /* */ if (!(sd->s_type & CONFIGFS_ITEM_LINK)) goto out; sl = sd->s_element; parent_item = configfs_get_config_item(dentry->d_parent); type = parent_item->ci_type; spin_lock(&configfs_dirent_lock); list_del_init(&sd->s_sibling); spin_unlock(&configfs_dirent_lock); configfs_drop_dentry(sd, dentry->d_parent); dput(dentry); configfs_put(sd); /* */ if (type && type->ct_item_ops && type->ct_item_ops->drop_link) type->ct_item_ops->drop_link(parent_item, sl->sl_target); spin_lock(&configfs_dirent_lock); list_del_init(&sl->sl_list); spin_unlock(&configfs_dirent_lock); /* */ config_item_put(sl->sl_target); kfree(sl); config_item_put(parent_item); ret = 0; out: return ret; }
int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { int ret; struct path path; struct configfs_dirent *sd; struct config_item *parent_item; struct config_item *target_item = NULL; struct config_item_type *type; sd = dentry->d_parent->d_fsdata; /* */ ret = -ENOENT; if (!configfs_dirent_is_ready(sd)) goto out; parent_item = configfs_get_config_item(dentry->d_parent); type = parent_item->ci_type; ret = -EPERM; if (!type || !type->ct_item_ops || !type->ct_item_ops->allow_link) goto out_put; ret = get_target(symname, &path, &target_item, dentry->d_sb); if (ret) goto out_put; ret = type->ct_item_ops->allow_link(parent_item, target_item); if (!ret) { mutex_lock(&configfs_symlink_mutex); ret = create_link(parent_item, target_item, dentry); mutex_unlock(&configfs_symlink_mutex); if (ret && type->ct_item_ops->drop_link) type->ct_item_ops->drop_link(parent_item, target_item); } config_item_put(target_item); path_put(&path); out_put: config_item_put(parent_item); out: return ret; }
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 int get_target(const char *symname, struct nameidata *nd, struct config_item **target) { int ret; ret = path_lookup(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, nd); if (!ret) { if (nd->path.dentry->d_sb == configfs_sb) { *target = configfs_get_config_item(nd->path.dentry); if (!*target) { ret = -ENOENT; path_put(&nd->path); } } else ret = -EPERM; } return ret; }
static int get_target(const char *symname, struct path *path, struct config_item **target) { int ret; ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path); if (!ret) { if (path->dentry->d_sb == configfs_sb) { *target = configfs_get_config_item(path->dentry); if (!*target) { ret = -ENOENT; path_put(path); } } else { ret = -EPERM; path_put(path); } } return ret; }
int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { int ret; struct nameidata nd; struct config_item *parent_item; struct config_item *target_item; struct config_item_type *type; ret = -EPERM; /* What lack-of-symlink returns */ if (dentry->d_parent == configfs_sb->s_root) goto out; parent_item = configfs_get_config_item(dentry->d_parent); type = parent_item->ci_type; if (!type || !type->ct_item_ops || !type->ct_item_ops->allow_link) goto out_put; ret = get_target(symname, &nd, &target_item); if (ret) goto out_put; ret = type->ct_item_ops->allow_link(parent_item, target_item); if (!ret) ret = create_link(parent_item, target_item, dentry); config_item_put(target_item); path_put(&nd.path); out_put: config_item_put(parent_item); out: return ret; }
static int check_perm(struct inode * inode, struct file * file) { struct config_item *item = configfs_get_config_item(file->f_path.dentry->d_parent); struct configfs_attribute * attr = to_attr(file->f_path.dentry); struct configfs_buffer * buffer; struct configfs_item_operations * ops = NULL; int error = 0; if (!item || !attr) goto Einval; /* Grab the module reference for this attribute if we have one */ if (!try_module_get(attr->ca_owner)) { error = -ENODEV; goto Done; } if (item->ci_type) ops = item->ci_type->ct_item_ops; else goto Eaccess; /* File needs write support. * The inode's perms must say it's ok, * and we must have a store method. */ if (file->f_mode & FMODE_WRITE) { if (!(inode->i_mode & S_IWUGO) || !ops->store_attribute) goto Eaccess; } /* File needs read support. * The inode's perms must say it's ok, and we there * must be a show method for it. */ if (file->f_mode & FMODE_READ) { if (!(inode->i_mode & S_IRUGO) || !ops->show_attribute) goto Eaccess; } /* No error? Great, allocate a buffer for the file, and store it * it in file->private_data for easy access. */ buffer = kzalloc(sizeof(struct configfs_buffer),GFP_KERNEL); if (!buffer) { error = -ENOMEM; goto Enomem; } mutex_init(&buffer->mutex); buffer->needs_read_fill = 1; buffer->ops = ops; file->private_data = buffer; goto Done; Einval: error = -EINVAL; goto Done; Eaccess: error = -EACCES; Enomem: module_put(attr->ca_owner); Done: if (error && item) config_item_put(item); return error; }
static int configfs_open_bin_file(struct inode *inode, struct file *filp) { return check_perm(inode, filp, configfs_get_config_item(filp->f_path.dentry->d_parent), to_attr(filp->f_path.dentry), CONFIGFS_ITEM_BIN_ATTR); }