blob: 9fc8558fd86c083c2e00b5a11f2f6fc8f399482a [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>
Tejun Heo8619f972007-06-14 03:45:18 +090013#include <linux/completion.h>
Oliver Neukum94bebf42006-12-20 10:52:44 +010014#include <asm/semaphore.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include "sysfs.h"
16
Tejun Heo3007e992007-06-14 04:27:23 +090017DEFINE_MUTEX(sysfs_mutex);
Tejun Heo5f995322007-06-14 04:27:23 +090018spinlock_t 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/**
Tejun Heo0c73f182007-06-14 03:45:18 +090024 * sysfs_link_sibling - link sysfs_dirent into sibling list
25 * @sd: sysfs_dirent of interest
26 *
27 * Link @sd into its sibling list which starts from
28 * sd->s_parent->s_children.
29 *
30 * Locking:
Tejun Heo3007e992007-06-14 04:27:23 +090031 * mutex_lock(sysfs_mutex)
Tejun Heo0c73f182007-06-14 03:45:18 +090032 */
33static void sysfs_link_sibling(struct sysfs_dirent *sd)
34{
35 struct sysfs_dirent *parent_sd = sd->s_parent;
36
37 BUG_ON(sd->s_sibling);
38 sd->s_sibling = parent_sd->s_children;
39 parent_sd->s_children = sd;
40}
41
42/**
43 * sysfs_unlink_sibling - unlink sysfs_dirent from sibling list
44 * @sd: sysfs_dirent of interest
45 *
46 * Unlink @sd from its sibling list which starts from
47 * sd->s_parent->s_children.
48 *
49 * Locking:
Tejun Heo3007e992007-06-14 04:27:23 +090050 * mutex_lock(sysfs_mutex)
Tejun Heo0c73f182007-06-14 03:45:18 +090051 */
52static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
53{
54 struct sysfs_dirent **pos;
55
56 for (pos = &sd->s_parent->s_children; *pos; pos = &(*pos)->s_sibling) {
57 if (*pos == sd) {
58 *pos = sd->s_sibling;
59 sd->s_sibling = NULL;
60 break;
61 }
62 }
63}
64
65/**
Tejun Heob6b4a432007-06-14 03:45:18 +090066 * sysfs_get_active - get an active reference to sysfs_dirent
67 * @sd: sysfs_dirent to get an active reference to
68 *
69 * Get an active reference of @sd. This function is noop if @sd
70 * is NULL.
71 *
72 * RETURNS:
73 * Pointer to @sd on success, NULL on failure.
74 */
75struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd)
76{
Tejun Heo8619f972007-06-14 03:45:18 +090077 if (unlikely(!sd))
78 return NULL;
79
80 while (1) {
81 int v, t;
82
83 v = atomic_read(&sd->s_active);
84 if (unlikely(v < 0))
85 return NULL;
86
87 t = atomic_cmpxchg(&sd->s_active, v, v + 1);
88 if (likely(t == v))
89 return sd;
90 if (t < 0)
91 return NULL;
92
93 cpu_relax();
Tejun Heob6b4a432007-06-14 03:45:18 +090094 }
Tejun Heob6b4a432007-06-14 03:45:18 +090095}
96
97/**
98 * sysfs_put_active - put an active reference to sysfs_dirent
99 * @sd: sysfs_dirent to put an active reference to
100 *
101 * Put an active reference to @sd. This function is noop if @sd
102 * is NULL.
103 */
104void sysfs_put_active(struct sysfs_dirent *sd)
105{
Tejun Heo8619f972007-06-14 03:45:18 +0900106 struct completion *cmpl;
107 int v;
108
109 if (unlikely(!sd))
110 return;
111
112 v = atomic_dec_return(&sd->s_active);
113 if (likely(v != SD_DEACTIVATED_BIAS))
114 return;
115
116 /* atomic_dec_return() is a mb(), we'll always see the updated
Tejun Heo0c73f182007-06-14 03:45:18 +0900117 * sd->s_sibling.
Tejun Heo8619f972007-06-14 03:45:18 +0900118 */
Tejun Heo0c73f182007-06-14 03:45:18 +0900119 cmpl = (void *)sd->s_sibling;
Tejun Heo8619f972007-06-14 03:45:18 +0900120 complete(cmpl);
Tejun Heob6b4a432007-06-14 03:45:18 +0900121}
122
123/**
124 * sysfs_get_active_two - get active references to sysfs_dirent and parent
125 * @sd: sysfs_dirent of interest
126 *
127 * Get active reference to @sd and its parent. Parent's active
128 * reference is grabbed first. This function is noop if @sd is
129 * NULL.
130 *
131 * RETURNS:
132 * Pointer to @sd on success, NULL on failure.
133 */
134struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd)
135{
136 if (sd) {
137 if (sd->s_parent && unlikely(!sysfs_get_active(sd->s_parent)))
138 return NULL;
139 if (unlikely(!sysfs_get_active(sd))) {
140 sysfs_put_active(sd->s_parent);
141 return NULL;
142 }
143 }
144 return sd;
145}
146
147/**
148 * sysfs_put_active_two - put active references to sysfs_dirent and parent
149 * @sd: sysfs_dirent of interest
150 *
151 * Put active references to @sd and its parent. This function is
152 * noop if @sd is NULL.
153 */
154void sysfs_put_active_two(struct sysfs_dirent *sd)
155{
156 if (sd) {
157 sysfs_put_active(sd);
158 sysfs_put_active(sd->s_parent);
159 }
160}
161
162/**
163 * sysfs_deactivate - deactivate sysfs_dirent
164 * @sd: sysfs_dirent to deactivate
165 *
Tejun Heo8619f972007-06-14 03:45:18 +0900166 * Deny new active references and drain existing ones.
Tejun Heob6b4a432007-06-14 03:45:18 +0900167 */
168void sysfs_deactivate(struct sysfs_dirent *sd)
169{
Tejun Heo8619f972007-06-14 03:45:18 +0900170 DECLARE_COMPLETION_ONSTACK(wait);
171 int v;
Tejun Heob6b4a432007-06-14 03:45:18 +0900172
Tejun Heo380e6fb2007-06-14 04:27:22 +0900173 BUG_ON(sd->s_sibling || !(sd->s_flags & SYSFS_FLAG_REMOVED));
Tejun Heo0c73f182007-06-14 03:45:18 +0900174 sd->s_sibling = (void *)&wait;
Tejun Heo8619f972007-06-14 03:45:18 +0900175
176 /* atomic_add_return() is a mb(), put_active() will always see
Tejun Heo0c73f182007-06-14 03:45:18 +0900177 * the updated sd->s_sibling.
Tejun Heob6b4a432007-06-14 03:45:18 +0900178 */
Tejun Heo8619f972007-06-14 03:45:18 +0900179 v = atomic_add_return(SD_DEACTIVATED_BIAS, &sd->s_active);
180
181 if (v != SD_DEACTIVATED_BIAS)
182 wait_for_completion(&wait);
183
Tejun Heo0c73f182007-06-14 03:45:18 +0900184 sd->s_sibling = NULL;
Tejun Heob6b4a432007-06-14 03:45:18 +0900185}
186
Tejun Heo42b37df2007-06-14 03:45:17 +0900187static int sysfs_alloc_ino(ino_t *pino)
Tejun Heo2b611bb2007-06-14 03:45:13 +0900188{
189 int ino, rc;
190
191 retry:
192 spin_lock(&sysfs_ino_lock);
193 rc = ida_get_new_above(&sysfs_ino_ida, 2, &ino);
194 spin_unlock(&sysfs_ino_lock);
195
196 if (rc == -EAGAIN) {
197 if (ida_pre_get(&sysfs_ino_ida, GFP_KERNEL))
198 goto retry;
199 rc = -ENOMEM;
200 }
201
202 *pino = ino;
203 return rc;
204}
205
206static void sysfs_free_ino(ino_t ino)
207{
208 spin_lock(&sysfs_ino_lock);
209 ida_remove(&sysfs_ino_ida, ino);
210 spin_unlock(&sysfs_ino_lock);
211}
212
Tejun Heofa7f9122007-06-14 03:45:13 +0900213void release_sysfs_dirent(struct sysfs_dirent * sd)
214{
Tejun Heo13b30862007-06-14 03:45:14 +0900215 struct sysfs_dirent *parent_sd;
216
217 repeat:
Tejun Heo3007e992007-06-14 04:27:23 +0900218 /* Moving/renaming is always done while holding reference.
219 * sd->s_parent won't change beneath us.
220 */
Tejun Heo13b30862007-06-14 03:45:14 +0900221 parent_sd = sd->s_parent;
222
Tejun Heob402d722007-06-14 04:27:21 +0900223 if (sysfs_type(sd) == SYSFS_KOBJ_LINK)
Tejun Heo2b29ac22007-06-14 03:45:15 +0900224 sysfs_put(sd->s_elem.symlink.target_sd);
Tejun Heob402d722007-06-14 04:27:21 +0900225 if (sysfs_type(sd) & SYSFS_COPY_NAME)
Tejun Heo0c096b52007-06-14 03:45:15 +0900226 kfree(sd->s_name);
Tejun Heofa7f9122007-06-14 03:45:13 +0900227 kfree(sd->s_iattr);
Tejun Heo2b611bb2007-06-14 03:45:13 +0900228 sysfs_free_ino(sd->s_ino);
Tejun Heofa7f9122007-06-14 03:45:13 +0900229 kmem_cache_free(sysfs_dir_cachep, sd);
Tejun Heo13b30862007-06-14 03:45:14 +0900230
231 sd = parent_sd;
232 if (sd && atomic_dec_and_test(&sd->s_count))
233 goto repeat;
Tejun Heofa7f9122007-06-14 03:45:13 +0900234}
235
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
237{
238 struct sysfs_dirent * sd = dentry->d_fsdata;
239
240 if (sd) {
Tejun Heo5f995322007-06-14 04:27:23 +0900241 /* sd->s_dentry is protected with sysfs_assoc_lock.
242 * This allows sysfs_drop_dentry() to dereference it.
Tejun Heodd14cbc2007-06-11 14:04:01 +0900243 */
Tejun Heo5f995322007-06-14 04:27:23 +0900244 spin_lock(&sysfs_assoc_lock);
Tejun Heodd14cbc2007-06-11 14:04:01 +0900245
246 /* The dentry might have been deleted or another
247 * lookup could have happened updating sd->s_dentry to
248 * point the new dentry. Ignore if it isn't pointing
249 * to this dentry.
250 */
251 if (sd->s_dentry == dentry)
252 sd->s_dentry = NULL;
Tejun Heo5f995322007-06-14 04:27:23 +0900253 spin_unlock(&sysfs_assoc_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 sysfs_put(sd);
255 }
256 iput(inode);
257}
258
259static struct dentry_operations sysfs_dentry_ops = {
260 .d_iput = sysfs_d_iput,
261};
262
Tejun Heo3e519032007-06-14 03:45:15 +0900263struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
Tejun Heo0c096b52007-06-14 03:45:15 +0900265 char *dup_name = NULL;
266 struct sysfs_dirent *sd = NULL;
267
268 if (type & SYSFS_COPY_NAME) {
269 name = dup_name = kstrdup(name, GFP_KERNEL);
270 if (!name)
271 goto err_out;
272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Robert P. J. Dayc3762222007-02-10 01:45:03 -0800274 sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 if (!sd)
Tejun Heo0c096b52007-06-14 03:45:15 +0900276 goto err_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
Tejun Heo0c096b52007-06-14 03:45:15 +0900278 if (sysfs_alloc_ino(&sd->s_ino))
279 goto err_out;
Tejun Heo2b611bb2007-06-14 03:45:13 +0900280
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 atomic_set(&sd->s_count, 1);
Tejun Heo8619f972007-06-14 03:45:18 +0900282 atomic_set(&sd->s_active, 0);
Juha Yrjöläeea3f892006-08-03 19:06:25 +0300283 atomic_set(&sd->s_event, 1);
Tejun Heoa26cd722007-06-14 03:45:14 +0900284
Tejun Heo0c096b52007-06-14 03:45:15 +0900285 sd->s_name = name;
Tejun Heoa26cd722007-06-14 03:45:14 +0900286 sd->s_mode = mode;
Tejun Heob402d722007-06-14 04:27:21 +0900287 sd->s_flags = type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
289 return sd;
Tejun Heo0c096b52007-06-14 03:45:15 +0900290
291 err_out:
292 kfree(dup_name);
293 kmem_cache_free(sysfs_dir_cachep, sd);
294 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295}
296
Tejun Heo3007e992007-06-14 04:27:23 +0900297/**
298 * sysfs_attach_dentry - associate sysfs_dirent with dentry
299 * @sd: target sysfs_dirent
300 * @dentry: dentry to associate
301 *
302 * Associate @sd with @dentry. This is protected by
303 * sysfs_assoc_lock to avoid race with sysfs_d_iput().
304 *
305 * LOCKING:
306 * mutex_lock(sysfs_mutex)
307 */
Tejun Heo198a2a82007-06-14 03:45:16 +0900308static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry)
309{
310 dentry->d_op = &sysfs_dentry_ops;
311 dentry->d_fsdata = sysfs_get(sd);
312
313 /* protect sd->s_dentry against sysfs_d_iput */
Tejun Heo5f995322007-06-14 04:27:23 +0900314 spin_lock(&sysfs_assoc_lock);
Tejun Heo198a2a82007-06-14 03:45:16 +0900315 sd->s_dentry = dentry;
Tejun Heo5f995322007-06-14 04:27:23 +0900316 spin_unlock(&sysfs_assoc_lock);
Tejun Heo198a2a82007-06-14 03:45:16 +0900317
318 d_rehash(dentry);
319}
320
Tejun Heo3007e992007-06-14 04:27:23 +0900321/**
322 * sysfs_attach_dirent - attach sysfs_dirent to its parent and dentry
323 * @sd: sysfs_dirent to attach
324 * @parent_sd: parent to attach to (optional)
325 * @dentry: dentry to be associated to @sd (optional)
326 *
327 * Attach @sd to @parent_sd and/or @dentry. Both are optional.
328 *
329 * LOCKING:
330 * mutex_lock(sysfs_mutex)
331 */
Tejun Heoa26cd722007-06-14 03:45:14 +0900332void sysfs_attach_dirent(struct sysfs_dirent *sd,
333 struct sysfs_dirent *parent_sd, struct dentry *dentry)
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700334{
Tejun Heo198a2a82007-06-14 03:45:16 +0900335 if (dentry)
336 sysfs_attach_dentry(sd, dentry);
Tejun Heoa26cd722007-06-14 03:45:14 +0900337
Tejun Heo13b30862007-06-14 03:45:14 +0900338 if (parent_sd) {
339 sd->s_parent = sysfs_get(parent_sd);
Tejun Heo0c73f182007-06-14 03:45:18 +0900340 sysfs_link_sibling(sd);
Tejun Heo13b30862007-06-14 03:45:14 +0900341 }
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700342}
343
Tejun Heof0b0af42007-06-14 04:27:22 +0900344/**
345 * sysfs_find_dirent - find sysfs_dirent with the given name
346 * @parent_sd: sysfs_dirent to search under
347 * @name: name to look for
Maneesh Sonic5168652006-03-09 19:40:14 +0530348 *
Tejun Heof0b0af42007-06-14 04:27:22 +0900349 * Look for sysfs_dirent with name @name under @parent_sd.
Maneesh Sonic5168652006-03-09 19:40:14 +0530350 *
Tejun Heof0b0af42007-06-14 04:27:22 +0900351 * LOCKING:
Tejun Heo3007e992007-06-14 04:27:23 +0900352 * mutex_lock(sysfs_mutex)
Tejun Heof0b0af42007-06-14 04:27:22 +0900353 *
354 * RETURNS:
355 * Pointer to sysfs_dirent if found, NULL if not.
Maneesh Sonic5168652006-03-09 19:40:14 +0530356 */
Tejun Heof0b0af42007-06-14 04:27:22 +0900357struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
358 const unsigned char *name)
Maneesh Sonic5168652006-03-09 19:40:14 +0530359{
Tejun Heof0b0af42007-06-14 04:27:22 +0900360 struct sysfs_dirent *sd;
Maneesh Sonic5168652006-03-09 19:40:14 +0530361
Tejun Heof0b0af42007-06-14 04:27:22 +0900362 for (sd = parent_sd->s_children; sd; sd = sd->s_sibling)
363 if (sysfs_type(sd) && !strcmp(sd->s_name, name))
364 return sd;
365 return NULL;
366}
Maneesh Sonic5168652006-03-09 19:40:14 +0530367
Tejun Heof0b0af42007-06-14 04:27:22 +0900368/**
369 * sysfs_get_dirent - find and get sysfs_dirent with the given name
370 * @parent_sd: sysfs_dirent to search under
371 * @name: name to look for
372 *
373 * Look for sysfs_dirent with name @name under @parent_sd and get
374 * it if found.
375 *
376 * LOCKING:
Tejun Heo3007e992007-06-14 04:27:23 +0900377 * Kernel thread context (may sleep). Grabs sysfs_mutex.
Tejun Heof0b0af42007-06-14 04:27:22 +0900378 *
379 * RETURNS:
380 * Pointer to sysfs_dirent if found, NULL if not.
381 */
382struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
383 const unsigned char *name)
384{
385 struct sysfs_dirent *sd;
386
Tejun Heo3007e992007-06-14 04:27:23 +0900387 mutex_lock(&sysfs_mutex);
Tejun Heof0b0af42007-06-14 04:27:22 +0900388 sd = sysfs_find_dirent(parent_sd, name);
389 sysfs_get(sd);
Tejun Heo3007e992007-06-14 04:27:23 +0900390 mutex_unlock(&sysfs_mutex);
Tejun Heof0b0af42007-06-14 04:27:22 +0900391
392 return sd;
Maneesh Sonic5168652006-03-09 19:40:14 +0530393}
394
Tejun Heo608e2662007-06-14 04:27:22 +0900395static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
396 const char *name, struct sysfs_dirent **p_sd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397{
Tejun Heo608e2662007-06-14 04:27:22 +0900398 struct dentry *parent = parent_sd->s_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 int error;
400 umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900401 struct dentry *dentry;
Tejun Heofc9f54b2007-06-14 03:45:17 +0900402 struct inode *inode;
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900403 struct sysfs_dirent *sd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900405 mutex_lock(&parent->d_inode->i_mutex);
406
Tejun Heofc9f54b2007-06-14 03:45:17 +0900407 /* allocate */
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900408 dentry = lookup_one_len(name, parent, strlen(name));
409 if (IS_ERR(dentry)) {
410 error = PTR_ERR(dentry);
411 goto out_unlock;
412 }
413
414 error = -EEXIST;
Tejun Heofc9f54b2007-06-14 03:45:17 +0900415 if (dentry->d_inode)
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900416 goto out_dput;
417
Tejun Heoa26cd722007-06-14 03:45:14 +0900418 error = -ENOMEM;
Tejun Heo3e519032007-06-14 03:45:15 +0900419 sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
Tejun Heoa26cd722007-06-14 03:45:14 +0900420 if (!sd)
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900421 goto out_drop;
Tejun Heo3e519032007-06-14 03:45:15 +0900422 sd->s_elem.dir.kobj = kobj;
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900423
Tejun Heo8312a8d2007-06-14 03:45:17 +0900424 inode = sysfs_get_inode(sd);
Tejun Heofc9f54b2007-06-14 03:45:17 +0900425 if (!inode)
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900426 goto out_sput;
427
Tejun Heo8312a8d2007-06-14 03:45:17 +0900428 if (inode->i_state & I_NEW) {
429 inode->i_op = &sysfs_dir_inode_operations;
430 inode->i_fop = &sysfs_dir_operations;
431 /* directory inodes start off with i_nlink == 2 (for ".") */
432 inc_nlink(inode);
433 }
Tejun Heofc9f54b2007-06-14 03:45:17 +0900434
435 /* link in */
Tejun Heo3007e992007-06-14 04:27:23 +0900436 mutex_lock(&sysfs_mutex);
437
Tejun Heofc9f54b2007-06-14 03:45:17 +0900438 error = -EEXIST;
Tejun Heo3007e992007-06-14 04:27:23 +0900439 if (sysfs_find_dirent(parent_sd, name)) {
440 mutex_unlock(&sysfs_mutex);
Tejun Heofc9f54b2007-06-14 03:45:17 +0900441 goto out_iput;
Tejun Heo3007e992007-06-14 04:27:23 +0900442 }
Tejun Heofc9f54b2007-06-14 03:45:17 +0900443
444 sysfs_instantiate(dentry, inode);
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900445 inc_nlink(parent->d_inode);
Tejun Heo608e2662007-06-14 04:27:22 +0900446 sysfs_attach_dirent(sd, parent_sd, dentry);
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900447
Tejun Heo3007e992007-06-14 04:27:23 +0900448 mutex_unlock(&sysfs_mutex);
449
Tejun Heo608e2662007-06-14 04:27:22 +0900450 *p_sd = sd;
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900451 error = 0;
Tejun Heofc9f54b2007-06-14 03:45:17 +0900452 goto out_unlock; /* pin directory dentry in core */
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900453
Tejun Heofc9f54b2007-06-14 03:45:17 +0900454 out_iput:
455 iput(inode);
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900456 out_sput:
Tejun Heodfeb9fb2007-06-14 03:45:14 +0900457 sysfs_put(sd);
458 out_drop:
459 d_drop(dentry);
460 out_dput:
461 dput(dentry);
462 out_unlock:
463 mutex_unlock(&parent->d_inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 return error;
465}
466
Tejun Heo608e2662007-06-14 04:27:22 +0900467int sysfs_create_subdir(struct kobject *kobj, const char *name,
468 struct sysfs_dirent **p_sd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469{
Tejun Heo608e2662007-06-14 04:27:22 +0900470 return create_dir(kobj, kobj->sd, name, p_sd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471}
472
473/**
474 * sysfs_create_dir - create a directory for an object.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 * @kobj: object we're creating directory for.
Tejun Heo608e2662007-06-14 04:27:22 +0900476 * @shadow_parent: parent object.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 */
Tejun Heo608e2662007-06-14 04:27:22 +0900478int sysfs_create_dir(struct kobject *kobj,
479 struct sysfs_dirent *shadow_parent_sd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480{
Tejun Heo608e2662007-06-14 04:27:22 +0900481 struct sysfs_dirent *parent_sd, *sd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 int error = 0;
483
484 BUG_ON(!kobj);
485
Tejun Heo608e2662007-06-14 04:27:22 +0900486 if (shadow_parent_sd)
487 parent_sd = shadow_parent_sd;
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700488 else if (kobj->parent)
Tejun Heo608e2662007-06-14 04:27:22 +0900489 parent_sd = kobj->parent->sd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 else if (sysfs_mount && sysfs_mount->mnt_sb)
Tejun Heo608e2662007-06-14 04:27:22 +0900491 parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 else
493 return -EFAULT;
494
Tejun Heo608e2662007-06-14 04:27:22 +0900495 error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 if (!error)
Tejun Heo608e2662007-06-14 04:27:22 +0900497 kobj->sd = sd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 return error;
499}
500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
502 struct nameidata *nd)
503{
504 struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
505 struct sysfs_dirent * sd;
Tejun Heob402d722007-06-14 04:27:21 +0900506 struct bin_attribute *bin_attr;
Tejun Heofc9f54b2007-06-14 03:45:17 +0900507 struct inode *inode;
508 int found = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
Tejun Heo0c73f182007-06-14 03:45:18 +0900510 for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
Tejun Heob402d722007-06-14 04:27:21 +0900511 if ((sysfs_type(sd) & SYSFS_NOT_PINNED) &&
Tejun Heofc9f54b2007-06-14 03:45:17 +0900512 !strcmp(sd->s_name, dentry->d_name.name)) {
513 found = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 break;
515 }
516 }
517
Tejun Heofc9f54b2007-06-14 03:45:17 +0900518 /* no such entry */
519 if (!found)
520 return NULL;
521
522 /* attach dentry and inode */
Tejun Heo8312a8d2007-06-14 03:45:17 +0900523 inode = sysfs_get_inode(sd);
Tejun Heofc9f54b2007-06-14 03:45:17 +0900524 if (!inode)
525 return ERR_PTR(-ENOMEM);
526
Tejun Heo3007e992007-06-14 04:27:23 +0900527 mutex_lock(&sysfs_mutex);
528
Tejun Heo8312a8d2007-06-14 03:45:17 +0900529 if (inode->i_state & I_NEW) {
530 /* initialize inode according to type */
Tejun Heob402d722007-06-14 04:27:21 +0900531 switch (sysfs_type(sd)) {
532 case SYSFS_KOBJ_ATTR:
Tejun Heo8312a8d2007-06-14 03:45:17 +0900533 inode->i_size = PAGE_SIZE;
534 inode->i_fop = &sysfs_file_operations;
Tejun Heob402d722007-06-14 04:27:21 +0900535 break;
536 case SYSFS_KOBJ_BIN_ATTR:
537 bin_attr = sd->s_elem.bin_attr.bin_attr;
Tejun Heo8312a8d2007-06-14 03:45:17 +0900538 inode->i_size = bin_attr->size;
539 inode->i_fop = &bin_fops;
Tejun Heob402d722007-06-14 04:27:21 +0900540 break;
541 case SYSFS_KOBJ_LINK:
Tejun Heo8312a8d2007-06-14 03:45:17 +0900542 inode->i_op = &sysfs_symlink_inode_operations;
Tejun Heob402d722007-06-14 04:27:21 +0900543 break;
544 default:
545 BUG();
546 }
Tejun Heo8312a8d2007-06-14 03:45:17 +0900547 }
Tejun Heofc9f54b2007-06-14 03:45:17 +0900548
549 sysfs_instantiate(dentry, inode);
550 sysfs_attach_dentry(sd, dentry);
551
Tejun Heo3007e992007-06-14 04:27:23 +0900552 mutex_unlock(&sysfs_mutex);
553
Tejun Heofc9f54b2007-06-14 03:45:17 +0900554 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555}
556
Arjan van de Venc5ef1c42007-02-12 00:55:40 -0800557const struct inode_operations sysfs_dir_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 .lookup = sysfs_lookup,
Maneesh Soni988d1862005-05-31 10:39:14 +0530559 .setattr = sysfs_setattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560};
561
Tejun Heo608e2662007-06-14 04:27:22 +0900562static void remove_dir(struct sysfs_dirent *sd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
Tejun Heo3007e992007-06-14 04:27:23 +0900564 mutex_lock(&sysfs_mutex);
Tejun Heo0c73f182007-06-14 03:45:18 +0900565 sysfs_unlink_sibling(sd);
Tejun Heo380e6fb2007-06-14 04:27:22 +0900566 sd->s_flags |= SYSFS_FLAG_REMOVED;
Tejun Heo3007e992007-06-14 04:27:23 +0900567 mutex_unlock(&sysfs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
Tejun Heo608e2662007-06-14 04:27:22 +0900569 pr_debug(" o %s removing done\n", sd->s_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Tejun Heodbde0fc2007-06-14 03:45:16 +0900571 sysfs_drop_dentry(sd);
Tejun Heo0ab66082007-06-14 03:45:16 +0900572 sysfs_deactivate(sd);
573 sysfs_put(sd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574}
575
Tejun Heo608e2662007-06-14 04:27:22 +0900576void sysfs_remove_subdir(struct sysfs_dirent *sd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
Tejun Heo608e2662007-06-14 04:27:22 +0900578 remove_dir(sd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579}
580
581
Tejun Heo608e2662007-06-14 04:27:22 +0900582static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
Tejun Heo0c73f182007-06-14 03:45:18 +0900584 struct sysfs_dirent *removed = NULL;
Tejun Heo0c73f182007-06-14 03:45:18 +0900585 struct sysfs_dirent **pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Tejun Heo608e2662007-06-14 04:27:22 +0900587 if (!dir_sd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 return;
589
Tejun Heo608e2662007-06-14 04:27:22 +0900590 pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
Tejun Heo3007e992007-06-14 04:27:23 +0900591 mutex_lock(&sysfs_mutex);
Tejun Heo608e2662007-06-14 04:27:22 +0900592 pos = &dir_sd->s_children;
Tejun Heo0c73f182007-06-14 03:45:18 +0900593 while (*pos) {
594 struct sysfs_dirent *sd = *pos;
595
Tejun Heob402d722007-06-14 04:27:21 +0900596 if (sysfs_type(sd) && (sysfs_type(sd) & SYSFS_NOT_PINNED)) {
Tejun Heo380e6fb2007-06-14 04:27:22 +0900597 sd->s_flags |= SYSFS_FLAG_REMOVED;
Tejun Heo0c73f182007-06-14 03:45:18 +0900598 *pos = sd->s_sibling;
599 sd->s_sibling = removed;
600 removed = sd;
601 } else
602 pos = &(*pos)->s_sibling;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 }
Tejun Heo3007e992007-06-14 04:27:23 +0900604 mutex_unlock(&sysfs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
Tejun Heo0c73f182007-06-14 03:45:18 +0900606 while (removed) {
607 struct sysfs_dirent *sd = removed;
608
609 removed = sd->s_sibling;
610 sd->s_sibling = NULL;
611
Tejun Heodbde0fc2007-06-14 03:45:16 +0900612 sysfs_drop_dentry(sd);
Tejun Heo0ab66082007-06-14 03:45:16 +0900613 sysfs_deactivate(sd);
614 sysfs_put(sd);
615 }
616
Tejun Heo608e2662007-06-14 04:27:22 +0900617 remove_dir(dir_sd);
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700618}
619
620/**
621 * sysfs_remove_dir - remove an object's directory.
622 * @kobj: object.
623 *
624 * The only thing special about this is that we remove any files in
625 * the directory before we remove the directory, and we've inlined
626 * what used to be sysfs_rmdir() below, instead of calling separately.
627 */
628
629void sysfs_remove_dir(struct kobject * kobj)
630{
Tejun Heo608e2662007-06-14 04:27:22 +0900631 struct sysfs_dirent *sd = kobj->sd;
Tejun Heoaecdced2007-06-14 03:45:15 +0900632
Tejun Heo5f995322007-06-14 04:27:23 +0900633 spin_lock(&sysfs_assoc_lock);
Tejun Heo608e2662007-06-14 04:27:22 +0900634 kobj->sd = NULL;
Tejun Heo5f995322007-06-14 04:27:23 +0900635 spin_unlock(&sysfs_assoc_lock);
Tejun Heoaecdced2007-06-14 03:45:15 +0900636
Tejun Heo608e2662007-06-14 04:27:22 +0900637 __sysfs_remove_dir(sd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638}
639
Tejun Heo608e2662007-06-14 04:27:22 +0900640int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700641 const char *new_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642{
Tejun Heo608e2662007-06-14 04:27:22 +0900643 struct sysfs_dirent *sd = kobj->sd;
644 struct dentry *new_parent = new_parent_sd->s_dentry;
Tejun Heo0c096b52007-06-14 03:45:15 +0900645 struct dentry *new_dentry;
646 char *dup_name;
Tejun Heo996b7372007-06-14 03:45:14 +0900647 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Tejun Heo608e2662007-06-14 04:27:22 +0900649 if (!new_parent_sd)
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700650 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700652 mutex_lock(&new_parent->d_inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700654 new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
Tejun Heo996b7372007-06-14 03:45:14 +0900655 if (IS_ERR(new_dentry)) {
656 error = PTR_ERR(new_dentry);
657 goto out_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 }
Tejun Heo996b7372007-06-14 03:45:14 +0900659
660 /* By allowing two different directories with the same
661 * d_parent we allow this routine to move between different
662 * shadows of the same directory
663 */
664 error = -EINVAL;
Tejun Heo608e2662007-06-14 04:27:22 +0900665 if (sd->s_parent->s_dentry->d_inode != new_parent->d_inode ||
Tejun Heo996b7372007-06-14 03:45:14 +0900666 new_dentry->d_parent->d_inode != new_parent->d_inode ||
Tejun Heo608e2662007-06-14 04:27:22 +0900667 new_dentry == sd->s_dentry)
Tejun Heo996b7372007-06-14 03:45:14 +0900668 goto out_dput;
669
670 error = -EEXIST;
671 if (new_dentry->d_inode)
672 goto out_dput;
673
Tejun Heo0c096b52007-06-14 03:45:15 +0900674 /* rename kobject and sysfs_dirent */
675 error = -ENOMEM;
676 new_name = dup_name = kstrdup(new_name, GFP_KERNEL);
677 if (!new_name)
Tejun Heo996b7372007-06-14 03:45:14 +0900678 goto out_drop;
679
Tejun Heo0c096b52007-06-14 03:45:15 +0900680 error = kobject_set_name(kobj, "%s", new_name);
681 if (error)
682 goto out_free;
683
684 kfree(sd->s_name);
685 sd->s_name = new_name;
686
687 /* move under the new parent */
Tejun Heo996b7372007-06-14 03:45:14 +0900688 d_add(new_dentry, NULL);
Tejun Heo608e2662007-06-14 04:27:22 +0900689 d_move(sd->s_dentry, new_dentry);
Tejun Heo996b7372007-06-14 03:45:14 +0900690
Tejun Heo3007e992007-06-14 04:27:23 +0900691 mutex_lock(&sysfs_mutex);
692
Tejun Heo0c73f182007-06-14 03:45:18 +0900693 sysfs_unlink_sibling(sd);
Tejun Heo608e2662007-06-14 04:27:22 +0900694 sysfs_get(new_parent_sd);
Tejun Heo7f7cfff2007-06-14 03:45:17 +0900695 sysfs_put(sd->s_parent);
Tejun Heo608e2662007-06-14 04:27:22 +0900696 sd->s_parent = new_parent_sd;
Tejun Heo0c73f182007-06-14 03:45:18 +0900697 sysfs_link_sibling(sd);
Tejun Heo996b7372007-06-14 03:45:14 +0900698
Tejun Heo3007e992007-06-14 04:27:23 +0900699 mutex_unlock(&sysfs_mutex);
700
Tejun Heo996b7372007-06-14 03:45:14 +0900701 error = 0;
702 goto out_unlock;
703
Tejun Heo0c096b52007-06-14 03:45:15 +0900704 out_free:
705 kfree(dup_name);
Tejun Heo996b7372007-06-14 03:45:14 +0900706 out_drop:
707 d_drop(new_dentry);
708 out_dput:
709 dput(new_dentry);
710 out_unlock:
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700711 mutex_unlock(&new_parent->d_inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 return error;
713}
714
Cornelia Huck8a824722006-11-20 17:07:51 +0100715int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent)
716{
717 struct dentry *old_parent_dentry, *new_parent_dentry, *new_dentry;
718 struct sysfs_dirent *new_parent_sd, *sd;
719 int error;
720
Cornelia Huck8a824722006-11-20 17:07:51 +0100721 old_parent_dentry = kobj->parent ?
Tejun Heo608e2662007-06-14 04:27:22 +0900722 kobj->parent->sd->s_dentry : sysfs_mount->mnt_sb->s_root;
Cornelia Huckc744aeae2007-01-08 20:16:44 +0100723 new_parent_dentry = new_parent ?
Tejun Heo608e2662007-06-14 04:27:22 +0900724 new_parent->sd->s_dentry : sysfs_mount->mnt_sb->s_root;
Cornelia Huck8a824722006-11-20 17:07:51 +0100725
Mark Lord0de15172007-03-06 01:42:03 -0800726 if (old_parent_dentry->d_inode == new_parent_dentry->d_inode)
727 return 0; /* nothing to move */
Cornelia Huck8a824722006-11-20 17:07:51 +0100728again:
729 mutex_lock(&old_parent_dentry->d_inode->i_mutex);
730 if (!mutex_trylock(&new_parent_dentry->d_inode->i_mutex)) {
731 mutex_unlock(&old_parent_dentry->d_inode->i_mutex);
732 goto again;
733 }
734
735 new_parent_sd = new_parent_dentry->d_fsdata;
Tejun Heo608e2662007-06-14 04:27:22 +0900736 sd = kobj->sd;
Cornelia Huck8a824722006-11-20 17:07:51 +0100737
738 new_dentry = lookup_one_len(kobj->name, new_parent_dentry,
739 strlen(kobj->name));
740 if (IS_ERR(new_dentry)) {
741 error = PTR_ERR(new_dentry);
742 goto out;
743 } else
744 error = 0;
745 d_add(new_dentry, NULL);
Tejun Heo608e2662007-06-14 04:27:22 +0900746 d_move(sd->s_dentry, new_dentry);
Cornelia Huck8a824722006-11-20 17:07:51 +0100747 dput(new_dentry);
748
749 /* Remove from old parent's list and insert into new parent's list. */
Tejun Heo3007e992007-06-14 04:27:23 +0900750 mutex_lock(&sysfs_mutex);
751
Tejun Heo0c73f182007-06-14 03:45:18 +0900752 sysfs_unlink_sibling(sd);
Tejun Heo7f7cfff2007-06-14 03:45:17 +0900753 sysfs_get(new_parent_sd);
754 sysfs_put(sd->s_parent);
755 sd->s_parent = new_parent_sd;
Tejun Heo0c73f182007-06-14 03:45:18 +0900756 sysfs_link_sibling(sd);
Cornelia Huck8a824722006-11-20 17:07:51 +0100757
Tejun Heo3007e992007-06-14 04:27:23 +0900758 mutex_unlock(&sysfs_mutex);
Cornelia Huck8a824722006-11-20 17:07:51 +0100759out:
760 mutex_unlock(&new_parent_dentry->d_inode->i_mutex);
761 mutex_unlock(&old_parent_dentry->d_inode->i_mutex);
762
763 return error;
764}
765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766static int sysfs_dir_open(struct inode *inode, struct file *file)
767{
Josef "Jeff" Sipekf427f5d2006-12-08 02:36:36 -0800768 struct dentry * dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 struct sysfs_dirent * parent_sd = dentry->d_fsdata;
Tejun Heoa26cd722007-06-14 03:45:14 +0900770 struct sysfs_dirent * sd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Tejun Heo3e519032007-06-14 03:45:15 +0900772 sd = sysfs_new_dirent("_DIR_", 0, 0);
Tejun Heo3007e992007-06-14 04:27:23 +0900773 if (sd) {
774 mutex_lock(&sysfs_mutex);
Tejun Heoa26cd722007-06-14 03:45:14 +0900775 sysfs_attach_dirent(sd, parent_sd, NULL);
Tejun Heo3007e992007-06-14 04:27:23 +0900776 mutex_unlock(&sysfs_mutex);
777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Tejun Heoa26cd722007-06-14 03:45:14 +0900779 file->private_data = sd;
780 return sd ? 0 : -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781}
782
783static int sysfs_dir_close(struct inode *inode, struct file *file)
784{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 struct sysfs_dirent * cursor = file->private_data;
786
Tejun Heo3007e992007-06-14 04:27:23 +0900787 mutex_lock(&sysfs_mutex);
Tejun Heo0c73f182007-06-14 03:45:18 +0900788 sysfs_unlink_sibling(cursor);
Tejun Heo3007e992007-06-14 04:27:23 +0900789 mutex_unlock(&sysfs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791 release_sysfs_dirent(cursor);
792
793 return 0;
794}
795
796/* Relationship between s_mode and the DT_xxx types */
797static inline unsigned char dt_type(struct sysfs_dirent *sd)
798{
799 return (sd->s_mode >> 12) & 15;
800}
801
802static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
803{
Josef "Jeff" Sipekf427f5d2006-12-08 02:36:36 -0800804 struct dentry *dentry = filp->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 struct sysfs_dirent * parent_sd = dentry->d_fsdata;
806 struct sysfs_dirent *cursor = filp->private_data;
Tejun Heo0c73f182007-06-14 03:45:18 +0900807 struct sysfs_dirent **pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 ino_t ino;
809 int i = filp->f_pos;
810
811 switch (i) {
812 case 0:
Eric Sandeendc351252007-06-11 14:02:45 +0900813 ino = parent_sd->s_ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
815 break;
816 filp->f_pos++;
817 i++;
818 /* fallthrough */
819 case 1:
Tejun Heo13b30862007-06-14 03:45:14 +0900820 if (parent_sd->s_parent)
821 ino = parent_sd->s_parent->s_ino;
822 else
823 ino = parent_sd->s_ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
825 break;
826 filp->f_pos++;
827 i++;
828 /* fallthrough */
829 default:
Tejun Heo3007e992007-06-14 04:27:23 +0900830 mutex_lock(&sysfs_mutex);
831
Tejun Heo0c73f182007-06-14 03:45:18 +0900832 pos = &parent_sd->s_children;
833 while (*pos != cursor)
834 pos = &(*pos)->s_sibling;
Akinobu Mita1bfba4e2006-06-26 00:24:40 -0700835
Tejun Heo0c73f182007-06-14 03:45:18 +0900836 /* unlink cursor */
837 *pos = cursor->s_sibling;
838
839 if (filp->f_pos == 2)
840 pos = &parent_sd->s_children;
841
842 for ( ; *pos; pos = &(*pos)->s_sibling) {
843 struct sysfs_dirent *next = *pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 const char * name;
845 int len;
846
Tejun Heob402d722007-06-14 04:27:21 +0900847 if (!sysfs_type(next))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 continue;
849
Tejun Heo0c096b52007-06-14 03:45:15 +0900850 name = next->s_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 len = strlen(name);
Eric Sandeendc351252007-06-11 14:02:45 +0900852 ino = next->s_ino;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
854 if (filldir(dirent, name, len, filp->f_pos, ino,
855 dt_type(next)) < 0)
Tejun Heo0c73f182007-06-14 03:45:18 +0900856 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 filp->f_pos++;
859 }
Tejun Heo0c73f182007-06-14 03:45:18 +0900860
861 /* put cursor back in */
862 cursor->s_sibling = *pos;
863 *pos = cursor;
Tejun Heo3007e992007-06-14 04:27:23 +0900864
865 mutex_unlock(&sysfs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 }
867 return 0;
868}
869
870static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
871{
Josef "Jeff" Sipekf427f5d2006-12-08 02:36:36 -0800872 struct dentry * dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 switch (origin) {
875 case 1:
876 offset += file->f_pos;
877 case 0:
878 if (offset >= 0)
879 break;
880 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 return -EINVAL;
882 }
883 if (offset != file->f_pos) {
Tejun Heo3007e992007-06-14 04:27:23 +0900884 mutex_lock(&sysfs_mutex);
885
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 file->f_pos = offset;
887 if (file->f_pos >= 2) {
888 struct sysfs_dirent *sd = dentry->d_fsdata;
889 struct sysfs_dirent *cursor = file->private_data;
Tejun Heo0c73f182007-06-14 03:45:18 +0900890 struct sysfs_dirent **pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 loff_t n = file->f_pos - 2;
892
Tejun Heo0c73f182007-06-14 03:45:18 +0900893 sysfs_unlink_sibling(cursor);
894
895 pos = &sd->s_children;
896 while (n && *pos) {
897 struct sysfs_dirent *next = *pos;
Tejun Heob402d722007-06-14 04:27:21 +0900898 if (sysfs_type(next))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 n--;
Tejun Heo0c73f182007-06-14 03:45:18 +0900900 pos = &(*pos)->s_sibling;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 }
Tejun Heo0c73f182007-06-14 03:45:18 +0900902
903 cursor->s_sibling = *pos;
904 *pos = cursor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 }
Tejun Heo3007e992007-06-14 04:27:23 +0900906
907 mutex_unlock(&sysfs_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 }
Tejun Heo3007e992007-06-14 04:27:23 +0900909
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 return offset;
911}
912
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700913
914/**
915 * sysfs_make_shadowed_dir - Setup so a directory can be shadowed
916 * @kobj: object we're creating shadow of.
917 */
918
919int sysfs_make_shadowed_dir(struct kobject *kobj,
920 void * (*follow_link)(struct dentry *, struct nameidata *))
921{
922 struct inode *inode;
923 struct inode_operations *i_op;
924
Tejun Heo608e2662007-06-14 04:27:22 +0900925 inode = kobj->sd->s_dentry->d_inode;
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700926 if (inode->i_op != &sysfs_dir_inode_operations)
927 return -EINVAL;
928
929 i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
930 if (!i_op)
931 return -ENOMEM;
932
933 memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op));
934 i_op->follow_link = follow_link;
935
936 /* Locking of inode->i_op?
937 * Since setting i_op is a single word write and they
938 * are atomic we should be ok here.
939 */
940 inode->i_op = i_op;
941 return 0;
942}
943
944/**
945 * sysfs_create_shadow_dir - create a shadow directory for an object.
946 * @kobj: object we're creating directory for.
947 *
948 * sysfs_make_shadowed_dir must already have been called on this
949 * directory.
950 */
951
Tejun Heo608e2662007-06-14 04:27:22 +0900952struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj)
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700953{
Tejun Heo608e2662007-06-14 04:27:22 +0900954 struct dentry *dir = kobj->sd->s_dentry;
Tejun Heo13b30862007-06-14 03:45:14 +0900955 struct inode *inode = dir->d_inode;
956 struct dentry *parent = dir->d_parent;
957 struct sysfs_dirent *parent_sd = parent->d_fsdata;
958 struct dentry *shadow;
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700959 struct sysfs_dirent *sd;
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700960
Tejun Heo608e2662007-06-14 04:27:22 +0900961 sd = ERR_PTR(-EINVAL);
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700962 if (!sysfs_is_shadowed_inode(inode))
963 goto out;
964
965 shadow = d_alloc(parent, &dir->d_name);
966 if (!shadow)
967 goto nomem;
968
Tejun Heo3e519032007-06-14 03:45:15 +0900969 sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR);
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700970 if (!sd)
971 goto nomem;
Tejun Heo3e519032007-06-14 03:45:15 +0900972 sd->s_elem.dir.kobj = kobj;
Tejun Heo13b30862007-06-14 03:45:14 +0900973 /* point to parent_sd but don't attach to it */
974 sd->s_parent = sysfs_get(parent_sd);
Tejun Heo3007e992007-06-14 04:27:23 +0900975 mutex_lock(&sysfs_mutex);
Tejun Heoa26cd722007-06-14 03:45:14 +0900976 sysfs_attach_dirent(sd, NULL, shadow);
Tejun Heo3007e992007-06-14 04:27:23 +0900977 mutex_unlock(&sysfs_mutex);
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700978
979 d_instantiate(shadow, igrab(inode));
980 inc_nlink(inode);
981 inc_nlink(parent->d_inode);
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700982
983 dget(shadow); /* Extra count - pin the dentry in core */
984
985out:
Tejun Heo608e2662007-06-14 04:27:22 +0900986 return sd;
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700987nomem:
988 dput(shadow);
Tejun Heo608e2662007-06-14 04:27:22 +0900989 sd = ERR_PTR(-ENOMEM);
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700990 goto out;
991}
992
993/**
994 * sysfs_remove_shadow_dir - remove an object's directory.
Tejun Heo608e2662007-06-14 04:27:22 +0900995 * @shadow_sd: sysfs_dirent of shadow directory
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -0700996 *
997 * The only thing special about this is that we remove any files in
998 * the directory before we remove the directory, and we've inlined
999 * what used to be sysfs_rmdir() below, instead of calling separately.
1000 */
1001
Tejun Heo608e2662007-06-14 04:27:22 +09001002void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd)
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -07001003{
Tejun Heo608e2662007-06-14 04:27:22 +09001004 __sysfs_remove_dir(shadow_sd);
Eric W. Biedermanb592fcf2007-01-24 12:35:52 -07001005}
1006
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -08001007const struct file_operations sysfs_dir_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 .open = sysfs_dir_open,
1009 .release = sysfs_dir_close,
1010 .llseek = sysfs_dir_lseek,
1011 .read = generic_read_dir,
1012 .readdir = sysfs_readdir,
1013};