Blame view

fs/sysfs/dir.c 4.12 KB
619daeeeb   Greg Kroah-Hartman   sysfs: use SPDX i...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
6d66f5cd2   Tejun Heo   sysfs: add copyri...
3
4
5
6
7
8
   * fs/sysfs/dir.c - sysfs core and dir operation implementation
   *
   * Copyright (c) 2001-3 Patrick Mochel
   * Copyright (c) 2007 SUSE Linux Products GmbH
   * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
   *
0c1bc6b84   Mauro Carvalho Chehab   docs: filesystems...
9
   * Please see Documentation/filesystems/sysfs.rst for more information.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
   */
5d54f948a   Greg Kroah-Hartman   sysfs: turn WARN(...
11
  #define pr_fmt(fmt)	"sysfs: " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
  
  #include <linux/fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
  #include <linux/kobject.h>
c6f877338   Robert P. J. Day   SYSFS: Explicitly...
15
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include "sysfs.h"
0cae60f91   Tejun Heo   sysfs: rename sys...
17
  DEFINE_SPINLOCK(sysfs_symlink_target_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18

324a56e16   Tejun Heo   kernfs: s/sysfs_d...
19
  void sysfs_warn_dup(struct kernfs_node *parent, const char *name)
d1c1459e4   Tejun Heo   sysfs: separate o...
20
  {
3abb1d90f   Tejun Heo   kernfs: make kern...
21
  	char *buf;
d1c1459e4   Tejun Heo   sysfs: separate o...
22

3eef34ad7   Tejun Heo   kernfs: implement...
23
24
  	buf = kzalloc(PATH_MAX, GFP_KERNEL);
  	if (buf)
3abb1d90f   Tejun Heo   kernfs: make kern...
25
  		kernfs_path(parent, buf, PATH_MAX);
d1c1459e4   Tejun Heo   sysfs: separate o...
26

5d54f948a   Greg Kroah-Hartman   sysfs: turn WARN(...
27
28
29
  	pr_warn("cannot create duplicate filename '%s/%s'
  ", buf, name);
  	dump_stack();
d1c1459e4   Tejun Heo   sysfs: separate o...
30

3eef34ad7   Tejun Heo   kernfs: implement...
31
  	kfree(buf);
d1c1459e4   Tejun Heo   sysfs: separate o...
32
  }
425cb0291   Alex Chiang   sysfs: sysfs_add_...
33
  /**
e34ff4906   Tejun Heo   sysfs: remove kty...
34
35
36
   * sysfs_create_dir_ns - create a directory for an object with a namespace tag
   * @kobj: object we're creating directory for
   * @ns: the namespace tag to use
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
   */
e34ff4906   Tejun Heo   sysfs: remove kty...
38
  int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  {
324a56e16   Tejun Heo   kernfs: s/sysfs_d...
40
  	struct kernfs_node *parent, *kn;
5f81880d5   Dmitry Torokhov   sysfs, kobject: a...
41
42
  	kuid_t uid;
  	kgid_t gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

de96e9fea   Greg Kroah-Hartman   sysfs: convert BU...
44
45
  	if (WARN_ON(!kobj))
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46

90bc61359   Eric W. Biederman   sysfs: Remove fir...
47
  	if (kobj->parent)
324a56e16   Tejun Heo   kernfs: s/sysfs_d...
48
  		parent = kobj->parent->sd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  	else
324a56e16   Tejun Heo   kernfs: s/sysfs_d...
50
  		parent = sysfs_root_kn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51

324a56e16   Tejun Heo   kernfs: s/sysfs_d...
52
  	if (!parent)
3a198886a   Dan Williams   sysfs: handle 'pa...
53
  		return -ENOENT;
5f81880d5   Dmitry Torokhov   sysfs, kobject: a...
54
  	kobject_get_ownership(kobj, &uid, &gid);
bb8b9d095   Tejun Heo   kernfs: add @mode...
55
  	kn = kernfs_create_dir_ns(parent, kobject_name(kobj),
5f81880d5   Dmitry Torokhov   sysfs, kobject: a...
56
  				  S_IRWXU | S_IRUGO | S_IXUGO, uid, gid,
488dee96b   Dmitry Torokhov   kernfs: allow cre...
57
  				  kobj, ns);
324a56e16   Tejun Heo   kernfs: s/sysfs_d...
58
59
60
61
  	if (IS_ERR(kn)) {
  		if (PTR_ERR(kn) == -EEXIST)
  			sysfs_warn_dup(parent, kobject_name(kobj));
  		return PTR_ERR(kn);
93b2b8e4a   Tejun Heo   sysfs, kernfs: in...
62
  	}
324a56e16   Tejun Heo   kernfs: s/sysfs_d...
63
  	kobj->sd = kn;
93b2b8e4a   Tejun Heo   sysfs, kernfs: in...
64
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  }
7eed6ecb0   Tejun Heo   sysfs: move sysfs...
66
  /**
b592fcfe7   Eric W. Biederman   sysfs: Shadow dir...
67
68
69
70
71
72
73
   *	sysfs_remove_dir - remove an object's directory.
   *	@kobj:	object.
   *
   *	The only thing special about this is that we remove any files in
   *	the directory before we remove the directory, and we've inlined
   *	what used to be sysfs_rmdir() below, instead of calling separately.
   */
1b18dc2be   Greg Kroah-Hartman   sysfs: fix up spa...
74
  void sysfs_remove_dir(struct kobject *kobj)
b592fcfe7   Eric W. Biederman   sysfs: Shadow dir...
75
  {
324a56e16   Tejun Heo   kernfs: s/sysfs_d...
76
  	struct kernfs_node *kn = kobj->sd;
aecdcedaa   Tejun Heo   sysfs: implement ...
77

0cae60f91   Tejun Heo   sysfs: rename sys...
78
79
80
81
82
  	/*
  	 * In general, kboject owner is responsible for ensuring removal
  	 * doesn't race with other operations and sysfs doesn't provide any
  	 * protection; however, when @kobj is used as a symlink target, the
  	 * symlinking entity usually doesn't own @kobj and thus has no
324a56e16   Tejun Heo   kernfs: s/sysfs_d...
83
84
  	 * control over removal.  @kobj->sd may be removed anytime
  	 * and symlink code may end up dereferencing an already freed node.
0cae60f91   Tejun Heo   sysfs: rename sys...
85
  	 *
324a56e16   Tejun Heo   kernfs: s/sysfs_d...
86
87
88
  	 * sysfs_symlink_target_lock synchronizes @kobj->sd
  	 * disassociation against symlink operations so that symlink code
  	 * can safely dereference @kobj->sd.
0cae60f91   Tejun Heo   sysfs: rename sys...
89
90
  	 */
  	spin_lock(&sysfs_symlink_target_lock);
608e266a2   Tejun Heo   sysfs: make kobj ...
91
  	kobj->sd = NULL;
0cae60f91   Tejun Heo   sysfs: rename sys...
92
  	spin_unlock(&sysfs_symlink_target_lock);
aecdcedaa   Tejun Heo   sysfs: implement ...
93

324a56e16   Tejun Heo   kernfs: s/sysfs_d...
94
  	if (kn) {
df23fc39b   Tejun Heo   kernfs: s/sysfs/k...
95
  		WARN_ON_ONCE(kernfs_type(kn) != KERNFS_DIR);
324a56e16   Tejun Heo   kernfs: s/sysfs_d...
96
  		kernfs_remove(kn);
250f7c3fe   Tejun Heo   sysfs: introduce ...
97
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  }
e34ff4906   Tejun Heo   sysfs: remove kty...
99
100
  int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,
  			const void *new_ns)
ca1bab381   Eric W. Biederman   sysfs: Factor out...
101
  {
3eef34ad7   Tejun Heo   kernfs: implement...
102
103
  	struct kernfs_node *parent;
  	int ret;
3ff195b01   Eric W. Biederman   sysfs: Implement ...
104

3eef34ad7   Tejun Heo   kernfs: implement...
105
106
107
108
  	parent = kernfs_get_parent(kobj->sd);
  	ret = kernfs_rename_ns(kobj->sd, parent, new_name, new_ns);
  	kernfs_put(parent);
  	return ret;
ca1bab381   Eric W. Biederman   sysfs: Factor out...
109
  }
e34ff4906   Tejun Heo   sysfs: remove kty...
110
111
  int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,
  		      const void *new_ns)
8a82472f8   Cornelia Huck   driver core: Intr...
112
  {
324a56e16   Tejun Heo   kernfs: s/sysfs_d...
113
114
  	struct kernfs_node *kn = kobj->sd;
  	struct kernfs_node *new_parent;
8a82472f8   Cornelia Huck   driver core: Intr...
115

324a56e16   Tejun Heo   kernfs: s/sysfs_d...
116
117
  	new_parent = new_parent_kobj && new_parent_kobj->sd ?
  		new_parent_kobj->sd : sysfs_root_kn;
51225039f   Tejun Heo   sysfs: make direc...
118

adc5e8b58   Tejun Heo   kernfs: drop s_ p...
119
  	return kernfs_rename_ns(kn, new_parent, kn->name, new_ns);
8a82472f8   Cornelia Huck   driver core: Intr...
120
  }
87d2846fc   Eric W. Biederman   sysfs: Add suppor...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  
  /**
   * sysfs_create_mount_point - create an always empty directory
   * @parent_kobj:  kobject that will contain this always empty directory
   * @name: The name of the always empty directory to add
   */
  int sysfs_create_mount_point(struct kobject *parent_kobj, const char *name)
  {
  	struct kernfs_node *kn, *parent = parent_kobj->sd;
  
  	kn = kernfs_create_empty_dir(parent, name);
  	if (IS_ERR(kn)) {
  		if (PTR_ERR(kn) == -EEXIST)
  			sysfs_warn_dup(parent, name);
  		return PTR_ERR(kn);
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(sysfs_create_mount_point);
  
  /**
   *	sysfs_remove_mount_point - remove an always empty directory.
   *	@parent_kobj: kobject that will contain this always empty directory
   *	@name: The name of the always empty directory to remove
   *
   */
  void sysfs_remove_mount_point(struct kobject *parent_kobj, const char *name)
  {
  	struct kernfs_node *parent = parent_kobj->sd;
  
  	kernfs_remove_by_name_ns(parent, name, NULL);
  }
  EXPORT_SYMBOL_GPL(sysfs_remove_mount_point);