cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dir.c (4185B)


      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
     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 tag
     37 * @kobj: object we're creating directory for
     38 * @ns: the namespace tag to use
     39 */
     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	else
     52		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 in
     76 *	the directory before we remove the directory, and we've inlined
     77 *	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, kboject owner is responsible for ensuring removal
     85	 * doesn't race with other operations and sysfs doesn't provide any
     86	 * protection; however, when @kobj is used as a symlink target, the
     87	 * symlinking entity usually doesn't own @kobj and thus has no
     88	 * control over removal.  @kobj->sd may be removed anytime
     89	 * and symlink code may end up dereferencing an already freed node.
     90	 *
     91	 * sysfs_symlink_target_lock synchronizes @kobj->sd
     92	 * disassociation against symlink operations so that symlink code
     93	 * 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 directory
    131 * @parent_kobj:  kobject that will contain this always empty directory
    132 * @name: The name of the always empty directory to add
    133 */
    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 directory
    152 *	@name: The name of the always empty directory to remove
    153 *
    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);