0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/fs.h>
0012 #include <linux/module.h>
0013 #include <linux/namei.h>
0014 #include <linux/slab.h>
0015
0016 #include <linux/configfs.h>
0017 #include "configfs_internal.h"
0018
0019
0020 DEFINE_MUTEX(configfs_symlink_mutex);
0021
0022 static int item_depth(struct config_item * item)
0023 {
0024 struct config_item * p = item;
0025 int depth = 0;
0026 do { depth++; } while ((p = p->ci_parent) && !configfs_is_root(p));
0027 return depth;
0028 }
0029
0030 static int item_path_length(struct config_item * item)
0031 {
0032 struct config_item * p = item;
0033 int length = 1;
0034 do {
0035 length += strlen(config_item_name(p)) + 1;
0036 p = p->ci_parent;
0037 } while (p && !configfs_is_root(p));
0038 return length;
0039 }
0040
0041 static void fill_item_path(struct config_item * item, char * buffer, int length)
0042 {
0043 struct config_item * p;
0044
0045 --length;
0046 for (p = item; p && !configfs_is_root(p); p = p->ci_parent) {
0047 int cur = strlen(config_item_name(p));
0048
0049
0050 length -= cur;
0051 memcpy(buffer + length, config_item_name(p), cur);
0052 *(buffer + --length) = '/';
0053 }
0054 }
0055
0056 static int configfs_get_target_path(struct config_item *item,
0057 struct config_item *target, char *path)
0058 {
0059 int depth, size;
0060 char *s;
0061
0062 depth = item_depth(item);
0063 size = item_path_length(target) + depth * 3 - 1;
0064 if (size > PATH_MAX)
0065 return -ENAMETOOLONG;
0066
0067 pr_debug("%s: depth = %d, size = %d\n", __func__, depth, size);
0068
0069 for (s = path; depth--; s += 3)
0070 strcpy(s,"../");
0071
0072 fill_item_path(target, path, size);
0073 pr_debug("%s: path = '%s'\n", __func__, path);
0074 return 0;
0075 }
0076
0077 static int create_link(struct config_item *parent_item,
0078 struct config_item *item,
0079 struct dentry *dentry)
0080 {
0081 struct configfs_dirent *target_sd = item->ci_dentry->d_fsdata;
0082 char *body;
0083 int ret;
0084
0085 if (!configfs_dirent_is_ready(target_sd))
0086 return -ENOENT;
0087
0088 body = kzalloc(PAGE_SIZE, GFP_KERNEL);
0089 if (!body)
0090 return -ENOMEM;
0091
0092 configfs_get(target_sd);
0093 spin_lock(&configfs_dirent_lock);
0094 if (target_sd->s_type & CONFIGFS_USET_DROPPING) {
0095 spin_unlock(&configfs_dirent_lock);
0096 configfs_put(target_sd);
0097 kfree(body);
0098 return -ENOENT;
0099 }
0100 target_sd->s_links++;
0101 spin_unlock(&configfs_dirent_lock);
0102 ret = configfs_get_target_path(parent_item, item, body);
0103 if (!ret)
0104 ret = configfs_create_link(target_sd, parent_item->ci_dentry,
0105 dentry, body);
0106 if (ret) {
0107 spin_lock(&configfs_dirent_lock);
0108 target_sd->s_links--;
0109 spin_unlock(&configfs_dirent_lock);
0110 configfs_put(target_sd);
0111 kfree(body);
0112 }
0113 return ret;
0114 }
0115
0116
0117 static int get_target(const char *symname, struct path *path,
0118 struct config_item **target, struct super_block *sb)
0119 {
0120 int ret;
0121
0122 ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path);
0123 if (!ret) {
0124 if (path->dentry->d_sb == sb) {
0125 *target = configfs_get_config_item(path->dentry);
0126 if (!*target) {
0127 ret = -ENOENT;
0128 path_put(path);
0129 }
0130 } else {
0131 ret = -EPERM;
0132 path_put(path);
0133 }
0134 }
0135
0136 return ret;
0137 }
0138
0139
0140 int configfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
0141 struct dentry *dentry, const char *symname)
0142 {
0143 int ret;
0144 struct path path;
0145 struct configfs_dirent *sd;
0146 struct config_item *parent_item;
0147 struct config_item *target_item = NULL;
0148 const struct config_item_type *type;
0149
0150 sd = dentry->d_parent->d_fsdata;
0151
0152
0153
0154
0155 if (!configfs_dirent_is_ready(sd))
0156 return -ENOENT;
0157
0158 parent_item = configfs_get_config_item(dentry->d_parent);
0159 type = parent_item->ci_type;
0160
0161 ret = -EPERM;
0162 if (!type || !type->ct_item_ops ||
0163 !type->ct_item_ops->allow_link)
0164 goto out_put;
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190 inode_unlock(dir);
0191 ret = get_target(symname, &path, &target_item, dentry->d_sb);
0192 inode_lock(dir);
0193 if (ret)
0194 goto out_put;
0195
0196 if (dentry->d_inode || d_unhashed(dentry))
0197 ret = -EEXIST;
0198 else
0199 ret = inode_permission(&init_user_ns, dir,
0200 MAY_WRITE | MAY_EXEC);
0201 if (!ret)
0202 ret = type->ct_item_ops->allow_link(parent_item, target_item);
0203 if (!ret) {
0204 mutex_lock(&configfs_symlink_mutex);
0205 ret = create_link(parent_item, target_item, dentry);
0206 mutex_unlock(&configfs_symlink_mutex);
0207 if (ret && type->ct_item_ops->drop_link)
0208 type->ct_item_ops->drop_link(parent_item,
0209 target_item);
0210 }
0211
0212 config_item_put(target_item);
0213 path_put(&path);
0214
0215 out_put:
0216 config_item_put(parent_item);
0217 return ret;
0218 }
0219
0220 int configfs_unlink(struct inode *dir, struct dentry *dentry)
0221 {
0222 struct configfs_dirent *sd = dentry->d_fsdata, *target_sd;
0223 struct config_item *parent_item;
0224 const struct config_item_type *type;
0225 int ret;
0226
0227 ret = -EPERM;
0228 if (!(sd->s_type & CONFIGFS_ITEM_LINK))
0229 goto out;
0230
0231 target_sd = sd->s_element;
0232
0233 parent_item = configfs_get_config_item(dentry->d_parent);
0234 type = parent_item->ci_type;
0235
0236 spin_lock(&configfs_dirent_lock);
0237 list_del_init(&sd->s_sibling);
0238 spin_unlock(&configfs_dirent_lock);
0239 configfs_drop_dentry(sd, dentry->d_parent);
0240 dput(dentry);
0241 configfs_put(sd);
0242
0243
0244
0245
0246
0247
0248 if (type && type->ct_item_ops &&
0249 type->ct_item_ops->drop_link)
0250 type->ct_item_ops->drop_link(parent_item,
0251 target_sd->s_element);
0252
0253 spin_lock(&configfs_dirent_lock);
0254 target_sd->s_links--;
0255 spin_unlock(&configfs_dirent_lock);
0256 configfs_put(target_sd);
0257
0258 config_item_put(parent_item);
0259
0260 ret = 0;
0261
0262 out:
0263 return ret;
0264 }
0265
0266 const struct inode_operations configfs_symlink_inode_operations = {
0267 .get_link = simple_get_link,
0268 .setattr = configfs_setattr,
0269 };
0270