brintos

brintos / linux-shallow public Read only

0
0
Text · 4.1 KiB · 4df2afa Raw
162 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * fs/sysfs/dir.c - sysfs core and dir operation implementation4 *5 * Copyright (c) 2001-3 Patrick Mochel6 * Copyright (c) 2007 SUSE Linux Products GmbH7 * 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: " fmt13 14#include <linux/fs.h>15#include <linux/kobject.h>16#include <linux/slab.h>17#include "sysfs.h"18 19DEFINE_SPINLOCK(sysfs_symlink_target_lock);20 21void sysfs_warn_dup(struct kernfs_node *parent, const char *name)22{23	char *buf;24 25	buf = kzalloc(PATH_MAX, GFP_KERNEL);26	if (buf)27		kernfs_path(parent, buf, PATH_MAX);28 29	pr_warn("cannot create duplicate filename '%s/%s'\n", buf, name);30	dump_stack();31 32	kfree(buf);33}34 35/**36 * sysfs_create_dir_ns - create a directory for an object with a namespace tag37 * @kobj: object we're creating directory for38 * @ns: the namespace tag to use39 */40int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)41{42	struct kernfs_node *parent, *kn;43	kuid_t uid;44	kgid_t gid;45 46	if (WARN_ON(!kobj))47		return -EINVAL;48 49	if (kobj->parent)50		parent = kobj->parent->sd;51	else52		parent = sysfs_root_kn;53 54	if (!parent)55		return -ENOENT;56 57	kobject_get_ownership(kobj, &uid, &gid);58 59	kn = kernfs_create_dir_ns(parent, kobject_name(kobj), 0755, uid, gid,60				  kobj, ns);61	if (IS_ERR(kn)) {62		if (PTR_ERR(kn) == -EEXIST)63			sysfs_warn_dup(parent, kobject_name(kobj));64		return PTR_ERR(kn);65	}66 67	kobj->sd = kn;68	return 0;69}70 71/**72 *	sysfs_remove_dir - remove an object's directory.73 *	@kobj:	object.74 *75 *	The only thing special about this is that we remove any files in76 *	the directory before we remove the directory, and we've inlined77 *	what used to be sysfs_rmdir() below, instead of calling separately.78 */79void sysfs_remove_dir(struct kobject *kobj)80{81	struct kernfs_node *kn = kobj->sd;82 83	/*84	 * In general, kobject owner is responsible for ensuring removal85	 * doesn't race with other operations and sysfs doesn't provide any86	 * protection; however, when @kobj is used as a symlink target, the87	 * symlinking entity usually doesn't own @kobj and thus has no88	 * control over removal.  @kobj->sd may be removed anytime89	 * and symlink code may end up dereferencing an already freed node.90	 *91	 * sysfs_symlink_target_lock synchronizes @kobj->sd92	 * disassociation against symlink operations so that symlink code93	 * can safely dereference @kobj->sd.94	 */95	spin_lock(&sysfs_symlink_target_lock);96	kobj->sd = NULL;97	spin_unlock(&sysfs_symlink_target_lock);98 99	if (kn) {100		WARN_ON_ONCE(kernfs_type(kn) != KERNFS_DIR);101		kernfs_remove(kn);102	}103}104 105int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name,106			const void *new_ns)107{108	struct kernfs_node *parent;109	int ret;110 111	parent = kernfs_get_parent(kobj->sd);112	ret = kernfs_rename_ns(kobj->sd, parent, new_name, new_ns);113	kernfs_put(parent);114	return ret;115}116 117int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj,118		      const void *new_ns)119{120	struct kernfs_node *kn = kobj->sd;121	struct kernfs_node *new_parent;122 123	new_parent = new_parent_kobj && new_parent_kobj->sd ?124		new_parent_kobj->sd : sysfs_root_kn;125 126	return kernfs_rename_ns(kn, new_parent, kn->name, new_ns);127}128 129/**130 * sysfs_create_mount_point - create an always empty directory131 * @parent_kobj:  kobject that will contain this always empty directory132 * @name: The name of the always empty directory to add133 */134int sysfs_create_mount_point(struct kobject *parent_kobj, const char *name)135{136	struct kernfs_node *kn, *parent = parent_kobj->sd;137 138	kn = kernfs_create_empty_dir(parent, name);139	if (IS_ERR(kn)) {140		if (PTR_ERR(kn) == -EEXIST)141			sysfs_warn_dup(parent, name);142		return PTR_ERR(kn);143	}144 145	return 0;146}147EXPORT_SYMBOL_GPL(sysfs_create_mount_point);148 149/**150 *	sysfs_remove_mount_point - remove an always empty directory.151 *	@parent_kobj: kobject that will contain this always empty directory152 *	@name: The name of the always empty directory to remove153 *154 */155void sysfs_remove_mount_point(struct kobject *parent_kobj, const char *name)156{157	struct kernfs_node *parent = parent_kobj->sd;158 159	kernfs_remove_by_name_ns(parent, name, NULL);160}161EXPORT_SYMBOL_GPL(sysfs_remove_mount_point);162