blob: f5f0b936f1811b3682401cb6972399a7e41f00c5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * dir.c - Operations for sysfs directories.
3 */
4
5#undef DEBUG
6
7#include <linux/fs.h>
8#include <linux/mount.h>
9#include <linux/module.h>
10#include <linux/kobject.h>
Christoph Hellwig5f45f1a2005-06-23 00:09:12 -070011#include <linux/namei.h>
Tejun Heo2b611bb2007-06-14 03:45:13 +090012#include <linux/idr.h>
Oliver Neukum94bebf42006-12-20 10:52:44 +010013#include <asm/semaphore.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include "sysfs.h"
15
16DECLARE_RWSEM(sysfs_rename_sem);
Tejun Heodd14cbc2007-06-11 14:04:01 +090017spinlock_t sysfs_lock = SPIN_LOCK_UNLOCKED;
Tejun Heoaecdced2007-06-14 03:45:15 +090018spinlock_t kobj_sysfs_assoc_lock = SPIN_LOCK_UNLOCKED;
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
Tejun Heo2b611bb2007-06-14 03:45:13 +090020static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED;
21static DEFINE_IDA(sysfs_ino_ida);
22
Tejun Heob6b4a432007-06-14 03:45:18 +090023/**
24 * sysfs_get_active - get an active reference to sysfs_dirent
25 * @sd: sysfs_dirent to get an active reference to
26 *
27 * Get an active reference of @sd. This function is noop if @sd
28 * is NULL.
29 *
30 * RETURNS:
31 * Pointer to @sd on success, NULL on failure.
32 */
33struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd)
34{
35 if (sd) {
36 if (unlikely(!down_read_trylock(&sd->s_active)))
37 sd = NULL;
38 }
39 return sd;
40}
41
42/**
43 * sysfs_put_active - put an active reference to sysfs_dirent
44 * @sd: sysfs_dirent to put an active reference to
45 *
46 * Put an active reference to @sd. This function is noop if @sd
47 * is NULL.
48 */
49void sysfs_put_active(struct sysfs_dirent *sd)
50{
51 if (sd)
52 up_read(&sd->s_active);
53}
54
55/**
56 * sysfs_get_active_two - get active references to sysfs_dirent and parent
57 * @sd: sysfs_dirent of interest
58 *
59 * Get active reference to @sd and its parent. Parent's active
60 * reference is grabbed first. This function is noop if @sd is
61 * NULL.
62 *
63 * RETURNS:
64 * Pointer to @sd on success, NULL on failure.
65 */
66struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd)
67{
68 if (sd) {
69 if (sd->s_parent && unlikely(!sysfs_get_active(sd->s_parent)))
70 return NULL;
71 if (unlikely(!sysfs_get_active(sd))) {
72 sysfs_put_active(sd->s_parent);
73 return NULL;
74 }
75 }
76 return sd;
77}
78
79/**
80 * sysfs_put_active_two - put active references to sysfs_dirent and parent
81 * @sd: sysfs_dirent of interest
82 *
83 * Put active references to @sd and its parent. This function is
84 * noop if @sd is NULL.
85 */
86void sysfs_put_active_two(struct sysfs_dirent *sd)
87{
88 if (sd) {
89 sysfs_put_active(sd);
90 sysfs_put_active(sd->s_parent);
91 }
92}
93
94/**
95 * sysfs_deactivate - deactivate sysfs_dirent
96 * @sd: sysfs_dirent to deactivate
97 *
98 * Deny new active references and drain existing ones. s_active
99 * will be unlocked when the sysfs_dirent is released.
100 */
101void sysfs_deactivate(struct sysfs_dirent *sd)
102{
103 down_write_nested(&sd->s_active, SYSFS_S_ACTIVE_DEACTIVATE);
104
105 /* s_active will be unlocked by the thread doing the final put
106 * on @sd. Lie to lockdep.
107 */
108 rwsem_release(&sd->s_active.dep_map, 1, _RET_IP_);
109}
110
Tejun Heo42b37df2007-06-14 03:45:17 +0900111static int sysfs_alloc_ino(ino_t *pino)
Tejun Heo2b611bb2007-06-14 03:45:13 +0900112{
113 int ino, rc;
114
115 retry:
116 spin_lock(&sysfs_ino_lock);
117 rc = ida_get_new_above(&sysfs_ino_ida, 2, &ino);
118 spin_unlock(&sysfs_ino_lock);
119
120 if (rc == -EAGAIN) {
121 if (ida_pre_get(&sysfs_ino_ida, GFP_KERNEL))
122 goto retry;
123 rc = -ENOMEM;
124 }
125
126 *pino = ino;
127 return rc;
128}
129
130static void sysfs_free_ino(ino_t ino)
131{
132 spin_lock(&sysfs_ino_lock);
133 ida_remove(&sysfs_ino_ida, ino);
134 spin_unlock(&sysfs_ino_lock);
135}
136
Tejun Heofa7f9122007-06-14 03:45:13 +0900137void release_sysfs_dirent(struct sysfs_dirent * sd)
138{
Tejun Heo13b30862007-06-14 03:45:14 +0900139 struct sysfs_dirent *parent_sd;
140
141 repeat:
142 parent_sd = sd->s_parent;
143
Tejun Heo0ab66082007-06-14 03:45:16 +0900144 /* If @sd is being released after deletion, s_active is write
145 * locked. If @sd is cursor for directory walk or being
146 * released prematurely, s_active has no reader or writer.
147 *
148 * sysfs_deactivate() lies to lockdep that s_active is
149 * unlocked immediately. Lie one more time to cover the
150 * previous lie.
151 */
152 if (!down_write_trylock(&sd->s_active))
153 rwsem_acquire(&sd->s_active.dep_map,
154 SYSFS_S_ACTIVE_DEACTIVATE, 0, _RET_IP_);
155 up_write(&sd->s_active);
156
Tejun Heo3e519032007-06-14 03:45:15 +0900157 if (sd->s_type & SYSFS_KOBJ_LINK)
Tejun Heo2b29ac22007-06-14 03:45:15 +0900158 sysfs_put(sd->s_elem.symlink.target_sd);
Tejun Heo0c096b52007-06-14 03:45:15 +0900159 if (sd->s_type & SYSFS_COPY_NAME)
160 kfree(sd->s_name);
Tejun Heofa7f9122007-06-14 03:45:13 +0900161 kfree(sd->s_iattr);
Tejun Heo2b611bb2007-06-14 03:45:13 +0900162 sysfs_free_ino(sd->s_ino);
Tejun Heofa7f9122007-06-14 03:45:13 +0900163 kmem_cache_free(sysfs_dir_cachep, sd);
Tejun Heo13b30862007-06-14 03:45:14 +0900164
165 sd = parent_sd;
166 if (sd && atomic_dec_and_test(&sd->s_count))
167 goto repeat;
Tejun Heofa7f9122007-06-14 03:45:13 +0900168}
169
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
171{
172 struct sysfs_dirent * sd = dentry->d_fsdata;
173
174 if (sd) {
Tejun Heodd14cbc2007-06-11 14:04:01 +0900175 /* sd->s_dentry is protected with sysfs_lock. This
176 * allows sysfs_drop_dentry() to dereference it.
177 */
178 spin_lock(&sysfs_lock);
179
180 /* The dentry might have been deleted or another
181 * lookup could have happened updating sd->s_dentry to
182 * point the new dentry. Ignore if it isn't pointing
183 * to this dentry.
184 */
185 if (sd->s_dentry == dentry)
186 sd->s_dentry = NULL;
187 spin_unlock(&sysfs_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 sysfs_put(sd);
189 }
190 iput(inode);
191}
192
193static struct dentry_operations sysfs_dentry_ops = {
194 .d_iput = sysfs_d_iput,
195};
196
Tejun Heo3e519032007-06-14 03:45:15 +0900197struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{
Tejun Heo0c096b52007-06-14 03:45:15 +0900199 char *dup_name = NULL;
200 struct sysfs_dirent *sd = NULL;
201
202 if (type & SYSFS_COPY_NAME) {
203 name = dup_name = kstrdup(name, GFP_KERNEL);
204 if (!name)
205 goto err_out;
206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
Robert P. J. Dayc3762222007-02-10 01:45:03 -0800208 sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 if (!sd)
Tejun Heo0c096b52007-06-14 03:45:15 +0900210 goto err_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
Tejun Heo0c096b52007-06-14 03:45:15 +0900212 if (sysfs_alloc_ino(&sd->s_ino))
213 goto err_out;
Tejun Heo2b611bb2007-06-14 03:45:13 +0900214
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 atomic_set(&sd->s_count, 1);
Juha Yrjöläeea3f892006-08-03 19:06:25 +0300216 atomic_set(&sd->s_event, 1);
Tejun Heo0ab66082007-06-14 03:45:16 +0900217 init_rwsem(&sd->s_active);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 INIT_LIST_HEAD(&sd->s_children);
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700219 INIT_LIST_HEAD(&sd->s_sibling);
Tejun Heoa26cd722007-06-14 03:45:14 +0900220
Tejun Heo0c096b52007-06-14 03:45:15 +0900221 sd->s_name = name;
Tejun Heoa26cd722007-06-14 03:45:14 +0900222 sd->s_mode = mode;
223 sd->s_type = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
225 return sd;
Tejun Heo0c096b52007-06-14 03:45:15 +0900226
227 err_out:
228 kfree(dup_name);
229 kmem_cache_free(sysfs_dir_cachep, sd);
230 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231}
232
Tejun Heo198a2a82007-06-14 03:45:16 +0900233static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry)
234{
235 dentry->d_op = &sysfs_dentry_ops;
236 dentry->d_fsdata = sysfs_get(sd);
237
238 /* protect sd->s_dentry against sysfs_d_iput */
239 spin_lock(&sysfs_lock);
240 sd->s_dentry = dentry;
241 spin_unlock(&sysfs_lock);
242
243 d_rehash(dentry);
244}
245
Tejun Heoa26cd722007-06-14 03:45:14 +0900246void sysfs_attach_dirent(struct sysfs_dirent *sd,
247 struct sysfs_dirent *parent_sd, struct dentry *dentry)
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700248{
Tejun Heo198a2a82007-06-14 03:45:16 +0900249 if (dentry)
250 sysfs_attach_dentry(sd, dentry);
Tejun Heoa26cd722007-06-14 03:45:14 +0900251
Tejun Heo13b30862007-06-14 03:45:14 +0900252 if (parent_sd) {
253 sd->s_parent = sysfs_get(parent_sd);
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700254 list_add(&sd->s_sibling, &parent_sd->s_children);
Tejun Heo13b30862007-06-14 03:45:14 +0900255 }
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700256}
257
Martin Waitza5802902006-04-02 13:59:55 +0200258/*
Maneesh Sonic5168652006-03-09 19:40:14 +0530259 *
260 * Return -EEXIST if there is already a sysfs element with the same name for
261 * the same parent.
262 *
263 * called with parent inode's i_mutex held
264 */
265int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,
266 const unsigned char *new)
267{
268 struct sysfs_dirent * sd;
269
270 list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
Tejun Heo3e519032007-06-14 03:45:15 +0900271 if (sd->s_type) {
Tejun Heo0c096b52007-06-14 03:45:15 +0900272 if (strcmp(sd->s_name, new))
Maneesh Sonic5168652006-03-09 19:40:14 +0530273 continue;
274 else
275 return -EEXIST;
276 }
277 }
278
279 return 0;
280}
281
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900282static int create_dir(struct kobject *kobj, struct dentry *parent,
283 const char *name, struct dentry **p_dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284{
285 int error;
286 umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900287 struct dentry *dentry;
Tejun Heofc9f54b2007-06-14 03:45:17 +0900288 struct inode *inode;
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900289 struct sysfs_dirent *sd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900291 mutex_lock(&parent->d_inode->i_mutex);
292
Tejun Heofc9f54b2007-06-14 03:45:17 +0900293 /* allocate */
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900294 dentry = lookup_one_len(name, parent, strlen(name));
295 if (IS_ERR(dentry)) {
296 error = PTR_ERR(dentry);
297 goto out_unlock;
298 }
299
300 error = -EEXIST;
Tejun Heofc9f54b2007-06-14 03:45:17 +0900301 if (dentry->d_inode)
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900302 goto out_dput;
303
Tejun Heoa26cd722007-06-14 03:45:14 +0900304 error = -ENOMEM;
Tejun Heo3e519032007-06-14 03:45:15 +0900305 sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
Tejun Heoa26cd722007-06-14 03:45:14 +0900306 if (!sd)
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900307 goto out_drop;
Tejun Heo3e519032007-06-14 03:45:15 +0900308 sd->s_elem.dir.kobj = kobj;
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900309
Tejun Heo8312a8d2007-06-14 03:45:17 +0900310 inode = sysfs_get_inode(sd);
Tejun Heofc9f54b2007-06-14 03:45:17 +0900311 if (!inode)
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900312 goto out_sput;
313
Tejun Heo8312a8d2007-06-14 03:45:17 +0900314 if (inode->i_state & I_NEW) {
315 inode->i_op = &sysfs_dir_inode_operations;
316 inode->i_fop = &sysfs_dir_operations;
317 /* directory inodes start off with i_nlink == 2 (for ".") */
318 inc_nlink(inode);
319 }
Tejun Heofc9f54b2007-06-14 03:45:17 +0900320
321 /* link in */
322 error = -EEXIST;
323 if (sysfs_dirent_exist(parent->d_fsdata, name))
324 goto out_iput;
325
326 sysfs_instantiate(dentry, inode);
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900327 inc_nlink(parent->d_inode);
Tejun Heo198a2a82007-06-14 03:45:16 +0900328 sysfs_attach_dirent(sd, parent->d_fsdata, dentry);
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900329
330 *p_dentry = dentry;
331 error = 0;
Tejun Heofc9f54b2007-06-14 03:45:17 +0900332 goto out_unlock; /* pin directory dentry in core */
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900333
Tejun Heofc9f54b2007-06-14 03:45:17 +0900334 out_iput:
335 iput(inode);
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900336 out_sput:
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900337 sysfs_put(sd);
338 out_drop:
339 d_drop(dentry);
340 out_dput:
341 dput(dentry);
342 out_unlock:
343 mutex_unlock(&parent->d_inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 return error;
345}
346
347
348int sysfs_create_subdir(struct kobject * k, const char * n, struct dentry ** d)
349{
350 return create_dir(k,k->dentry,n,d);
351}
352
353/**
354 * sysfs_create_dir - create a directory for an object.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 * @kobj: object we're creating directory for.
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700356 * @shadow_parent: parent parent object.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 */
358
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700359int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
361 struct dentry * dentry = NULL;
362 struct dentry * parent;
363 int error = 0;
364
365 BUG_ON(!kobj);
366
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700367 if (shadow_parent)
368 parent = shadow_parent;
369 else if (kobj->parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 parent = kobj->parent->dentry;
371 else if (sysfs_mount && sysfs_mount->mnt_sb)
372 parent = sysfs_mount->mnt_sb->s_root;
373 else
374 return -EFAULT;
375
376 error = create_dir(kobj,parent,kobject_name(kobj),&dentry);
377 if (!error)
378 kobj->dentry = dentry;
379 return error;
380}
381
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
383 struct nameidata *nd)
384{
385 struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
386 struct sysfs_dirent * sd;
Tejun Heofc9f54b2007-06-14 03:45:17 +0900387 struct inode *inode;
388 int found = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
390 list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
Tejun Heofc9f54b2007-06-14 03:45:17 +0900391 if ((sd->s_type & SYSFS_NOT_PINNED) &&
392 !strcmp(sd->s_name, dentry->d_name.name)) {
393 found = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 break;
395 }
396 }
397
Tejun Heofc9f54b2007-06-14 03:45:17 +0900398 /* no such entry */
399 if (!found)
400 return NULL;
401
402 /* attach dentry and inode */
Tejun Heo8312a8d2007-06-14 03:45:17 +0900403 inode = sysfs_get_inode(sd);
Tejun Heofc9f54b2007-06-14 03:45:17 +0900404 if (!inode)
405 return ERR_PTR(-ENOMEM);
406
Tejun Heo8312a8d2007-06-14 03:45:17 +0900407 if (inode->i_state & I_NEW) {
408 /* initialize inode according to type */
409 if (sd->s_type & SYSFS_KOBJ_ATTR) {
410 inode->i_size = PAGE_SIZE;
411 inode->i_fop = &sysfs_file_operations;
412 } else if (sd->s_type & SYSFS_KOBJ_BIN_ATTR) {
413 struct bin_attribute *bin_attr =
414 sd->s_elem.bin_attr.bin_attr;
415 inode->i_size = bin_attr->size;
416 inode->i_fop = &bin_fops;
417 } else if (sd->s_type & SYSFS_KOBJ_LINK)
418 inode->i_op = &sysfs_symlink_inode_operations;
419 }
Tejun Heofc9f54b2007-06-14 03:45:17 +0900420
421 sysfs_instantiate(dentry, inode);
422 sysfs_attach_dentry(sd, dentry);
423
424 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425}
426
Arjan van de Venc5ef1c42007-02-12 00:55:40 -0800427const struct inode_operations sysfs_dir_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 .lookup = sysfs_lookup,
Maneesh Soni988d1862005-05-31 10:39:14 +0530429 .setattr = sysfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430};
431
432static void remove_dir(struct dentry * d)
433{
Tejun Heodbde0fc2007-06-14 03:45:16 +0900434 struct dentry *parent = d->d_parent;
435 struct sysfs_dirent *sd = d->d_fsdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
Jes Sorensen1b1dcc12006-01-09 15:59:24 -0800437 mutex_lock(&parent->d_inode->i_mutex);
Tejun Heodbde0fc2007-06-14 03:45:16 +0900438
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 list_del_init(&sd->s_sibling);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
441 pr_debug(" o %s removing done (%d)\n",d->d_name.name,
442 atomic_read(&d->d_count));
443
Jes Sorensen1b1dcc12006-01-09 15:59:24 -0800444 mutex_unlock(&parent->d_inode->i_mutex);
Tejun Heo0ab66082007-06-14 03:45:16 +0900445
Tejun Heodbde0fc2007-06-14 03:45:16 +0900446 sysfs_drop_dentry(sd);
Tejun Heo0ab66082007-06-14 03:45:16 +0900447 sysfs_deactivate(sd);
448 sysfs_put(sd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449}
450
451void sysfs_remove_subdir(struct dentry * d)
452{
453 remove_dir(d);
454}
455
456
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700457static void __sysfs_remove_dir(struct dentry *dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
Tejun Heo0ab66082007-06-14 03:45:16 +0900459 LIST_HEAD(removed);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 struct sysfs_dirent * parent_sd;
461 struct sysfs_dirent * sd, * tmp;
462
463 if (!dentry)
464 return;
465
466 pr_debug("sysfs %s: removing dir\n",dentry->d_name.name);
Jes Sorensen1b1dcc12006-01-09 15:59:24 -0800467 mutex_lock(&dentry->d_inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 parent_sd = dentry->d_fsdata;
469 list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {
Tejun Heo3e519032007-06-14 03:45:15 +0900470 if (!sd->s_type || !(sd->s_type & SYSFS_NOT_PINNED))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 continue;
Tejun Heo0ab66082007-06-14 03:45:16 +0900472 list_move(&sd->s_sibling, &removed);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 }
Jes Sorensen1b1dcc12006-01-09 15:59:24 -0800474 mutex_unlock(&dentry->d_inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Tejun Heo0ab66082007-06-14 03:45:16 +0900476 list_for_each_entry_safe(sd, tmp, &removed, s_sibling) {
477 list_del_init(&sd->s_sibling);
Tejun Heodbde0fc2007-06-14 03:45:16 +0900478 sysfs_drop_dentry(sd);
Tejun Heo0ab66082007-06-14 03:45:16 +0900479 sysfs_deactivate(sd);
480 sysfs_put(sd);
481 }
482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 remove_dir(dentry);
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700484}
485
486/**
487 * sysfs_remove_dir - remove an object's directory.
488 * @kobj: object.
489 *
490 * The only thing special about this is that we remove any files in
491 * the directory before we remove the directory, and we've inlined
492 * what used to be sysfs_rmdir() below, instead of calling separately.
493 */
494
495void sysfs_remove_dir(struct kobject * kobj)
496{
Tejun Heoaecdced2007-06-14 03:45:15 +0900497 struct dentry *d = kobj->dentry;
498
499 spin_lock(&kobj_sysfs_assoc_lock);
Greg Kroah-Hartman641e6f32006-03-16 15:44:26 -0800500 kobj->dentry = NULL;
Tejun Heoaecdced2007-06-14 03:45:15 +0900501 spin_unlock(&kobj_sysfs_assoc_lock);
502
503 __sysfs_remove_dir(d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504}
505
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700506int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,
507 const char *new_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
Tejun Heo0c096b52007-06-14 03:45:15 +0900509 struct sysfs_dirent *sd = kobj->dentry->d_fsdata;
510 struct sysfs_dirent *parent_sd = new_parent->d_fsdata;
511 struct dentry *new_dentry;
512 char *dup_name;
Tejun Heo996b7372007-06-14 03:45:14 +0900513 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700515 if (!new_parent)
516 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
518 down_write(&sysfs_rename_sem);
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700519 mutex_lock(&new_parent->d_inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700521 new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
Tejun Heo996b7372007-06-14 03:45:14 +0900522 if (IS_ERR(new_dentry)) {
523 error = PTR_ERR(new_dentry);
524 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 }
Tejun Heo996b7372007-06-14 03:45:14 +0900526
527 /* By allowing two different directories with the same
528 * d_parent we allow this routine to move between different
529 * shadows of the same directory
530 */
531 error = -EINVAL;
532 if (kobj->dentry->d_parent->d_inode != new_parent->d_inode ||
533 new_dentry->d_parent->d_inode != new_parent->d_inode ||
534 new_dentry == kobj->dentry)
535 goto out_dput;
536
537 error = -EEXIST;
538 if (new_dentry->d_inode)
539 goto out_dput;
540
Tejun Heo0c096b52007-06-14 03:45:15 +0900541 /* rename kobject and sysfs_dirent */
542 error = -ENOMEM;
543 new_name = dup_name = kstrdup(new_name, GFP_KERNEL);
544 if (!new_name)
Tejun Heo996b7372007-06-14 03:45:14 +0900545 goto out_drop;
546
Tejun Heo0c096b52007-06-14 03:45:15 +0900547 error = kobject_set_name(kobj, "%s", new_name);
548 if (error)
549 goto out_free;
550
551 kfree(sd->s_name);
552 sd->s_name = new_name;
553
554 /* move under the new parent */
Tejun Heo996b7372007-06-14 03:45:14 +0900555 d_add(new_dentry, NULL);
556 d_move(kobj->dentry, new_dentry);
557
Tejun Heo996b7372007-06-14 03:45:14 +0900558 list_del_init(&sd->s_sibling);
Tejun Heo7f7cfff2007-06-14 03:45:17 +0900559 sysfs_get(parent_sd);
560 sysfs_put(sd->s_parent);
561 sd->s_parent = parent_sd;
Tejun Heo996b7372007-06-14 03:45:14 +0900562 list_add(&sd->s_sibling, &parent_sd->s_children);
563
564 error = 0;
565 goto out_unlock;
566
Tejun Heo0c096b52007-06-14 03:45:15 +0900567 out_free:
568 kfree(dup_name);
Tejun Heo996b7372007-06-14 03:45:14 +0900569 out_drop:
570 d_drop(new_dentry);
571 out_dput:
572 dput(new_dentry);
573 out_unlock:
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700574 mutex_unlock(&new_parent->d_inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 up_write(&sysfs_rename_sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 return error;
577}
578
Cornelia Huck8a824722006-11-20 17:07:51 +0100579int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent)
580{
581 struct dentry *old_parent_dentry, *new_parent_dentry, *new_dentry;
582 struct sysfs_dirent *new_parent_sd, *sd;
583 int error;
584
Cornelia Huck8a824722006-11-20 17:07:51 +0100585 old_parent_dentry = kobj->parent ?
586 kobj->parent->dentry : sysfs_mount->mnt_sb->s_root;
Cornelia Huckc744aeae2007-01-08 20:16:44 +0100587 new_parent_dentry = new_parent ?
588 new_parent->dentry : sysfs_mount->mnt_sb->s_root;
Cornelia Huck8a824722006-11-20 17:07:51 +0100589
Mark Lord0de15172007-03-06 01:42:03 -0800590 if (old_parent_dentry->d_inode == new_parent_dentry->d_inode)
591 return 0; /* nothing to move */
Cornelia Huck8a824722006-11-20 17:07:51 +0100592again:
593 mutex_lock(&old_parent_dentry->d_inode->i_mutex);
594 if (!mutex_trylock(&new_parent_dentry->d_inode->i_mutex)) {
595 mutex_unlock(&old_parent_dentry->d_inode->i_mutex);
596 goto again;
597 }
598
599 new_parent_sd = new_parent_dentry->d_fsdata;
600 sd = kobj->dentry->d_fsdata;
601
602 new_dentry = lookup_one_len(kobj->name, new_parent_dentry,
603 strlen(kobj->name));
604 if (IS_ERR(new_dentry)) {
605 error = PTR_ERR(new_dentry);
606 goto out;
607 } else
608 error = 0;
609 d_add(new_dentry, NULL);
610 d_move(kobj->dentry, new_dentry);
611 dput(new_dentry);
612
613 /* Remove from old parent's list and insert into new parent's list. */
614 list_del_init(&sd->s_sibling);
Tejun Heo7f7cfff2007-06-14 03:45:17 +0900615 sysfs_get(new_parent_sd);
616 sysfs_put(sd->s_parent);
617 sd->s_parent = new_parent_sd;
Cornelia Huck8a824722006-11-20 17:07:51 +0100618 list_add(&sd->s_sibling, &new_parent_sd->s_children);
619
620out:
621 mutex_unlock(&new_parent_dentry->d_inode->i_mutex);
622 mutex_unlock(&old_parent_dentry->d_inode->i_mutex);
623
624 return error;
625}
626
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627static int sysfs_dir_open(struct inode *inode, struct file *file)
628{
Josef "Jeff" Sipekf427f5d2006-12-08 02:36:36 -0800629 struct dentry * dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 struct sysfs_dirent * parent_sd = dentry->d_fsdata;
Tejun Heoa26cd722007-06-14 03:45:14 +0900631 struct sysfs_dirent * sd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
Jes Sorensen1b1dcc12006-01-09 15:59:24 -0800633 mutex_lock(&dentry->d_inode->i_mutex);
Tejun Heo3e519032007-06-14 03:45:15 +0900634 sd = sysfs_new_dirent("_DIR_", 0, 0);
Tejun Heoa26cd722007-06-14 03:45:14 +0900635 if (sd)
636 sysfs_attach_dirent(sd, parent_sd, NULL);
Jes Sorensen1b1dcc12006-01-09 15:59:24 -0800637 mutex_unlock(&dentry->d_inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
Tejun Heoa26cd722007-06-14 03:45:14 +0900639 file->private_data = sd;
640 return sd ? 0 : -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641}
642
643static int sysfs_dir_close(struct inode *inode, struct file *file)
644{
Josef "Jeff" Sipekf427f5d2006-12-08 02:36:36 -0800645 struct dentry * dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 struct sysfs_dirent * cursor = file->private_data;
647
Jes Sorensen1b1dcc12006-01-09 15:59:24 -0800648 mutex_lock(&dentry->d_inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 list_del_init(&cursor->s_sibling);
Jes Sorensen1b1dcc12006-01-09 15:59:24 -0800650 mutex_unlock(&dentry->d_inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
652 release_sysfs_dirent(cursor);
653
654 return 0;
655}
656
657/* Relationship between s_mode and the DT_xxx types */
658static inline unsigned char dt_type(struct sysfs_dirent *sd)
659{
660 return (sd->s_mode >> 12) & 15;
661}
662
663static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
664{
Josef "Jeff" Sipekf427f5d2006-12-08 02:36:36 -0800665 struct dentry *dentry = filp->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 struct sysfs_dirent * parent_sd = dentry->d_fsdata;
667 struct sysfs_dirent *cursor = filp->private_data;
668 struct list_head *p, *q = &cursor->s_sibling;
669 ino_t ino;
670 int i = filp->f_pos;
671
672 switch (i) {
673 case 0:
Eric Sandeendc351252007-06-11 14:02:45 +0900674 ino = parent_sd->s_ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
676 break;
677 filp->f_pos++;
678 i++;
679 /* fallthrough */
680 case 1:
Tejun Heo13b30862007-06-14 03:45:14 +0900681 if (parent_sd->s_parent)
682 ino = parent_sd->s_parent->s_ino;
683 else
684 ino = parent_sd->s_ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
686 break;
687 filp->f_pos++;
688 i++;
689 /* fallthrough */
690 default:
Akinobu Mita1bfba4e2006-06-26 00:24:40 -0700691 if (filp->f_pos == 2)
692 list_move(q, &parent_sd->s_children);
693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 for (p=q->next; p!= &parent_sd->s_children; p=p->next) {
695 struct sysfs_dirent *next;
696 const char * name;
697 int len;
698
699 next = list_entry(p, struct sysfs_dirent,
700 s_sibling);
Tejun Heo3e519032007-06-14 03:45:15 +0900701 if (!next->s_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 continue;
703
Tejun Heo0c096b52007-06-14 03:45:15 +0900704 name = next->s_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 len = strlen(name);
Eric Sandeendc351252007-06-11 14:02:45 +0900706 ino = next->s_ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708 if (filldir(dirent, name, len, filp->f_pos, ino,
709 dt_type(next)) < 0)
710 return 0;
711
Akinobu Mita1bfba4e2006-06-26 00:24:40 -0700712 list_move(q, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 p = q;
714 filp->f_pos++;
715 }
716 }
717 return 0;
718}
719
720static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
721{
Josef "Jeff" Sipekf427f5d2006-12-08 02:36:36 -0800722 struct dentry * dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
Jes Sorensen1b1dcc12006-01-09 15:59:24 -0800724 mutex_lock(&dentry->d_inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 switch (origin) {
726 case 1:
727 offset += file->f_pos;
728 case 0:
729 if (offset >= 0)
730 break;
731 default:
Josef "Jeff" Sipekf427f5d2006-12-08 02:36:36 -0800732 mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 return -EINVAL;
734 }
735 if (offset != file->f_pos) {
736 file->f_pos = offset;
737 if (file->f_pos >= 2) {
738 struct sysfs_dirent *sd = dentry->d_fsdata;
739 struct sysfs_dirent *cursor = file->private_data;
740 struct list_head *p;
741 loff_t n = file->f_pos - 2;
742
743 list_del(&cursor->s_sibling);
744 p = sd->s_children.next;
745 while (n && p != &sd->s_children) {
746 struct sysfs_dirent *next;
747 next = list_entry(p, struct sysfs_dirent,
748 s_sibling);
Tejun Heo3e519032007-06-14 03:45:15 +0900749 if (next->s_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 n--;
751 p = p->next;
752 }
753 list_add_tail(&cursor->s_sibling, p);
754 }
755 }
Jes Sorensen1b1dcc12006-01-09 15:59:24 -0800756 mutex_unlock(&dentry->d_inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 return offset;
758}
759
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700760
761/**
762 * sysfs_make_shadowed_dir - Setup so a directory can be shadowed
763 * @kobj: object we're creating shadow of.
764 */
765
766int sysfs_make_shadowed_dir(struct kobject *kobj,
767 void * (*follow_link)(struct dentry *, struct nameidata *))
768{
769 struct inode *inode;
770 struct inode_operations *i_op;
771
772 inode = kobj->dentry->d_inode;
773 if (inode->i_op != &sysfs_dir_inode_operations)
774 return -EINVAL;
775
776 i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
777 if (!i_op)
778 return -ENOMEM;
779
780 memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op));
781 i_op->follow_link = follow_link;
782
783 /* Locking of inode->i_op?
784 * Since setting i_op is a single word write and they
785 * are atomic we should be ok here.
786 */
787 inode->i_op = i_op;
788 return 0;
789}
790
791/**
792 * sysfs_create_shadow_dir - create a shadow directory for an object.
793 * @kobj: object we're creating directory for.
794 *
795 * sysfs_make_shadowed_dir must already have been called on this
796 * directory.
797 */
798
799struct dentry *sysfs_create_shadow_dir(struct kobject *kobj)
800{
Tejun Heo13b30862007-06-14 03:45:14 +0900801 struct dentry *dir = kobj->dentry;
802 struct inode *inode = dir->d_inode;
803 struct dentry *parent = dir->d_parent;
804 struct sysfs_dirent *parent_sd = parent->d_fsdata;
805 struct dentry *shadow;
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700806 struct sysfs_dirent *sd;
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700807
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700808 shadow = ERR_PTR(-EINVAL);
809 if (!sysfs_is_shadowed_inode(inode))
810 goto out;
811
812 shadow = d_alloc(parent, &dir->d_name);
813 if (!shadow)
814 goto nomem;
815
Tejun Heo3e519032007-06-14 03:45:15 +0900816 sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR);
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700817 if (!sd)
818 goto nomem;
Tejun Heo3e519032007-06-14 03:45:15 +0900819 sd->s_elem.dir.kobj = kobj;
Tejun Heo13b30862007-06-14 03:45:14 +0900820 /* point to parent_sd but don't attach to it */
821 sd->s_parent = sysfs_get(parent_sd);
Tejun Heoa26cd722007-06-14 03:45:14 +0900822 sysfs_attach_dirent(sd, NULL, shadow);
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700823
824 d_instantiate(shadow, igrab(inode));
825 inc_nlink(inode);
826 inc_nlink(parent->d_inode);
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700827
828 dget(shadow); /* Extra count - pin the dentry in core */
829
830out:
831 return shadow;
832nomem:
833 dput(shadow);
834 shadow = ERR_PTR(-ENOMEM);
835 goto out;
836}
837
838/**
839 * sysfs_remove_shadow_dir - remove an object's directory.
840 * @shadow: dentry of shadow directory
841 *
842 * The only thing special about this is that we remove any files in
843 * the directory before we remove the directory, and we've inlined
844 * what used to be sysfs_rmdir() below, instead of calling separately.
845 */
846
847void sysfs_remove_shadow_dir(struct dentry *shadow)
848{
849 __sysfs_remove_dir(shadow);
850}
851
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800852const struct file_operations sysfs_dir_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 .open = sysfs_dir_open,
854 .release = sysfs_dir_close,
855 .llseek = sysfs_dir_lseek,
856 .read = generic_read_dir,
857 .readdir = sysfs_readdir,
858};