Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /*
3 : * fs/sysfs/dir.c - sysfs core and dir operation implementation
4 : *
5 : * Copyright (c) 2001-3 Patrick Mochel
6 : * Copyright (c) 2007 SUSE Linux Products GmbH
7 : * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
8 : *
9 : * Please see Documentation/filesystems/sysfs.rst for more information.
10 : */
11 :
12 : #define pr_fmt(fmt) "sysfs: " fmt
13 :
14 : #include <linux/fs.h>
15 : #include <linux/kobject.h>
16 : #include <linux/slab.h>
17 : #include "sysfs.h"
18 :
19 : DEFINE_SPINLOCK(sysfs_symlink_target_lock);
20 :
21 0 : void sysfs_warn_dup(struct kernfs_node *parent, const char *name)
22 : {
23 0 : char *buf;
24 :
25 0 : buf = kzalloc(PATH_MAX, GFP_KERNEL);
26 0 : if (buf)
27 0 : kernfs_path(parent, buf, PATH_MAX);
28 :
29 0 : pr_warn("cannot create duplicate filename '%s/%s'\n", buf, name);
30 0 : dump_stack();
31 :
32 0 : kfree(buf);
33 0 : }
34 :
35 : /**
36 : * sysfs_create_dir_ns - create a directory for an object with a namespace tag
37 : * @kobj: object we're creating directory for
38 : * @ns: the namespace tag to use
39 : */
40 544 : int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
41 : {
42 544 : struct kernfs_node *parent, *kn;
43 544 : kuid_t uid;
44 544 : kgid_t gid;
45 :
46 544 : if (WARN_ON(!kobj))
47 : return -EINVAL;
48 :
49 544 : if (kobj->parent)
50 535 : parent = kobj->parent->sd;
51 : else
52 9 : parent = sysfs_root_kn;
53 :
54 544 : if (!parent)
55 : return -ENOENT;
56 :
57 544 : kobject_get_ownership(kobj, &uid, &gid);
58 :
59 544 : kn = kernfs_create_dir_ns(parent, kobject_name(kobj),
60 : S_IRWXU | S_IRUGO | S_IXUGO, uid, gid,
61 : kobj, ns);
62 544 : if (IS_ERR(kn)) {
63 0 : if (PTR_ERR(kn) == -EEXIST)
64 0 : sysfs_warn_dup(parent, kobject_name(kobj));
65 0 : return PTR_ERR(kn);
66 : }
67 :
68 544 : kobj->sd = kn;
69 544 : return 0;
70 : }
71 :
72 : /**
73 : * sysfs_remove_dir - remove an object's directory.
74 : * @kobj: object.
75 : *
76 : * The only thing special about this is that we remove any files in
77 : * the directory before we remove the directory, and we've inlined
78 : * what used to be sysfs_rmdir() below, instead of calling separately.
79 : */
80 1 : void sysfs_remove_dir(struct kobject *kobj)
81 : {
82 1 : struct kernfs_node *kn = kobj->sd;
83 :
84 : /*
85 : * In general, kboject owner is responsible for ensuring removal
86 : * doesn't race with other operations and sysfs doesn't provide any
87 : * protection; however, when @kobj is used as a symlink target, the
88 : * symlinking entity usually doesn't own @kobj and thus has no
89 : * control over removal. @kobj->sd may be removed anytime
90 : * and symlink code may end up dereferencing an already freed node.
91 : *
92 : * sysfs_symlink_target_lock synchronizes @kobj->sd
93 : * disassociation against symlink operations so that symlink code
94 : * can safely dereference @kobj->sd.
95 : */
96 1 : spin_lock(&sysfs_symlink_target_lock);
97 1 : kobj->sd = NULL;
98 1 : spin_unlock(&sysfs_symlink_target_lock);
99 :
100 1 : if (kn) {
101 1 : WARN_ON_ONCE(kernfs_type(kn) != KERNFS_DIR);
102 1 : kernfs_remove(kn);
103 : }
104 1 : }
105 :
106 0 : int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
107 : const void *new_ns)
108 : {
109 0 : struct kernfs_node *parent;
110 0 : int ret;
111 :
112 0 : parent = kernfs_get_parent(kobj->sd);
113 0 : ret = kernfs_rename_ns(kobj->sd, parent, new_name, new_ns);
114 0 : kernfs_put(parent);
115 0 : return ret;
116 : }
117 :
118 0 : int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
119 : const void *new_ns)
120 : {
121 0 : struct kernfs_node *kn = kobj->sd;
122 0 : struct kernfs_node *new_parent;
123 :
124 0 : new_parent = new_parent_kobj && new_parent_kobj->sd ?
125 0 : new_parent_kobj->sd : sysfs_root_kn;
126 :
127 0 : return kernfs_rename_ns(kn, new_parent, kn->name, new_ns);
128 : }
129 :
130 : /**
131 : * sysfs_create_mount_point - create an always empty directory
132 : * @parent_kobj: kobject that will contain this always empty directory
133 : * @name: The name of the always empty directory to add
134 : */
135 3 : int sysfs_create_mount_point(struct kobject *parent_kobj, const char *name)
136 : {
137 3 : struct kernfs_node *kn, *parent = parent_kobj->sd;
138 :
139 3 : kn = kernfs_create_empty_dir(parent, name);
140 3 : if (IS_ERR(kn)) {
141 0 : if (PTR_ERR(kn) == -EEXIST)
142 0 : sysfs_warn_dup(parent, name);
143 0 : return PTR_ERR(kn);
144 : }
145 :
146 : return 0;
147 : }
148 : EXPORT_SYMBOL_GPL(sysfs_create_mount_point);
149 :
150 : /**
151 : * sysfs_remove_mount_point - remove an always empty directory.
152 : * @parent_kobj: kobject that will contain this always empty directory
153 : * @name: The name of the always empty directory to remove
154 : *
155 : */
156 0 : void sysfs_remove_mount_point(struct kobject *parent_kobj, const char *name)
157 : {
158 0 : struct kernfs_node *parent = parent_kobj->sd;
159 :
160 0 : kernfs_remove_by_name_ns(parent, name, NULL);
161 0 : }
162 : EXPORT_SYMBOL_GPL(sysfs_remove_mount_point);
|