Blame view
fs/configfs/symlink.c
7.19 KB
7063fbf22 [PATCH] configfs:... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * symlink.c - operations for configfs symlinks. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. * * Based on sysfs: * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel * * configfs Copyright (C) 2005 Oracle. All rights reserved. */ #include <linux/fs.h> #include <linux/module.h> #include <linux/namei.h> |
5a0e3ad6a include cleanup: ... |
30 |
#include <linux/slab.h> |
7063fbf22 [PATCH] configfs:... |
31 32 33 |
#include <linux/configfs.h> #include "configfs_internal.h" |
9a73d78cd [PATCH] configfs:... |
34 35 |
/* Protects attachments of new symlinks */ DEFINE_MUTEX(configfs_symlink_mutex); |
7063fbf22 [PATCH] configfs:... |
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
static int item_depth(struct config_item * item) { struct config_item * p = item; int depth = 0; do { depth++; } while ((p = p->ci_parent) && !configfs_is_root(p)); return depth; } static int item_path_length(struct config_item * item) { struct config_item * p = item; int length = 1; do { length += strlen(config_item_name(p)) + 1; p = p->ci_parent; } while (p && !configfs_is_root(p)); return length; } static void fill_item_path(struct config_item * item, char * buffer, int length) { struct config_item * p; --length; for (p = item; p && !configfs_is_root(p); p = p->ci_parent) { int cur = strlen(config_item_name(p)); /* back up enough to print this bus id with '/' */ length -= cur; |
56d10194b configfs: replace... |
65 |
memcpy(buffer + length, config_item_name(p), cur); |
7063fbf22 [PATCH] configfs:... |
66 67 68 69 70 |
*(buffer + --length) = '/'; } } static int create_link(struct config_item *parent_item, |
e7515d065 configfs: Clear u... |
71 |
struct config_item *item, |
7063fbf22 [PATCH] configfs:... |
72 73 74 75 76 |
struct dentry *dentry) { struct configfs_dirent *target_sd = item->ci_dentry->d_fsdata; struct configfs_symlink *sl; int ret; |
2a109f2a4 [PATCH] configfs:... |
77 78 79 |
ret = -ENOENT; if (!configfs_dirent_is_ready(target_sd)) goto out; |
7063fbf22 [PATCH] configfs:... |
80 81 82 |
ret = -ENOMEM; sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL); if (sl) { |
5301a77da configfs: Protect... |
83 |
spin_lock(&configfs_dirent_lock); |
4768e9b18 [PATCH] configfs:... |
84 85 |
if (target_sd->s_type & CONFIGFS_USET_DROPPING) { spin_unlock(&configfs_dirent_lock); |
4768e9b18 [PATCH] configfs:... |
86 87 88 |
kfree(sl); return -ENOENT; } |
ba80aa909 configfs: Fix rac... |
89 |
sl->sl_target = config_item_get(item); |
7063fbf22 [PATCH] configfs:... |
90 |
list_add(&sl->sl_list, &target_sd->s_links); |
5301a77da configfs: Protect... |
91 |
spin_unlock(&configfs_dirent_lock); |
7063fbf22 [PATCH] configfs:... |
92 93 94 |
ret = configfs_create_link(sl, parent_item->ci_dentry, dentry); if (ret) { |
5301a77da configfs: Protect... |
95 |
spin_lock(&configfs_dirent_lock); |
7063fbf22 [PATCH] configfs:... |
96 |
list_del_init(&sl->sl_list); |
5301a77da configfs: Protect... |
97 |
spin_unlock(&configfs_dirent_lock); |
7063fbf22 [PATCH] configfs:... |
98 99 100 101 |
config_item_put(item); kfree(sl); } } |
2a109f2a4 [PATCH] configfs:... |
102 |
out: |
7063fbf22 [PATCH] configfs:... |
103 104 |
return ret; } |
421748ecd [PATCH] assorted ... |
105 |
static int get_target(const char *symname, struct path *path, |
b7c177fcd configfs: kill co... |
106 |
struct config_item **target, struct super_block *sb) |
7063fbf22 [PATCH] configfs:... |
107 108 |
{ int ret; |
421748ecd [PATCH] assorted ... |
109 |
ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path); |
7063fbf22 [PATCH] configfs:... |
110 |
if (!ret) { |
b7c177fcd configfs: kill co... |
111 |
if (path->dentry->d_sb == sb) { |
421748ecd [PATCH] assorted ... |
112 |
*target = configfs_get_config_item(path->dentry); |
7063fbf22 [PATCH] configfs:... |
113 114 |
if (!*target) { ret = -ENOENT; |
421748ecd [PATCH] assorted ... |
115 |
path_put(path); |
7063fbf22 [PATCH] configfs:... |
116 |
} |
9b6e31021 Fix configfs leak |
117 |
} else { |
7063fbf22 [PATCH] configfs:... |
118 |
ret = -EPERM; |
9b6e31021 Fix configfs leak |
119 120 |
path_put(path); } |
7063fbf22 [PATCH] configfs:... |
121 122 123 124 125 126 127 128 129 |
} return ret; } int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { int ret; |
421748ecd [PATCH] assorted ... |
130 |
struct path path; |
2a109f2a4 [PATCH] configfs:... |
131 |
struct configfs_dirent *sd; |
7063fbf22 [PATCH] configfs:... |
132 |
struct config_item *parent_item; |
3c48f23ad configfs: Fix Tri... |
133 |
struct config_item *target_item = NULL; |
7063fbf22 [PATCH] configfs:... |
134 |
struct config_item_type *type; |
2a109f2a4 [PATCH] configfs:... |
135 136 137 138 139 140 141 142 |
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; |
7063fbf22 [PATCH] configfs:... |
143 144 |
parent_item = configfs_get_config_item(dentry->d_parent); type = parent_item->ci_type; |
2a109f2a4 [PATCH] configfs:... |
145 |
ret = -EPERM; |
7063fbf22 [PATCH] configfs:... |
146 147 148 |
if (!type || !type->ct_item_ops || !type->ct_item_ops->allow_link) goto out_put; |
b7c177fcd configfs: kill co... |
149 |
ret = get_target(symname, &path, &target_item, dentry->d_sb); |
7063fbf22 [PATCH] configfs:... |
150 151 152 153 |
if (ret) goto out_put; ret = type->ct_item_ops->allow_link(parent_item, target_item); |
e75206517 configfs: call dr... |
154 |
if (!ret) { |
9a73d78cd [PATCH] configfs:... |
155 |
mutex_lock(&configfs_symlink_mutex); |
7063fbf22 [PATCH] configfs:... |
156 |
ret = create_link(parent_item, target_item, dentry); |
9a73d78cd [PATCH] configfs:... |
157 |
mutex_unlock(&configfs_symlink_mutex); |
e75206517 configfs: call dr... |
158 159 160 161 |
if (ret && type->ct_item_ops->drop_link) type->ct_item_ops->drop_link(parent_item, target_item); } |
7063fbf22 [PATCH] configfs:... |
162 163 |
config_item_put(target_item); |
421748ecd [PATCH] assorted ... |
164 |
path_put(&path); |
7063fbf22 [PATCH] configfs:... |
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
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; |
7063fbf22 [PATCH] configfs:... |
184 185 186 187 |
sl = sd->s_element; parent_item = configfs_get_config_item(dentry->d_parent); type = parent_item->ci_type; |
6f6107640 configfs: Introdu... |
188 |
spin_lock(&configfs_dirent_lock); |
7063fbf22 [PATCH] configfs:... |
189 |
list_del_init(&sd->s_sibling); |
6f6107640 configfs: Introdu... |
190 |
spin_unlock(&configfs_dirent_lock); |
7063fbf22 [PATCH] configfs:... |
191 192 193 194 195 196 197 198 199 200 201 202 203 |
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); |
5301a77da configfs: Protect... |
204 |
spin_lock(&configfs_dirent_lock); |
7063fbf22 [PATCH] configfs:... |
205 |
list_del_init(&sl->sl_list); |
5301a77da configfs: Protect... |
206 |
spin_unlock(&configfs_dirent_lock); |
7063fbf22 [PATCH] configfs:... |
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
/* Put reference from create_link() */ config_item_put(sl->sl_target); kfree(sl); config_item_put(parent_item); ret = 0; 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; |
8e24eea72 fs: replace remai... |
230 231 |
pr_debug("%s: depth = %d, size = %d ", __func__, depth, size); |
7063fbf22 [PATCH] configfs:... |
232 233 234 235 236 |
for (s = path; depth--; s += 3) strcpy(s,"../"); fill_item_path(target, path, size); |
8e24eea72 fs: replace remai... |
237 238 |
pr_debug("%s: path = '%s' ", __func__, path); |
7063fbf22 [PATCH] configfs:... |
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
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; } |
6b2553918 replace ->follow_... |
267 |
static const char *configfs_get_link(struct dentry *dentry, |
fceef393a switch ->get_link... |
268 269 |
struct inode *inode, struct delayed_call *done) |
7063fbf22 [PATCH] configfs:... |
270 |
{ |
fceef393a switch ->get_link... |
271 |
char *body; |
680baacbc new ->follow_link... |
272 |
int error; |
7063fbf22 [PATCH] configfs:... |
273 |
|
6b2553918 replace ->follow_... |
274 275 |
if (!dentry) return ERR_PTR(-ECHILD); |
fceef393a switch ->get_link... |
276 277 |
body = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!body) |
680baacbc new ->follow_link... |
278 |
return ERR_PTR(-ENOMEM); |
fceef393a switch ->get_link... |
279 |
error = configfs_getlink(dentry, body); |
680baacbc new ->follow_link... |
280 |
if (!error) { |
fceef393a switch ->get_link... |
281 282 |
set_delayed_call(done, kfree_link, body); return body; |
7063fbf22 [PATCH] configfs:... |
283 |
} |
fceef393a switch ->get_link... |
284 |
kfree(body); |
680baacbc new ->follow_link... |
285 |
return ERR_PTR(error); |
7063fbf22 [PATCH] configfs:... |
286 |
} |
754661f14 [PATCH] mark stru... |
287 |
const struct inode_operations configfs_symlink_inode_operations = { |
6b2553918 replace ->follow_... |
288 |
.get_link = configfs_get_link, |
3d0f89bb1 configfs: Add per... |
289 |
.setattr = configfs_setattr, |
7063fbf22 [PATCH] configfs:... |
290 |
}; |