Branch data Line data Source code
1 : : /*
2 : : * fs/sysfs/dir.c - sysfs core and dir operation implementation
3 : : *
4 : : * Copyright (c) 2001-3 Patrick Mochel
5 : : * Copyright (c) 2007 SUSE Linux Products GmbH
6 : : * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
7 : : *
8 : : * This file is released under the GPLv2.
9 : : *
10 : : * Please see Documentation/filesystems/sysfs.txt for more information.
11 : : */
12 : :
13 : : #undef DEBUG
14 : :
15 : : #include <linux/fs.h>
16 : : #include <linux/kobject.h>
17 : : #include <linux/slab.h>
18 : : #include "sysfs.h"
19 : :
20 : : DEFINE_SPINLOCK(sysfs_symlink_target_lock);
21 : :
22 : : /**
23 : : * sysfs_pathname - return full path to sysfs dirent
24 : : * @kn: kernfs_node whose path we want
25 : : * @path: caller allocated buffer of size PATH_MAX
26 : : *
27 : : * Gives the name "/" to the sysfs_root entry; any path returned
28 : : * is relative to wherever sysfs is mounted.
29 : : */
30 : 0 : static char *sysfs_pathname(struct kernfs_node *kn, char *path)
31 : : {
32 [ # # ]: 0 : if (kn->parent) {
33 : 0 : sysfs_pathname(kn->parent, path);
34 : 0 : strlcat(path, "/", PATH_MAX);
35 : : }
36 : 0 : strlcat(path, kn->name, PATH_MAX);
37 : 0 : return path;
38 : : }
39 : :
40 : 0 : void sysfs_warn_dup(struct kernfs_node *parent, const char *name)
41 : : {
42 : : char *path;
43 : :
44 : : path = kzalloc(PATH_MAX, GFP_KERNEL);
45 [ # # ]: 0 : if (path) {
46 : 0 : sysfs_pathname(parent, path);
47 : 0 : strlcat(path, "/", PATH_MAX);
48 : 0 : strlcat(path, name, PATH_MAX);
49 : : }
50 : :
51 [ # # ]: 0 : WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s'\n",
52 : : path ? path : name);
53 : :
54 : 0 : kfree(path);
55 : 0 : }
56 : :
57 : : /**
58 : : * sysfs_create_dir_ns - create a directory for an object with a namespace tag
59 : : * @kobj: object we're creating directory for
60 : : * @ns: the namespace tag to use
61 : : */
62 : 0 : int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
63 : : {
64 : : struct kernfs_node *parent, *kn;
65 : :
66 [ - + ]: 133 : BUG_ON(!kobj);
67 : :
68 [ + - ]: 133 : if (kobj->parent)
69 : 133 : parent = kobj->parent->sd;
70 : : else
71 : 0 : parent = sysfs_root_kn;
72 : :
73 [ + - ]: 133 : if (!parent)
74 : : return -ENOENT;
75 : :
76 : 133 : kn = kernfs_create_dir_ns(parent, kobject_name(kobj),
77 : : S_IRWXU | S_IRUGO | S_IXUGO, kobj, ns);
78 [ - + ]: 266 : if (IS_ERR(kn)) {
79 [ # # ]: 0 : if (PTR_ERR(kn) == -EEXIST)
80 : 0 : sysfs_warn_dup(parent, kobject_name(kobj));
81 : 0 : return PTR_ERR(kn);
82 : : }
83 : :
84 : 133 : kobj->sd = kn;
85 : 133 : return 0;
86 : : }
87 : :
88 : : /**
89 : : * sysfs_remove_dir - remove an object's directory.
90 : : * @kobj: object.
91 : : *
92 : : * The only thing special about this is that we remove any files in
93 : : * the directory before we remove the directory, and we've inlined
94 : : * what used to be sysfs_rmdir() below, instead of calling separately.
95 : : */
96 : 0 : void sysfs_remove_dir(struct kobject *kobj)
97 : : {
98 : 42 : struct kernfs_node *kn = kobj->sd;
99 : :
100 : : /*
101 : : * In general, kboject owner is responsible for ensuring removal
102 : : * doesn't race with other operations and sysfs doesn't provide any
103 : : * protection; however, when @kobj is used as a symlink target, the
104 : : * symlinking entity usually doesn't own @kobj and thus has no
105 : : * control over removal. @kobj->sd may be removed anytime
106 : : * and symlink code may end up dereferencing an already freed node.
107 : : *
108 : : * sysfs_symlink_target_lock synchronizes @kobj->sd
109 : : * disassociation against symlink operations so that symlink code
110 : : * can safely dereference @kobj->sd.
111 : : */
112 : : spin_lock(&sysfs_symlink_target_lock);
113 : 21 : kobj->sd = NULL;
114 : : spin_unlock(&sysfs_symlink_target_lock);
115 : :
116 [ + - ]: 21 : if (kn) {
117 [ - + ][ # # ]: 21 : WARN_ON_ONCE(kernfs_type(kn) != KERNFS_DIR);
[ # # ]
118 : 21 : kernfs_remove(kn);
119 : : }
120 : 21 : }
121 : :
122 : 0 : int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
123 : : const void *new_ns)
124 : : {
125 : 0 : struct kernfs_node *parent = kobj->sd->parent;
126 : :
127 : 0 : return kernfs_rename_ns(kobj->sd, parent, new_name, new_ns);
128 : : }
129 : :
130 : 0 : int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
131 : : const void *new_ns)
132 : : {
133 : 29 : struct kernfs_node *kn = kobj->sd;
134 : : struct kernfs_node *new_parent;
135 : :
136 [ - + ]: 29 : BUG_ON(!kn->parent);
137 [ - + ]: 29 : new_parent = new_parent_kobj && new_parent_kobj->sd ?
138 [ + - ]: 29 : new_parent_kobj->sd : sysfs_root_kn;
139 : :
140 : 29 : return kernfs_rename_ns(kn, new_parent, kn->name, new_ns);
141 : : }
|