diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-11 18:24:56 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-11 18:24:56 -0500 |
commit | f58df54a54451c5feb2fdc4bc2f4fb12cf79be01 (patch) | |
tree | 930b5892717ce84de93508407ebc35757bbc5ea0 /fs | |
parent | 748e566b7e24541e05e3e70be311887a1262f2a1 (diff) | |
parent | 3589972e51fac1e02d0aaa576fa47f568cb94d40 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: (27 commits)
Driver core: fix race in dev_driver_string
Driver Core: Early platform driver buffer
sysfs: sysfs_setattr remove unnecessary permission check.
sysfs: Factor out sysfs_rename from sysfs_rename_dir and sysfs_move_dir
sysfs: Propagate renames to the vfs on demand
sysfs: Gut sysfs_addrm_start and sysfs_addrm_finish
sysfs: In sysfs_chmod_file lazily propagate the mode change.
sysfs: Implement sysfs_getattr & sysfs_permission
sysfs: Nicely indent sysfs_symlink_inode_operations
sysfs: Update s_iattr on link and unlink.
sysfs: Fix locking and factor out sysfs_sd_setattr
sysfs: Simplify iattr time assignments
sysfs: Simplify sysfs_chmod_file semantics
sysfs: Use dentry_ops instead of directly playing with the dcache
sysfs: Rename sysfs_d_iput to sysfs_dentry_iput
sysfs: Update sysfs_setxattr so it updates secdata under the sysfs_mutex
debugfs: fix create mutex racy fops and private data
Driver core: Don't remove kobjects in device_shutdown.
firmware_class: make request_firmware_nowait more useful
Driver-Core: devtmpfs - set root directory mode to 0755
...
Diffstat (limited to 'fs')
-rw-r--r-- | fs/debugfs/inode.c | 55 | ||||
-rw-r--r-- | fs/namei.c | 22 | ||||
-rw-r--r-- | fs/sysfs/dir.c | 388 | ||||
-rw-r--r-- | fs/sysfs/file.c | 41 | ||||
-rw-r--r-- | fs/sysfs/inode.c | 176 | ||||
-rw-r--r-- | fs/sysfs/symlink.c | 11 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 9 |
7 files changed, 285 insertions, 417 deletions
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 0d23b52dd22c..b486169f42bf 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -32,7 +32,9 @@ static struct vfsmount *debugfs_mount; | |||
32 | static int debugfs_mount_count; | 32 | static int debugfs_mount_count; |
33 | static bool debugfs_registered; | 33 | static bool debugfs_registered; |
34 | 34 | ||
35 | static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t dev) | 35 | static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t dev, |
36 | void *data, const struct file_operations *fops) | ||
37 | |||
36 | { | 38 | { |
37 | struct inode *inode = new_inode(sb); | 39 | struct inode *inode = new_inode(sb); |
38 | 40 | ||
@@ -44,14 +46,18 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d | |||
44 | init_special_inode(inode, mode, dev); | 46 | init_special_inode(inode, mode, dev); |
45 | break; | 47 | break; |
46 | case S_IFREG: | 48 | case S_IFREG: |
47 | inode->i_fop = &debugfs_file_operations; | 49 | inode->i_fop = fops ? fops : &debugfs_file_operations; |
50 | inode->i_private = data; | ||
48 | break; | 51 | break; |
49 | case S_IFLNK: | 52 | case S_IFLNK: |
50 | inode->i_op = &debugfs_link_operations; | 53 | inode->i_op = &debugfs_link_operations; |
54 | inode->i_fop = fops; | ||
55 | inode->i_private = data; | ||
51 | break; | 56 | break; |
52 | case S_IFDIR: | 57 | case S_IFDIR: |
53 | inode->i_op = &simple_dir_inode_operations; | 58 | inode->i_op = &simple_dir_inode_operations; |
54 | inode->i_fop = &simple_dir_operations; | 59 | inode->i_fop = fops ? fops : &simple_dir_operations; |
60 | inode->i_private = data; | ||
55 | 61 | ||
56 | /* directory inodes start off with i_nlink == 2 | 62 | /* directory inodes start off with i_nlink == 2 |
57 | * (for "." entry) */ | 63 | * (for "." entry) */ |
@@ -64,7 +70,8 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d | |||
64 | 70 | ||
65 | /* SMP-safe */ | 71 | /* SMP-safe */ |
66 | static int debugfs_mknod(struct inode *dir, struct dentry *dentry, | 72 | static int debugfs_mknod(struct inode *dir, struct dentry *dentry, |
67 | int mode, dev_t dev) | 73 | int mode, dev_t dev, void *data, |
74 | const struct file_operations *fops) | ||
68 | { | 75 | { |
69 | struct inode *inode; | 76 | struct inode *inode; |
70 | int error = -EPERM; | 77 | int error = -EPERM; |
@@ -72,7 +79,7 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry, | |||
72 | if (dentry->d_inode) | 79 | if (dentry->d_inode) |
73 | return -EEXIST; | 80 | return -EEXIST; |
74 | 81 | ||
75 | inode = debugfs_get_inode(dir->i_sb, mode, dev); | 82 | inode = debugfs_get_inode(dir->i_sb, mode, dev, data, fops); |
76 | if (inode) { | 83 | if (inode) { |
77 | d_instantiate(dentry, inode); | 84 | d_instantiate(dentry, inode); |
78 | dget(dentry); | 85 | dget(dentry); |
@@ -81,12 +88,13 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry, | |||
81 | return error; | 88 | return error; |
82 | } | 89 | } |
83 | 90 | ||
84 | static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 91 | static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode, |
92 | void *data, const struct file_operations *fops) | ||
85 | { | 93 | { |
86 | int res; | 94 | int res; |
87 | 95 | ||
88 | mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; | 96 | mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; |
89 | res = debugfs_mknod(dir, dentry, mode, 0); | 97 | res = debugfs_mknod(dir, dentry, mode, 0, data, fops); |
90 | if (!res) { | 98 | if (!res) { |
91 | inc_nlink(dir); | 99 | inc_nlink(dir); |
92 | fsnotify_mkdir(dir, dentry); | 100 | fsnotify_mkdir(dir, dentry); |
@@ -94,18 +102,20 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
94 | return res; | 102 | return res; |
95 | } | 103 | } |
96 | 104 | ||
97 | static int debugfs_link(struct inode *dir, struct dentry *dentry, int mode) | 105 | static int debugfs_link(struct inode *dir, struct dentry *dentry, int mode, |
106 | void *data, const struct file_operations *fops) | ||
98 | { | 107 | { |
99 | mode = (mode & S_IALLUGO) | S_IFLNK; | 108 | mode = (mode & S_IALLUGO) | S_IFLNK; |
100 | return debugfs_mknod(dir, dentry, mode, 0); | 109 | return debugfs_mknod(dir, dentry, mode, 0, data, fops); |
101 | } | 110 | } |
102 | 111 | ||
103 | static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode) | 112 | static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode, |
113 | void *data, const struct file_operations *fops) | ||
104 | { | 114 | { |
105 | int res; | 115 | int res; |
106 | 116 | ||
107 | mode = (mode & S_IALLUGO) | S_IFREG; | 117 | mode = (mode & S_IALLUGO) | S_IFREG; |
108 | res = debugfs_mknod(dir, dentry, mode, 0); | 118 | res = debugfs_mknod(dir, dentry, mode, 0, data, fops); |
109 | if (!res) | 119 | if (!res) |
110 | fsnotify_create(dir, dentry); | 120 | fsnotify_create(dir, dentry); |
111 | return res; | 121 | return res; |
@@ -139,7 +149,9 @@ static struct file_system_type debug_fs_type = { | |||
139 | 149 | ||
140 | static int debugfs_create_by_name(const char *name, mode_t mode, | 150 | static int debugfs_create_by_name(const char *name, mode_t mode, |
141 | struct dentry *parent, | 151 | struct dentry *parent, |
142 | struct dentry **dentry) | 152 | struct dentry **dentry, |
153 | void *data, | ||
154 | const struct file_operations *fops) | ||
143 | { | 155 | { |
144 | int error = 0; | 156 | int error = 0; |
145 | 157 | ||
@@ -164,13 +176,16 @@ static int debugfs_create_by_name(const char *name, mode_t mode, | |||
164 | if (!IS_ERR(*dentry)) { | 176 | if (!IS_ERR(*dentry)) { |
165 | switch (mode & S_IFMT) { | 177 | switch (mode & S_IFMT) { |
166 | case S_IFDIR: | 178 | case S_IFDIR: |
167 | error = debugfs_mkdir(parent->d_inode, *dentry, mode); | 179 | error = debugfs_mkdir(parent->d_inode, *dentry, mode, |
180 | data, fops); | ||
168 | break; | 181 | break; |
169 | case S_IFLNK: | 182 | case S_IFLNK: |
170 | error = debugfs_link(parent->d_inode, *dentry, mode); | 183 | error = debugfs_link(parent->d_inode, *dentry, mode, |
184 | data, fops); | ||
171 | break; | 185 | break; |
172 | default: | 186 | default: |
173 | error = debugfs_create(parent->d_inode, *dentry, mode); | 187 | error = debugfs_create(parent->d_inode, *dentry, mode, |
188 | data, fops); | ||
174 | break; | 189 | break; |
175 | } | 190 | } |
176 | dput(*dentry); | 191 | dput(*dentry); |
@@ -221,19 +236,13 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode, | |||
221 | if (error) | 236 | if (error) |
222 | goto exit; | 237 | goto exit; |
223 | 238 | ||
224 | error = debugfs_create_by_name(name, mode, parent, &dentry); | 239 | error = debugfs_create_by_name(name, mode, parent, &dentry, |
240 | data, fops); | ||
225 | if (error) { | 241 | if (error) { |
226 | dentry = NULL; | 242 | dentry = NULL; |
227 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | 243 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); |
228 | goto exit; | 244 | goto exit; |
229 | } | 245 | } |
230 | |||
231 | if (dentry->d_inode) { | ||
232 | if (data) | ||
233 | dentry->d_inode->i_private = data; | ||
234 | if (fops) | ||
235 | dentry->d_inode->i_fop = fops; | ||
236 | } | ||
237 | exit: | 246 | exit: |
238 | return dentry; | 247 | return dentry; |
239 | } | 248 | } |
diff --git a/fs/namei.c b/fs/namei.c index d11f404667e9..d3c190c35fcc 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1279,28 +1279,6 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) | |||
1279 | return __lookup_hash(&this, base, NULL); | 1279 | return __lookup_hash(&this, base, NULL); |
1280 | } | 1280 | } |
1281 | 1281 | ||
1282 | /** | ||
1283 | * lookup_one_noperm - bad hack for sysfs | ||
1284 | * @name: pathname component to lookup | ||
1285 | * @base: base directory to lookup from | ||
1286 | * | ||
1287 | * This is a variant of lookup_one_len that doesn't perform any permission | ||
1288 | * checks. It's a horrible hack to work around the braindead sysfs | ||
1289 | * architecture and should not be used anywhere else. | ||
1290 | * | ||
1291 | * DON'T USE THIS FUNCTION EVER, thanks. | ||
1292 | */ | ||
1293 | struct dentry *lookup_one_noperm(const char *name, struct dentry *base) | ||
1294 | { | ||
1295 | int err; | ||
1296 | struct qstr this; | ||
1297 | |||
1298 | err = __lookup_one_len(name, &this, base, strlen(name)); | ||
1299 | if (err) | ||
1300 | return ERR_PTR(err); | ||
1301 | return __lookup_hash(&this, base, NULL); | ||
1302 | } | ||
1303 | |||
1304 | int user_path_at(int dfd, const char __user *name, unsigned flags, | 1282 | int user_path_at(int dfd, const char __user *name, unsigned flags, |
1305 | struct path *path) | 1283 | struct path *path) |
1306 | { | 1284 | { |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index e0201837d244..f05f2303a8b8 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include "sysfs.h" | 25 | #include "sysfs.h" |
26 | 26 | ||
27 | DEFINE_MUTEX(sysfs_mutex); | 27 | DEFINE_MUTEX(sysfs_mutex); |
28 | DEFINE_MUTEX(sysfs_rename_mutex); | ||
29 | DEFINE_SPINLOCK(sysfs_assoc_lock); | 28 | DEFINE_SPINLOCK(sysfs_assoc_lock); |
30 | 29 | ||
31 | static DEFINE_SPINLOCK(sysfs_ino_lock); | 30 | static DEFINE_SPINLOCK(sysfs_ino_lock); |
@@ -85,46 +84,6 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) | |||
85 | } | 84 | } |
86 | 85 | ||
87 | /** | 86 | /** |
88 | * sysfs_get_dentry - get dentry for the given sysfs_dirent | ||
89 | * @sd: sysfs_dirent of interest | ||
90 | * | ||
91 | * Get dentry for @sd. Dentry is looked up if currently not | ||
92 | * present. This function descends from the root looking up | ||
93 | * dentry for each step. | ||
94 | * | ||
95 | * LOCKING: | ||
96 | * mutex_lock(sysfs_rename_mutex) | ||
97 | * | ||
98 | * RETURNS: | ||
99 | * Pointer to found dentry on success, ERR_PTR() value on error. | ||
100 | */ | ||
101 | struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd) | ||
102 | { | ||
103 | struct dentry *dentry = dget(sysfs_sb->s_root); | ||
104 | |||
105 | while (dentry->d_fsdata != sd) { | ||
106 | struct sysfs_dirent *cur; | ||
107 | struct dentry *parent; | ||
108 | |||
109 | /* find the first ancestor which hasn't been looked up */ | ||
110 | cur = sd; | ||
111 | while (cur->s_parent != dentry->d_fsdata) | ||
112 | cur = cur->s_parent; | ||
113 | |||
114 | /* look it up */ | ||
115 | parent = dentry; | ||
116 | mutex_lock(&parent->d_inode->i_mutex); | ||
117 | dentry = lookup_one_noperm(cur->s_name, parent); | ||
118 | mutex_unlock(&parent->d_inode->i_mutex); | ||
119 | dput(parent); | ||
120 | |||
121 | if (IS_ERR(dentry)) | ||
122 | break; | ||
123 | } | ||
124 | return dentry; | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * sysfs_get_active - get an active reference to sysfs_dirent | 87 | * sysfs_get_active - get an active reference to sysfs_dirent |
129 | * @sd: sysfs_dirent to get an active reference to | 88 | * @sd: sysfs_dirent to get an active reference to |
130 | * | 89 | * |
@@ -298,7 +257,61 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) | |||
298 | goto repeat; | 257 | goto repeat; |
299 | } | 258 | } |
300 | 259 | ||
301 | static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) | 260 | static int sysfs_dentry_delete(struct dentry *dentry) |
261 | { | ||
262 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
263 | return !!(sd->s_flags & SYSFS_FLAG_REMOVED); | ||
264 | } | ||
265 | |||
266 | static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
267 | { | ||
268 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
269 | int is_dir; | ||
270 | |||
271 | mutex_lock(&sysfs_mutex); | ||
272 | |||
273 | /* The sysfs dirent has been deleted */ | ||
274 | if (sd->s_flags & SYSFS_FLAG_REMOVED) | ||
275 | goto out_bad; | ||
276 | |||
277 | /* The sysfs dirent has been moved? */ | ||
278 | if (dentry->d_parent->d_fsdata != sd->s_parent) | ||
279 | goto out_bad; | ||
280 | |||
281 | /* The sysfs dirent has been renamed */ | ||
282 | if (strcmp(dentry->d_name.name, sd->s_name) != 0) | ||
283 | goto out_bad; | ||
284 | |||
285 | mutex_unlock(&sysfs_mutex); | ||
286 | out_valid: | ||
287 | return 1; | ||
288 | out_bad: | ||
289 | /* Remove the dentry from the dcache hashes. | ||
290 | * If this is a deleted dentry we use d_drop instead of d_delete | ||
291 | * so sysfs doesn't need to cope with negative dentries. | ||
292 | * | ||
293 | * If this is a dentry that has simply been renamed we | ||
294 | * use d_drop to remove it from the dcache lookup on its | ||
295 | * old parent. If this dentry persists later when a lookup | ||
296 | * is performed at its new name the dentry will be readded | ||
297 | * to the dcache hashes. | ||
298 | */ | ||
299 | is_dir = (sysfs_type(sd) == SYSFS_DIR); | ||
300 | mutex_unlock(&sysfs_mutex); | ||
301 | if (is_dir) { | ||
302 | /* If we have submounts we must allow the vfs caches | ||
303 | * to lie about the state of the filesystem to prevent | ||
304 | * leaks and other nasty things. | ||
305 | */ | ||
306 | if (have_submounts(dentry)) | ||
307 | goto out_valid; | ||
308 | shrink_dcache_parent(dentry); | ||
309 | } | ||
310 | d_drop(dentry); | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static void sysfs_dentry_iput(struct dentry *dentry, struct inode *inode) | ||
302 | { | 315 | { |
303 | struct sysfs_dirent * sd = dentry->d_fsdata; | 316 | struct sysfs_dirent * sd = dentry->d_fsdata; |
304 | 317 | ||
@@ -307,7 +320,9 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode) | |||
307 | } | 320 | } |
308 | 321 | ||
309 | static const struct dentry_operations sysfs_dentry_ops = { | 322 | static const struct dentry_operations sysfs_dentry_ops = { |
310 | .d_iput = sysfs_d_iput, | 323 | .d_revalidate = sysfs_dentry_revalidate, |
324 | .d_delete = sysfs_dentry_delete, | ||
325 | .d_iput = sysfs_dentry_iput, | ||
311 | }; | 326 | }; |
312 | 327 | ||
313 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | 328 | struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) |
@@ -344,12 +359,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | |||
344 | return NULL; | 359 | return NULL; |
345 | } | 360 | } |
346 | 361 | ||
347 | static int sysfs_ilookup_test(struct inode *inode, void *arg) | ||
348 | { | ||
349 | struct sysfs_dirent *sd = arg; | ||
350 | return inode->i_ino == sd->s_ino; | ||
351 | } | ||
352 | |||
353 | /** | 362 | /** |
354 | * sysfs_addrm_start - prepare for sysfs_dirent add/remove | 363 | * sysfs_addrm_start - prepare for sysfs_dirent add/remove |
355 | * @acxt: pointer to sysfs_addrm_cxt to be used | 364 | * @acxt: pointer to sysfs_addrm_cxt to be used |
@@ -357,47 +366,20 @@ static int sysfs_ilookup_test(struct inode *inode, void *arg) | |||
357 | * | 366 | * |
358 | * This function is called when the caller is about to add or | 367 | * This function is called when the caller is about to add or |
359 | * remove sysfs_dirent under @parent_sd. This function acquires | 368 | * remove sysfs_dirent under @parent_sd. This function acquires |
360 | * sysfs_mutex, grabs inode for @parent_sd if available and lock | 369 | * sysfs_mutex. @acxt is used to keep and pass context to |
361 | * i_mutex of it. @acxt is used to keep and pass context to | ||
362 | * other addrm functions. | 370 | * other addrm functions. |
363 | * | 371 | * |
364 | * LOCKING: | 372 | * LOCKING: |
365 | * Kernel thread context (may sleep). sysfs_mutex is locked on | 373 | * Kernel thread context (may sleep). sysfs_mutex is locked on |
366 | * return. i_mutex of parent inode is locked on return if | 374 | * return. |
367 | * available. | ||
368 | */ | 375 | */ |
369 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | 376 | void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, |
370 | struct sysfs_dirent *parent_sd) | 377 | struct sysfs_dirent *parent_sd) |
371 | { | 378 | { |
372 | struct inode *inode; | ||
373 | |||
374 | memset(acxt, 0, sizeof(*acxt)); | 379 | memset(acxt, 0, sizeof(*acxt)); |
375 | acxt->parent_sd = parent_sd; | 380 | acxt->parent_sd = parent_sd; |
376 | 381 | ||
377 | /* Lookup parent inode. inode initialization is protected by | ||
378 | * sysfs_mutex, so inode existence can be determined by | ||
379 | * looking up inode while holding sysfs_mutex. | ||
380 | */ | ||
381 | mutex_lock(&sysfs_mutex); | 382 | mutex_lock(&sysfs_mutex); |
382 | |||
383 | inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test, | ||
384 | parent_sd); | ||
385 | if (inode) { | ||
386 | WARN_ON(inode->i_state & I_NEW); | ||
387 | |||
388 | /* parent inode available */ | ||
389 | acxt->parent_inode = inode; | ||
390 | |||
391 | /* sysfs_mutex is below i_mutex in lock hierarchy. | ||
392 | * First, trylock i_mutex. If fails, unlock | ||
393 | * sysfs_mutex and lock them in order. | ||
394 | */ | ||
395 | if (!mutex_trylock(&inode->i_mutex)) { | ||
396 | mutex_unlock(&sysfs_mutex); | ||
397 | mutex_lock(&inode->i_mutex); | ||
398 | mutex_lock(&sysfs_mutex); | ||
399 | } | ||
400 | } | ||
401 | } | 383 | } |
402 | 384 | ||
403 | /** | 385 | /** |
@@ -422,18 +404,22 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt, | |||
422 | */ | 404 | */ |
423 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 405 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) |
424 | { | 406 | { |
407 | struct sysfs_inode_attrs *ps_iattr; | ||
408 | |||
425 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) | 409 | if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) |
426 | return -EEXIST; | 410 | return -EEXIST; |
427 | 411 | ||
428 | sd->s_parent = sysfs_get(acxt->parent_sd); | 412 | sd->s_parent = sysfs_get(acxt->parent_sd); |
429 | 413 | ||
430 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) | ||
431 | inc_nlink(acxt->parent_inode); | ||
432 | |||
433 | acxt->cnt++; | ||
434 | |||
435 | sysfs_link_sibling(sd); | 414 | sysfs_link_sibling(sd); |
436 | 415 | ||
416 | /* Update timestamps on the parent */ | ||
417 | ps_iattr = acxt->parent_sd->s_iattr; | ||
418 | if (ps_iattr) { | ||
419 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; | ||
420 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; | ||
421 | } | ||
422 | |||
437 | return 0; | 423 | return 0; |
438 | } | 424 | } |
439 | 425 | ||
@@ -512,70 +498,22 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
512 | */ | 498 | */ |
513 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | 499 | void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) |
514 | { | 500 | { |
501 | struct sysfs_inode_attrs *ps_iattr; | ||
502 | |||
515 | BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); | 503 | BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED); |
516 | 504 | ||
517 | sysfs_unlink_sibling(sd); | 505 | sysfs_unlink_sibling(sd); |
518 | 506 | ||
507 | /* Update timestamps on the parent */ | ||
508 | ps_iattr = acxt->parent_sd->s_iattr; | ||
509 | if (ps_iattr) { | ||
510 | struct iattr *ps_iattrs = &ps_iattr->ia_iattr; | ||
511 | ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; | ||
512 | } | ||
513 | |||
519 | sd->s_flags |= SYSFS_FLAG_REMOVED; | 514 | sd->s_flags |= SYSFS_FLAG_REMOVED; |
520 | sd->s_sibling = acxt->removed; | 515 | sd->s_sibling = acxt->removed; |
521 | acxt->removed = sd; | 516 | acxt->removed = sd; |
522 | |||
523 | if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode) | ||
524 | drop_nlink(acxt->parent_inode); | ||
525 | |||
526 | acxt->cnt++; | ||
527 | } | ||
528 | |||
529 | /** | ||
530 | * sysfs_drop_dentry - drop dentry for the specified sysfs_dirent | ||
531 | * @sd: target sysfs_dirent | ||
532 | * | ||
533 | * Drop dentry for @sd. @sd must have been unlinked from its | ||
534 | * parent on entry to this function such that it can't be looked | ||
535 | * up anymore. | ||
536 | */ | ||
537 | static void sysfs_drop_dentry(struct sysfs_dirent *sd) | ||
538 | { | ||
539 | struct inode *inode; | ||
540 | struct dentry *dentry; | ||
541 | |||
542 | inode = ilookup(sysfs_sb, sd->s_ino); | ||
543 | if (!inode) | ||
544 | return; | ||
545 | |||
546 | /* Drop any existing dentries associated with sd. | ||
547 | * | ||
548 | * For the dentry to be properly freed we need to grab a | ||
549 | * reference to the dentry under the dcache lock, unhash it, | ||
550 | * and then put it. The playing with the dentry count allows | ||
551 | * dput to immediately free the dentry if it is not in use. | ||
552 | */ | ||
553 | repeat: | ||
554 | spin_lock(&dcache_lock); | ||
555 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { | ||
556 | if (d_unhashed(dentry)) | ||
557 | continue; | ||
558 | dget_locked(dentry); | ||
559 | spin_lock(&dentry->d_lock); | ||
560 | __d_drop(dentry); | ||
561 | spin_unlock(&dentry->d_lock); | ||
562 | spin_unlock(&dcache_lock); | ||
563 | dput(dentry); | ||
564 | goto repeat; | ||
565 | } | ||
566 | spin_unlock(&dcache_lock); | ||
567 | |||
568 | /* adjust nlink and update timestamp */ | ||
569 | mutex_lock(&inode->i_mutex); | ||
570 | |||
571 | inode->i_ctime = CURRENT_TIME; | ||
572 | drop_nlink(inode); | ||
573 | if (sysfs_type(sd) == SYSFS_DIR) | ||
574 | drop_nlink(inode); | ||
575 | |||
576 | mutex_unlock(&inode->i_mutex); | ||
577 | |||
578 | iput(inode); | ||
579 | } | 517 | } |
580 | 518 | ||
581 | /** | 519 | /** |
@@ -584,25 +522,15 @@ repeat: | |||
584 | * | 522 | * |
585 | * Finish up sysfs_dirent add/remove. Resources acquired by | 523 | * Finish up sysfs_dirent add/remove. Resources acquired by |
586 | * sysfs_addrm_start() are released and removed sysfs_dirents are | 524 | * sysfs_addrm_start() are released and removed sysfs_dirents are |
587 | * cleaned up. Timestamps on the parent inode are updated. | 525 | * cleaned up. |
588 | * | 526 | * |
589 | * LOCKING: | 527 | * LOCKING: |
590 | * All mutexes acquired by sysfs_addrm_start() are released. | 528 | * sysfs_mutex is released. |
591 | */ | 529 | */ |
592 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | 530 | void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) |
593 | { | 531 | { |
594 | /* release resources acquired by sysfs_addrm_start() */ | 532 | /* release resources acquired by sysfs_addrm_start() */ |
595 | mutex_unlock(&sysfs_mutex); | 533 | mutex_unlock(&sysfs_mutex); |
596 | if (acxt->parent_inode) { | ||
597 | struct inode *inode = acxt->parent_inode; | ||
598 | |||
599 | /* if added/removed, update timestamps on the parent */ | ||
600 | if (acxt->cnt) | ||
601 | inode->i_ctime = inode->i_mtime = CURRENT_TIME; | ||
602 | |||
603 | mutex_unlock(&inode->i_mutex); | ||
604 | iput(inode); | ||
605 | } | ||
606 | 534 | ||
607 | /* kill removed sysfs_dirents */ | 535 | /* kill removed sysfs_dirents */ |
608 | while (acxt->removed) { | 536 | while (acxt->removed) { |
@@ -611,7 +539,6 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) | |||
611 | acxt->removed = sd->s_sibling; | 539 | acxt->removed = sd->s_sibling; |
612 | sd->s_sibling = NULL; | 540 | sd->s_sibling = NULL; |
613 | 541 | ||
614 | sysfs_drop_dentry(sd); | ||
615 | sysfs_deactivate(sd); | 542 | sysfs_deactivate(sd); |
616 | unmap_bin_file(sd); | 543 | unmap_bin_file(sd); |
617 | sysfs_put(sd); | 544 | sysfs_put(sd); |
@@ -751,10 +678,15 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
751 | } | 678 | } |
752 | 679 | ||
753 | /* instantiate and hash dentry */ | 680 | /* instantiate and hash dentry */ |
754 | dentry->d_op = &sysfs_dentry_ops; | 681 | ret = d_find_alias(inode); |
755 | dentry->d_fsdata = sysfs_get(sd); | 682 | if (!ret) { |
756 | d_instantiate(dentry, inode); | 683 | dentry->d_op = &sysfs_dentry_ops; |
757 | d_rehash(dentry); | 684 | dentry->d_fsdata = sysfs_get(sd); |
685 | d_add(dentry, inode); | ||
686 | } else { | ||
687 | d_move(ret, dentry); | ||
688 | iput(inode); | ||
689 | } | ||
758 | 690 | ||
759 | out_unlock: | 691 | out_unlock: |
760 | mutex_unlock(&sysfs_mutex); | 692 | mutex_unlock(&sysfs_mutex); |
@@ -763,7 +695,9 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
763 | 695 | ||
764 | const struct inode_operations sysfs_dir_inode_operations = { | 696 | const struct inode_operations sysfs_dir_inode_operations = { |
765 | .lookup = sysfs_lookup, | 697 | .lookup = sysfs_lookup, |
698 | .permission = sysfs_permission, | ||
766 | .setattr = sysfs_setattr, | 699 | .setattr = sysfs_setattr, |
700 | .getattr = sysfs_getattr, | ||
767 | .setxattr = sysfs_setxattr, | 701 | .setxattr = sysfs_setxattr, |
768 | }; | 702 | }; |
769 | 703 | ||
@@ -826,141 +760,65 @@ void sysfs_remove_dir(struct kobject * kobj) | |||
826 | __sysfs_remove_dir(sd); | 760 | __sysfs_remove_dir(sd); |
827 | } | 761 | } |
828 | 762 | ||
829 | int sysfs_rename_dir(struct kobject * kobj, const char *new_name) | 763 | int sysfs_rename(struct sysfs_dirent *sd, |
764 | struct sysfs_dirent *new_parent_sd, const char *new_name) | ||
830 | { | 765 | { |
831 | struct sysfs_dirent *sd = kobj->sd; | ||
832 | struct dentry *parent = NULL; | ||
833 | struct dentry *old_dentry = NULL, *new_dentry = NULL; | ||
834 | const char *dup_name = NULL; | 766 | const char *dup_name = NULL; |
835 | int error; | 767 | int error; |
836 | 768 | ||
837 | mutex_lock(&sysfs_rename_mutex); | 769 | mutex_lock(&sysfs_mutex); |
838 | 770 | ||
839 | error = 0; | 771 | error = 0; |
840 | if (strcmp(sd->s_name, new_name) == 0) | 772 | if ((sd->s_parent == new_parent_sd) && |
773 | (strcmp(sd->s_name, new_name) == 0)) | ||
841 | goto out; /* nothing to rename */ | 774 | goto out; /* nothing to rename */ |
842 | 775 | ||
843 | /* get the original dentry */ | ||
844 | old_dentry = sysfs_get_dentry(sd); | ||
845 | if (IS_ERR(old_dentry)) { | ||
846 | error = PTR_ERR(old_dentry); | ||
847 | old_dentry = NULL; | ||
848 | goto out; | ||
849 | } | ||
850 | |||
851 | parent = old_dentry->d_parent; | ||
852 | |||
853 | /* lock parent and get dentry for new name */ | ||
854 | mutex_lock(&parent->d_inode->i_mutex); | ||
855 | mutex_lock(&sysfs_mutex); | ||
856 | |||
857 | error = -EEXIST; | 776 | error = -EEXIST; |
858 | if (sysfs_find_dirent(sd->s_parent, new_name)) | 777 | if (sysfs_find_dirent(new_parent_sd, new_name)) |
859 | goto out_unlock; | 778 | goto out; |
860 | |||
861 | error = -ENOMEM; | ||
862 | new_dentry = d_alloc_name(parent, new_name); | ||
863 | if (!new_dentry) | ||
864 | goto out_unlock; | ||
865 | 779 | ||
866 | /* rename sysfs_dirent */ | 780 | /* rename sysfs_dirent */ |
867 | error = -ENOMEM; | 781 | if (strcmp(sd->s_name, new_name) != 0) { |
868 | new_name = dup_name = kstrdup(new_name, GFP_KERNEL); | 782 | error = -ENOMEM; |
869 | if (!new_name) | 783 | new_name = dup_name = kstrdup(new_name, GFP_KERNEL); |
870 | goto out_unlock; | 784 | if (!new_name) |
871 | 785 | goto out; | |
872 | dup_name = sd->s_name; | 786 | |
873 | sd->s_name = new_name; | 787 | dup_name = sd->s_name; |
788 | sd->s_name = new_name; | ||
789 | } | ||
874 | 790 | ||
875 | /* rename */ | 791 | /* Remove from old parent's list and insert into new parent's list. */ |
876 | d_add(new_dentry, NULL); | 792 | if (sd->s_parent != new_parent_sd) { |
877 | d_move(old_dentry, new_dentry); | 793 | sysfs_unlink_sibling(sd); |
794 | sysfs_get(new_parent_sd); | ||
795 | sysfs_put(sd->s_parent); | ||
796 | sd->s_parent = new_parent_sd; | ||
797 | sysfs_link_sibling(sd); | ||
798 | } | ||
878 | 799 | ||
879 | error = 0; | 800 | error = 0; |
880 | out_unlock: | 801 | out: |
881 | mutex_unlock(&sysfs_mutex); | 802 | mutex_unlock(&sysfs_mutex); |
882 | mutex_unlock(&parent->d_inode->i_mutex); | ||
883 | kfree(dup_name); | 803 | kfree(dup_name); |
884 | dput(old_dentry); | ||
885 | dput(new_dentry); | ||
886 | out: | ||
887 | mutex_unlock(&sysfs_rename_mutex); | ||
888 | return error; | 804 | return error; |
889 | } | 805 | } |
890 | 806 | ||
807 | int sysfs_rename_dir(struct kobject *kobj, const char *new_name) | ||
808 | { | ||
809 | return sysfs_rename(kobj->sd, kobj->sd->s_parent, new_name); | ||
810 | } | ||
811 | |||
891 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) | 812 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) |
892 | { | 813 | { |
893 | struct sysfs_dirent *sd = kobj->sd; | 814 | struct sysfs_dirent *sd = kobj->sd; |
894 | struct sysfs_dirent *new_parent_sd; | 815 | struct sysfs_dirent *new_parent_sd; |
895 | struct dentry *old_parent, *new_parent = NULL; | ||
896 | struct dentry *old_dentry = NULL, *new_dentry = NULL; | ||
897 | int error; | ||
898 | 816 | ||
899 | mutex_lock(&sysfs_rename_mutex); | ||
900 | BUG_ON(!sd->s_parent); | 817 | BUG_ON(!sd->s_parent); |
901 | new_parent_sd = (new_parent_kobj && new_parent_kobj->sd) ? | 818 | new_parent_sd = new_parent_kobj && new_parent_kobj->sd ? |
902 | new_parent_kobj->sd : &sysfs_root; | 819 | new_parent_kobj->sd : &sysfs_root; |
903 | 820 | ||
904 | error = 0; | 821 | return sysfs_rename(sd, new_parent_sd, sd->s_name); |
905 | if (sd->s_parent == new_parent_sd) | ||
906 | goto out; /* nothing to move */ | ||
907 | |||
908 | /* get dentries */ | ||
909 | old_dentry = sysfs_get_dentry(sd); | ||
910 | if (IS_ERR(old_dentry)) { | ||
911 | error = PTR_ERR(old_dentry); | ||
912 | old_dentry = NULL; | ||
913 | goto out; | ||
914 | } | ||
915 | old_parent = old_dentry->d_parent; | ||
916 | |||
917 | new_parent = sysfs_get_dentry(new_parent_sd); | ||
918 | if (IS_ERR(new_parent)) { | ||
919 | error = PTR_ERR(new_parent); | ||
920 | new_parent = NULL; | ||
921 | goto out; | ||
922 | } | ||
923 | |||
924 | again: | ||
925 | mutex_lock(&old_parent->d_inode->i_mutex); | ||
926 | if (!mutex_trylock(&new_parent->d_inode->i_mutex)) { | ||
927 | mutex_unlock(&old_parent->d_inode->i_mutex); | ||
928 | goto again; | ||
929 | } | ||
930 | mutex_lock(&sysfs_mutex); | ||
931 | |||
932 | error = -EEXIST; | ||
933 | if (sysfs_find_dirent(new_parent_sd, sd->s_name)) | ||
934 | goto out_unlock; | ||
935 | |||
936 | error = -ENOMEM; | ||
937 | new_dentry = d_alloc_name(new_parent, sd->s_name); | ||
938 | if (!new_dentry) | ||
939 | goto out_unlock; | ||
940 | |||
941 | error = 0; | ||
942 | d_add(new_dentry, NULL); | ||
943 | d_move(old_dentry, new_dentry); | ||
944 | |||
945 | /* Remove from old parent's list and insert into new parent's list. */ | ||
946 | sysfs_unlink_sibling(sd); | ||
947 | sysfs_get(new_parent_sd); | ||
948 | drop_nlink(old_parent->d_inode); | ||
949 | sysfs_put(sd->s_parent); | ||
950 | sd->s_parent = new_parent_sd; | ||
951 | inc_nlink(new_parent->d_inode); | ||
952 | sysfs_link_sibling(sd); | ||
953 | |||
954 | out_unlock: | ||
955 | mutex_unlock(&sysfs_mutex); | ||
956 | mutex_unlock(&new_parent->d_inode->i_mutex); | ||
957 | mutex_unlock(&old_parent->d_inode->i_mutex); | ||
958 | out: | ||
959 | dput(new_parent); | ||
960 | dput(old_dentry); | ||
961 | dput(new_dentry); | ||
962 | mutex_unlock(&sysfs_rename_mutex); | ||
963 | return error; | ||
964 | } | 822 | } |
965 | 823 | ||
966 | /* Relationship between s_mode and the DT_xxx types */ | 824 | /* Relationship between s_mode and the DT_xxx types */ |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index f5ea4680f15f..dc30d9e31683 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -579,46 +579,23 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); | |||
579 | */ | 579 | */ |
580 | int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) | 580 | int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode) |
581 | { | 581 | { |
582 | struct sysfs_dirent *victim_sd = NULL; | 582 | struct sysfs_dirent *sd; |
583 | struct dentry *victim = NULL; | ||
584 | struct inode * inode; | ||
585 | struct iattr newattrs; | 583 | struct iattr newattrs; |
586 | int rc; | 584 | int rc; |
587 | 585 | ||
588 | rc = -ENOENT; | 586 | mutex_lock(&sysfs_mutex); |
589 | victim_sd = sysfs_get_dirent(kobj->sd, attr->name); | ||
590 | if (!victim_sd) | ||
591 | goto out; | ||
592 | 587 | ||
593 | mutex_lock(&sysfs_rename_mutex); | 588 | rc = -ENOENT; |
594 | victim = sysfs_get_dentry(victim_sd); | 589 | sd = sysfs_find_dirent(kobj->sd, attr->name); |
595 | mutex_unlock(&sysfs_rename_mutex); | 590 | if (!sd) |
596 | if (IS_ERR(victim)) { | ||
597 | rc = PTR_ERR(victim); | ||
598 | victim = NULL; | ||
599 | goto out; | 591 | goto out; |
600 | } | ||
601 | |||
602 | inode = victim->d_inode; | ||
603 | |||
604 | mutex_lock(&inode->i_mutex); | ||
605 | 592 | ||
606 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); | 593 | newattrs.ia_mode = (mode & S_IALLUGO) | (sd->s_mode & ~S_IALLUGO); |
607 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | 594 | newattrs.ia_valid = ATTR_MODE; |
608 | newattrs.ia_ctime = current_fs_time(inode->i_sb); | 595 | rc = sysfs_sd_setattr(sd, &newattrs); |
609 | rc = sysfs_setattr(victim, &newattrs); | ||
610 | 596 | ||
611 | if (rc == 0) { | ||
612 | fsnotify_change(victim, newattrs.ia_valid); | ||
613 | mutex_lock(&sysfs_mutex); | ||
614 | victim_sd->s_mode = newattrs.ia_mode; | ||
615 | mutex_unlock(&sysfs_mutex); | ||
616 | } | ||
617 | |||
618 | mutex_unlock(&inode->i_mutex); | ||
619 | out: | 597 | out: |
620 | dput(victim); | 598 | mutex_unlock(&sysfs_mutex); |
621 | sysfs_put(victim_sd); | ||
622 | return rc; | 599 | return rc; |
623 | } | 600 | } |
624 | EXPORT_SYMBOL_GPL(sysfs_chmod_file); | 601 | EXPORT_SYMBOL_GPL(sysfs_chmod_file); |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index e28cecf179f5..220b758523ae 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -37,7 +37,9 @@ static struct backing_dev_info sysfs_backing_dev_info = { | |||
37 | }; | 37 | }; |
38 | 38 | ||
39 | static const struct inode_operations sysfs_inode_operations ={ | 39 | static const struct inode_operations sysfs_inode_operations ={ |
40 | .permission = sysfs_permission, | ||
40 | .setattr = sysfs_setattr, | 41 | .setattr = sysfs_setattr, |
42 | .getattr = sysfs_getattr, | ||
41 | .setxattr = sysfs_setxattr, | 43 | .setxattr = sysfs_setxattr, |
42 | }; | 44 | }; |
43 | 45 | ||
@@ -46,7 +48,7 @@ int __init sysfs_inode_init(void) | |||
46 | return bdi_init(&sysfs_backing_dev_info); | 48 | return bdi_init(&sysfs_backing_dev_info); |
47 | } | 49 | } |
48 | 50 | ||
49 | struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) | 51 | static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) |
50 | { | 52 | { |
51 | struct sysfs_inode_attrs *attrs; | 53 | struct sysfs_inode_attrs *attrs; |
52 | struct iattr *iattrs; | 54 | struct iattr *iattrs; |
@@ -64,30 +66,15 @@ struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) | |||
64 | 66 | ||
65 | return attrs; | 67 | return attrs; |
66 | } | 68 | } |
67 | int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | 69 | |
70 | int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr * iattr) | ||
68 | { | 71 | { |
69 | struct inode * inode = dentry->d_inode; | ||
70 | struct sysfs_dirent * sd = dentry->d_fsdata; | ||
71 | struct sysfs_inode_attrs *sd_attrs; | 72 | struct sysfs_inode_attrs *sd_attrs; |
72 | struct iattr *iattrs; | 73 | struct iattr *iattrs; |
73 | unsigned int ia_valid = iattr->ia_valid; | 74 | unsigned int ia_valid = iattr->ia_valid; |
74 | int error; | ||
75 | |||
76 | if (!sd) | ||
77 | return -EINVAL; | ||
78 | 75 | ||
79 | sd_attrs = sd->s_iattr; | 76 | sd_attrs = sd->s_iattr; |
80 | 77 | ||
81 | error = inode_change_ok(inode, iattr); | ||
82 | if (error) | ||
83 | return error; | ||
84 | |||
85 | iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */ | ||
86 | |||
87 | error = inode_setattr(inode, iattr); | ||
88 | if (error) | ||
89 | return error; | ||
90 | |||
91 | if (!sd_attrs) { | 78 | if (!sd_attrs) { |
92 | /* setting attributes for the first time, allocate now */ | 79 | /* setting attributes for the first time, allocate now */ |
93 | sd_attrs = sysfs_init_inode_attrs(sd); | 80 | sd_attrs = sysfs_init_inode_attrs(sd); |
@@ -103,42 +90,78 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) | |||
103 | if (ia_valid & ATTR_GID) | 90 | if (ia_valid & ATTR_GID) |
104 | iattrs->ia_gid = iattr->ia_gid; | 91 | iattrs->ia_gid = iattr->ia_gid; |
105 | if (ia_valid & ATTR_ATIME) | 92 | if (ia_valid & ATTR_ATIME) |
106 | iattrs->ia_atime = timespec_trunc(iattr->ia_atime, | 93 | iattrs->ia_atime = iattr->ia_atime; |
107 | inode->i_sb->s_time_gran); | ||
108 | if (ia_valid & ATTR_MTIME) | 94 | if (ia_valid & ATTR_MTIME) |
109 | iattrs->ia_mtime = timespec_trunc(iattr->ia_mtime, | 95 | iattrs->ia_mtime = iattr->ia_mtime; |
110 | inode->i_sb->s_time_gran); | ||
111 | if (ia_valid & ATTR_CTIME) | 96 | if (ia_valid & ATTR_CTIME) |
112 | iattrs->ia_ctime = timespec_trunc(iattr->ia_ctime, | 97 | iattrs->ia_ctime = iattr->ia_ctime; |
113 | inode->i_sb->s_time_gran); | ||
114 | if (ia_valid & ATTR_MODE) { | 98 | if (ia_valid & ATTR_MODE) { |
115 | umode_t mode = iattr->ia_mode; | 99 | umode_t mode = iattr->ia_mode; |
116 | |||
117 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | ||
118 | mode &= ~S_ISGID; | ||
119 | iattrs->ia_mode = sd->s_mode = mode; | 100 | iattrs->ia_mode = sd->s_mode = mode; |
120 | } | 101 | } |
121 | } | 102 | } |
103 | return 0; | ||
104 | } | ||
105 | |||
106 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr) | ||
107 | { | ||
108 | struct inode *inode = dentry->d_inode; | ||
109 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
110 | int error; | ||
111 | |||
112 | if (!sd) | ||
113 | return -EINVAL; | ||
114 | |||
115 | error = inode_change_ok(inode, iattr); | ||
116 | if (error) | ||
117 | return error; | ||
118 | |||
119 | iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */ | ||
120 | |||
121 | error = inode_setattr(inode, iattr); | ||
122 | if (error) | ||
123 | return error; | ||
124 | |||
125 | mutex_lock(&sysfs_mutex); | ||
126 | error = sysfs_sd_setattr(sd, iattr); | ||
127 | mutex_unlock(&sysfs_mutex); | ||
128 | |||
122 | return error; | 129 | return error; |
123 | } | 130 | } |
124 | 131 | ||
132 | static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata, u32 *secdata_len) | ||
133 | { | ||
134 | struct sysfs_inode_attrs *iattrs; | ||
135 | void *old_secdata; | ||
136 | size_t old_secdata_len; | ||
137 | |||
138 | iattrs = sd->s_iattr; | ||
139 | if (!iattrs) | ||
140 | iattrs = sysfs_init_inode_attrs(sd); | ||
141 | if (!iattrs) | ||
142 | return -ENOMEM; | ||
143 | |||
144 | old_secdata = iattrs->ia_secdata; | ||
145 | old_secdata_len = iattrs->ia_secdata_len; | ||
146 | |||
147 | iattrs->ia_secdata = *secdata; | ||
148 | iattrs->ia_secdata_len = *secdata_len; | ||
149 | |||
150 | *secdata = old_secdata; | ||
151 | *secdata_len = old_secdata_len; | ||
152 | return 0; | ||
153 | } | ||
154 | |||
125 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 155 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
126 | size_t size, int flags) | 156 | size_t size, int flags) |
127 | { | 157 | { |
128 | struct sysfs_dirent *sd = dentry->d_fsdata; | 158 | struct sysfs_dirent *sd = dentry->d_fsdata; |
129 | struct sysfs_inode_attrs *iattrs; | ||
130 | void *secdata; | 159 | void *secdata; |
131 | int error; | 160 | int error; |
132 | u32 secdata_len = 0; | 161 | u32 secdata_len = 0; |
133 | 162 | ||
134 | if (!sd) | 163 | if (!sd) |
135 | return -EINVAL; | 164 | return -EINVAL; |
136 | if (!sd->s_iattr) | ||
137 | sd->s_iattr = sysfs_init_inode_attrs(sd); | ||
138 | if (!sd->s_iattr) | ||
139 | return -ENOMEM; | ||
140 | |||
141 | iattrs = sd->s_iattr; | ||
142 | 165 | ||
143 | if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { | 166 | if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) { |
144 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; | 167 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; |
@@ -150,12 +173,13 @@ int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | |||
150 | &secdata, &secdata_len); | 173 | &secdata, &secdata_len); |
151 | if (error) | 174 | if (error) |
152 | goto out; | 175 | goto out; |
153 | if (iattrs->ia_secdata) | ||
154 | security_release_secctx(iattrs->ia_secdata, | ||
155 | iattrs->ia_secdata_len); | ||
156 | iattrs->ia_secdata = secdata; | ||
157 | iattrs->ia_secdata_len = secdata_len; | ||
158 | 176 | ||
177 | mutex_lock(&sysfs_mutex); | ||
178 | error = sysfs_sd_setsecdata(sd, &secdata, &secdata_len); | ||
179 | mutex_unlock(&sysfs_mutex); | ||
180 | |||
181 | if (secdata) | ||
182 | security_release_secctx(secdata, secdata_len); | ||
159 | } else | 183 | } else |
160 | return -EINVAL; | 184 | return -EINVAL; |
161 | out: | 185 | out: |
@@ -170,7 +194,6 @@ static inline void set_default_inode_attr(struct inode * inode, mode_t mode) | |||
170 | 194 | ||
171 | static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | 195 | static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) |
172 | { | 196 | { |
173 | inode->i_mode = iattr->ia_mode; | ||
174 | inode->i_uid = iattr->ia_uid; | 197 | inode->i_uid = iattr->ia_uid; |
175 | inode->i_gid = iattr->ia_gid; | 198 | inode->i_gid = iattr->ia_gid; |
176 | inode->i_atime = iattr->ia_atime; | 199 | inode->i_atime = iattr->ia_atime; |
@@ -178,17 +201,6 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) | |||
178 | inode->i_ctime = iattr->ia_ctime; | 201 | inode->i_ctime = iattr->ia_ctime; |
179 | } | 202 | } |
180 | 203 | ||
181 | |||
182 | /* | ||
183 | * sysfs has a different i_mutex lock order behavior for i_mutex than other | ||
184 | * filesystems; sysfs i_mutex is called in many places with subsystem locks | ||
185 | * held. At the same time, many of the VFS locking rules do not apply to | ||
186 | * sysfs at all (cross directory rename for example). To untangle this mess | ||
187 | * (which gives false positives in lockdep), we're giving sysfs inodes their | ||
188 | * own class for i_mutex. | ||
189 | */ | ||
190 | static struct lock_class_key sysfs_inode_imutex_key; | ||
191 | |||
192 | static int sysfs_count_nlink(struct sysfs_dirent *sd) | 204 | static int sysfs_count_nlink(struct sysfs_dirent *sd) |
193 | { | 205 | { |
194 | struct sysfs_dirent *child; | 206 | struct sysfs_dirent *child; |
@@ -201,38 +213,55 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd) | |||
201 | return nr + 2; | 213 | return nr + 2; |
202 | } | 214 | } |
203 | 215 | ||
216 | static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode) | ||
217 | { | ||
218 | struct sysfs_inode_attrs *iattrs = sd->s_iattr; | ||
219 | |||
220 | inode->i_mode = sd->s_mode; | ||
221 | if (iattrs) { | ||
222 | /* sysfs_dirent has non-default attributes | ||
223 | * get them from persistent copy in sysfs_dirent | ||
224 | */ | ||
225 | set_inode_attr(inode, &iattrs->ia_iattr); | ||
226 | security_inode_notifysecctx(inode, | ||
227 | iattrs->ia_secdata, | ||
228 | iattrs->ia_secdata_len); | ||
229 | } | ||
230 | |||
231 | if (sysfs_type(sd) == SYSFS_DIR) | ||
232 | inode->i_nlink = sysfs_count_nlink(sd); | ||
233 | } | ||
234 | |||
235 | int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | ||
236 | { | ||
237 | struct sysfs_dirent *sd = dentry->d_fsdata; | ||
238 | struct inode *inode = dentry->d_inode; | ||
239 | |||
240 | mutex_lock(&sysfs_mutex); | ||
241 | sysfs_refresh_inode(sd, inode); | ||
242 | mutex_unlock(&sysfs_mutex); | ||
243 | |||
244 | generic_fillattr(inode, stat); | ||
245 | return 0; | ||
246 | } | ||
247 | |||
204 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) | 248 | static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) |
205 | { | 249 | { |
206 | struct bin_attribute *bin_attr; | 250 | struct bin_attribute *bin_attr; |
207 | struct sysfs_inode_attrs *iattrs; | ||
208 | 251 | ||
209 | inode->i_private = sysfs_get(sd); | 252 | inode->i_private = sysfs_get(sd); |
210 | inode->i_mapping->a_ops = &sysfs_aops; | 253 | inode->i_mapping->a_ops = &sysfs_aops; |
211 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; | 254 | inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; |
212 | inode->i_op = &sysfs_inode_operations; | 255 | inode->i_op = &sysfs_inode_operations; |
213 | inode->i_ino = sd->s_ino; | ||
214 | lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key); | ||
215 | 256 | ||
216 | iattrs = sd->s_iattr; | 257 | set_default_inode_attr(inode, sd->s_mode); |
217 | if (iattrs) { | 258 | sysfs_refresh_inode(sd, inode); |
218 | /* sysfs_dirent has non-default attributes | ||
219 | * get them for the new inode from persistent copy | ||
220 | * in sysfs_dirent | ||
221 | */ | ||
222 | set_inode_attr(inode, &iattrs->ia_iattr); | ||
223 | if (iattrs->ia_secdata) | ||
224 | security_inode_notifysecctx(inode, | ||
225 | iattrs->ia_secdata, | ||
226 | iattrs->ia_secdata_len); | ||
227 | } else | ||
228 | set_default_inode_attr(inode, sd->s_mode); | ||
229 | 259 | ||
230 | /* initialize inode according to type */ | 260 | /* initialize inode according to type */ |
231 | switch (sysfs_type(sd)) { | 261 | switch (sysfs_type(sd)) { |
232 | case SYSFS_DIR: | 262 | case SYSFS_DIR: |
233 | inode->i_op = &sysfs_dir_inode_operations; | 263 | inode->i_op = &sysfs_dir_inode_operations; |
234 | inode->i_fop = &sysfs_dir_operations; | 264 | inode->i_fop = &sysfs_dir_operations; |
235 | inode->i_nlink = sysfs_count_nlink(sd); | ||
236 | break; | 265 | break; |
237 | case SYSFS_KOBJ_ATTR: | 266 | case SYSFS_KOBJ_ATTR: |
238 | inode->i_size = PAGE_SIZE; | 267 | inode->i_size = PAGE_SIZE; |
@@ -315,3 +344,14 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) | |||
315 | else | 344 | else |
316 | return -ENOENT; | 345 | return -ENOENT; |
317 | } | 346 | } |
347 | |||
348 | int sysfs_permission(struct inode *inode, int mask) | ||
349 | { | ||
350 | struct sysfs_dirent *sd = inode->i_private; | ||
351 | |||
352 | mutex_lock(&sysfs_mutex); | ||
353 | sysfs_refresh_inode(sd, inode); | ||
354 | mutex_unlock(&sysfs_mutex); | ||
355 | |||
356 | return generic_permission(inode, mask, NULL); | ||
357 | } | ||
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index c5081ad77026..c5eff49fa41b 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -210,10 +210,13 @@ static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *co | |||
210 | } | 210 | } |
211 | 211 | ||
212 | const struct inode_operations sysfs_symlink_inode_operations = { | 212 | const struct inode_operations sysfs_symlink_inode_operations = { |
213 | .setxattr = sysfs_setxattr, | 213 | .setxattr = sysfs_setxattr, |
214 | .readlink = generic_readlink, | 214 | .readlink = generic_readlink, |
215 | .follow_link = sysfs_follow_link, | 215 | .follow_link = sysfs_follow_link, |
216 | .put_link = sysfs_put_link, | 216 | .put_link = sysfs_put_link, |
217 | .setattr = sysfs_setattr, | ||
218 | .getattr = sysfs_getattr, | ||
219 | .permission = sysfs_permission, | ||
217 | }; | 220 | }; |
218 | 221 | ||
219 | 222 | ||
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index af4c4e7482ac..ca52e7b9d8f8 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -89,9 +89,7 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd) | |||
89 | */ | 89 | */ |
90 | struct sysfs_addrm_cxt { | 90 | struct sysfs_addrm_cxt { |
91 | struct sysfs_dirent *parent_sd; | 91 | struct sysfs_dirent *parent_sd; |
92 | struct inode *parent_inode; | ||
93 | struct sysfs_dirent *removed; | 92 | struct sysfs_dirent *removed; |
94 | int cnt; | ||
95 | }; | 93 | }; |
96 | 94 | ||
97 | /* | 95 | /* |
@@ -105,7 +103,6 @@ extern struct kmem_cache *sysfs_dir_cachep; | |||
105 | * dir.c | 103 | * dir.c |
106 | */ | 104 | */ |
107 | extern struct mutex sysfs_mutex; | 105 | extern struct mutex sysfs_mutex; |
108 | extern struct mutex sysfs_rename_mutex; | ||
109 | extern spinlock_t sysfs_assoc_lock; | 106 | extern spinlock_t sysfs_assoc_lock; |
110 | 107 | ||
111 | extern const struct file_operations sysfs_dir_operations; | 108 | extern const struct file_operations sysfs_dir_operations; |
@@ -133,6 +130,9 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, | |||
133 | struct sysfs_dirent **p_sd); | 130 | struct sysfs_dirent **p_sd); |
134 | void sysfs_remove_subdir(struct sysfs_dirent *sd); | 131 | void sysfs_remove_subdir(struct sysfs_dirent *sd); |
135 | 132 | ||
133 | int sysfs_rename(struct sysfs_dirent *sd, | ||
134 | struct sysfs_dirent *new_parent_sd, const char *new_name); | ||
135 | |||
136 | static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) | 136 | static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) |
137 | { | 137 | { |
138 | if (sd) { | 138 | if (sd) { |
@@ -155,7 +155,10 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) | |||
155 | */ | 155 | */ |
156 | struct inode *sysfs_get_inode(struct sysfs_dirent *sd); | 156 | struct inode *sysfs_get_inode(struct sysfs_dirent *sd); |
157 | void sysfs_delete_inode(struct inode *inode); | 157 | void sysfs_delete_inode(struct inode *inode); |
158 | int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr); | ||
159 | int sysfs_permission(struct inode *inode, int mask); | ||
158 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); | 160 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); |
161 | int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); | ||
159 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 162 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
160 | size_t size, int flags); | 163 | size_t size, int flags); |
161 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); | 164 | int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); |