162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * inode.c - part of debugfs, a tiny little debug file system 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004,2019 Greg Kroah-Hartman <greg@kroah.com> 662306a36Sopenharmony_ci * Copyright (C) 2004 IBM Inc. 762306a36Sopenharmony_ci * Copyright (C) 2019 Linux Foundation <gregkh@linuxfoundation.org> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * debugfs is for people to use instead of /proc or /sys. 1062306a36Sopenharmony_ci * See ./Documentation/core-api/kernel-api.rst for more details. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define pr_fmt(fmt) "debugfs: " fmt 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/fs.h> 1762306a36Sopenharmony_ci#include <linux/mount.h> 1862306a36Sopenharmony_ci#include <linux/pagemap.h> 1962306a36Sopenharmony_ci#include <linux/init.h> 2062306a36Sopenharmony_ci#include <linux/kobject.h> 2162306a36Sopenharmony_ci#include <linux/namei.h> 2262306a36Sopenharmony_ci#include <linux/debugfs.h> 2362306a36Sopenharmony_ci#include <linux/fsnotify.h> 2462306a36Sopenharmony_ci#include <linux/string.h> 2562306a36Sopenharmony_ci#include <linux/seq_file.h> 2662306a36Sopenharmony_ci#include <linux/parser.h> 2762306a36Sopenharmony_ci#include <linux/magic.h> 2862306a36Sopenharmony_ci#include <linux/slab.h> 2962306a36Sopenharmony_ci#include <linux/security.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include "internal.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define DEBUGFS_DEFAULT_MODE 0700 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic struct vfsmount *debugfs_mount; 3662306a36Sopenharmony_cistatic int debugfs_mount_count; 3762306a36Sopenharmony_cistatic bool debugfs_registered; 3862306a36Sopenharmony_cistatic unsigned int debugfs_allow __ro_after_init = DEFAULT_DEBUGFS_ALLOW_BITS; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* 4162306a36Sopenharmony_ci * Don't allow access attributes to be changed whilst the kernel is locked down 4262306a36Sopenharmony_ci * so that we can use the file mode as part of a heuristic to determine whether 4362306a36Sopenharmony_ci * to lock down individual files. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_cistatic int debugfs_setattr(struct mnt_idmap *idmap, 4662306a36Sopenharmony_ci struct dentry *dentry, struct iattr *ia) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci int ret; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (ia->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) { 5162306a36Sopenharmony_ci ret = security_locked_down(LOCKDOWN_DEBUGFS); 5262306a36Sopenharmony_ci if (ret) 5362306a36Sopenharmony_ci return ret; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci return simple_setattr(&nop_mnt_idmap, dentry, ia); 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic const struct inode_operations debugfs_file_inode_operations = { 5962306a36Sopenharmony_ci .setattr = debugfs_setattr, 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_cistatic const struct inode_operations debugfs_dir_inode_operations = { 6262306a36Sopenharmony_ci .lookup = simple_lookup, 6362306a36Sopenharmony_ci .setattr = debugfs_setattr, 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_cistatic const struct inode_operations debugfs_symlink_inode_operations = { 6662306a36Sopenharmony_ci .get_link = simple_get_link, 6762306a36Sopenharmony_ci .setattr = debugfs_setattr, 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic struct inode *debugfs_get_inode(struct super_block *sb) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct inode *inode = new_inode(sb); 7362306a36Sopenharmony_ci if (inode) { 7462306a36Sopenharmony_ci inode->i_ino = get_next_ino(); 7562306a36Sopenharmony_ci inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode); 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci return inode; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistruct debugfs_mount_opts { 8162306a36Sopenharmony_ci kuid_t uid; 8262306a36Sopenharmony_ci kgid_t gid; 8362306a36Sopenharmony_ci umode_t mode; 8462306a36Sopenharmony_ci /* Opt_* bitfield. */ 8562306a36Sopenharmony_ci unsigned int opts; 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cienum { 8962306a36Sopenharmony_ci Opt_uid, 9062306a36Sopenharmony_ci Opt_gid, 9162306a36Sopenharmony_ci Opt_mode, 9262306a36Sopenharmony_ci Opt_err 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic const match_table_t tokens = { 9662306a36Sopenharmony_ci {Opt_uid, "uid=%u"}, 9762306a36Sopenharmony_ci {Opt_gid, "gid=%u"}, 9862306a36Sopenharmony_ci {Opt_mode, "mode=%o"}, 9962306a36Sopenharmony_ci {Opt_err, NULL} 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistruct debugfs_fs_info { 10362306a36Sopenharmony_ci struct debugfs_mount_opts mount_opts; 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 10962306a36Sopenharmony_ci int option; 11062306a36Sopenharmony_ci int token; 11162306a36Sopenharmony_ci kuid_t uid; 11262306a36Sopenharmony_ci kgid_t gid; 11362306a36Sopenharmony_ci char *p; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci opts->opts = 0; 11662306a36Sopenharmony_ci opts->mode = DEBUGFS_DEFAULT_MODE; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci while ((p = strsep(&data, ",")) != NULL) { 11962306a36Sopenharmony_ci if (!*p) 12062306a36Sopenharmony_ci continue; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci token = match_token(p, tokens, args); 12362306a36Sopenharmony_ci switch (token) { 12462306a36Sopenharmony_ci case Opt_uid: 12562306a36Sopenharmony_ci if (match_int(&args[0], &option)) 12662306a36Sopenharmony_ci return -EINVAL; 12762306a36Sopenharmony_ci uid = make_kuid(current_user_ns(), option); 12862306a36Sopenharmony_ci if (!uid_valid(uid)) 12962306a36Sopenharmony_ci return -EINVAL; 13062306a36Sopenharmony_ci opts->uid = uid; 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci case Opt_gid: 13362306a36Sopenharmony_ci if (match_int(&args[0], &option)) 13462306a36Sopenharmony_ci return -EINVAL; 13562306a36Sopenharmony_ci gid = make_kgid(current_user_ns(), option); 13662306a36Sopenharmony_ci if (!gid_valid(gid)) 13762306a36Sopenharmony_ci return -EINVAL; 13862306a36Sopenharmony_ci opts->gid = gid; 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci case Opt_mode: 14162306a36Sopenharmony_ci if (match_octal(&args[0], &option)) 14262306a36Sopenharmony_ci return -EINVAL; 14362306a36Sopenharmony_ci opts->mode = option & S_IALLUGO; 14462306a36Sopenharmony_ci break; 14562306a36Sopenharmony_ci /* 14662306a36Sopenharmony_ci * We might like to report bad mount options here; 14762306a36Sopenharmony_ci * but traditionally debugfs has ignored all mount options 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci opts->opts |= BIT(token); 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic void _debugfs_apply_options(struct super_block *sb, bool remount) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct debugfs_fs_info *fsi = sb->s_fs_info; 16062306a36Sopenharmony_ci struct inode *inode = d_inode(sb->s_root); 16162306a36Sopenharmony_ci struct debugfs_mount_opts *opts = &fsi->mount_opts; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* 16462306a36Sopenharmony_ci * On remount, only reset mode/uid/gid if they were provided as mount 16562306a36Sopenharmony_ci * options. 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (!remount || opts->opts & BIT(Opt_mode)) { 16962306a36Sopenharmony_ci inode->i_mode &= ~S_IALLUGO; 17062306a36Sopenharmony_ci inode->i_mode |= opts->mode; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (!remount || opts->opts & BIT(Opt_uid)) 17462306a36Sopenharmony_ci inode->i_uid = opts->uid; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (!remount || opts->opts & BIT(Opt_gid)) 17762306a36Sopenharmony_ci inode->i_gid = opts->gid; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic void debugfs_apply_options(struct super_block *sb) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci _debugfs_apply_options(sb, false); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic void debugfs_apply_options_remount(struct super_block *sb) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci _debugfs_apply_options(sb, true); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic int debugfs_remount(struct super_block *sb, int *flags, char *data) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci int err; 19362306a36Sopenharmony_ci struct debugfs_fs_info *fsi = sb->s_fs_info; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci sync_filesystem(sb); 19662306a36Sopenharmony_ci err = debugfs_parse_options(data, &fsi->mount_opts); 19762306a36Sopenharmony_ci if (err) 19862306a36Sopenharmony_ci goto fail; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci debugfs_apply_options_remount(sb); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cifail: 20362306a36Sopenharmony_ci return err; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic int debugfs_show_options(struct seq_file *m, struct dentry *root) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct debugfs_fs_info *fsi = root->d_sb->s_fs_info; 20962306a36Sopenharmony_ci struct debugfs_mount_opts *opts = &fsi->mount_opts; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (!uid_eq(opts->uid, GLOBAL_ROOT_UID)) 21262306a36Sopenharmony_ci seq_printf(m, ",uid=%u", 21362306a36Sopenharmony_ci from_kuid_munged(&init_user_ns, opts->uid)); 21462306a36Sopenharmony_ci if (!gid_eq(opts->gid, GLOBAL_ROOT_GID)) 21562306a36Sopenharmony_ci seq_printf(m, ",gid=%u", 21662306a36Sopenharmony_ci from_kgid_munged(&init_user_ns, opts->gid)); 21762306a36Sopenharmony_ci if (opts->mode != DEBUGFS_DEFAULT_MODE) 21862306a36Sopenharmony_ci seq_printf(m, ",mode=%o", opts->mode); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return 0; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic void debugfs_free_inode(struct inode *inode) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci if (S_ISLNK(inode->i_mode)) 22662306a36Sopenharmony_ci kfree(inode->i_link); 22762306a36Sopenharmony_ci free_inode_nonrcu(inode); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic const struct super_operations debugfs_super_operations = { 23162306a36Sopenharmony_ci .statfs = simple_statfs, 23262306a36Sopenharmony_ci .remount_fs = debugfs_remount, 23362306a36Sopenharmony_ci .show_options = debugfs_show_options, 23462306a36Sopenharmony_ci .free_inode = debugfs_free_inode, 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic void debugfs_release_dentry(struct dentry *dentry) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct debugfs_fsdata *fsd = dentry->d_fsdata; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) 24262306a36Sopenharmony_ci return; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci kfree(fsd); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic struct vfsmount *debugfs_automount(struct path *path) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct debugfs_fsdata *fsd = path->dentry->d_fsdata; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return fsd->automount(path->dentry, d_inode(path->dentry)->i_private); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic const struct dentry_operations debugfs_dops = { 25562306a36Sopenharmony_ci .d_delete = always_delete_dentry, 25662306a36Sopenharmony_ci .d_release = debugfs_release_dentry, 25762306a36Sopenharmony_ci .d_automount = debugfs_automount, 25862306a36Sopenharmony_ci}; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic int debug_fill_super(struct super_block *sb, void *data, int silent) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci static const struct tree_descr debug_files[] = {{""}}; 26362306a36Sopenharmony_ci struct debugfs_fs_info *fsi; 26462306a36Sopenharmony_ci int err; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci fsi = kzalloc(sizeof(struct debugfs_fs_info), GFP_KERNEL); 26762306a36Sopenharmony_ci sb->s_fs_info = fsi; 26862306a36Sopenharmony_ci if (!fsi) { 26962306a36Sopenharmony_ci err = -ENOMEM; 27062306a36Sopenharmony_ci goto fail; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci err = debugfs_parse_options(data, &fsi->mount_opts); 27462306a36Sopenharmony_ci if (err) 27562306a36Sopenharmony_ci goto fail; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci err = simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); 27862306a36Sopenharmony_ci if (err) 27962306a36Sopenharmony_ci goto fail; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci sb->s_op = &debugfs_super_operations; 28262306a36Sopenharmony_ci sb->s_d_op = &debugfs_dops; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci debugfs_apply_options(sb); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci return 0; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cifail: 28962306a36Sopenharmony_ci kfree(fsi); 29062306a36Sopenharmony_ci sb->s_fs_info = NULL; 29162306a36Sopenharmony_ci return err; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic struct dentry *debug_mount(struct file_system_type *fs_type, 29562306a36Sopenharmony_ci int flags, const char *dev_name, 29662306a36Sopenharmony_ci void *data) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci if (!(debugfs_allow & DEBUGFS_ALLOW_API)) 29962306a36Sopenharmony_ci return ERR_PTR(-EPERM); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci return mount_single(fs_type, flags, data, debug_fill_super); 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic struct file_system_type debug_fs_type = { 30562306a36Sopenharmony_ci .owner = THIS_MODULE, 30662306a36Sopenharmony_ci .name = "debugfs", 30762306a36Sopenharmony_ci .mount = debug_mount, 30862306a36Sopenharmony_ci .kill_sb = kill_litter_super, 30962306a36Sopenharmony_ci}; 31062306a36Sopenharmony_ciMODULE_ALIAS_FS("debugfs"); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci/** 31362306a36Sopenharmony_ci * debugfs_lookup() - look up an existing debugfs file 31462306a36Sopenharmony_ci * @name: a pointer to a string containing the name of the file to look up. 31562306a36Sopenharmony_ci * @parent: a pointer to the parent dentry of the file. 31662306a36Sopenharmony_ci * 31762306a36Sopenharmony_ci * This function will return a pointer to a dentry if it succeeds. If the file 31862306a36Sopenharmony_ci * doesn't exist or an error occurs, %NULL will be returned. The returned 31962306a36Sopenharmony_ci * dentry must be passed to dput() when it is no longer needed. 32062306a36Sopenharmony_ci * 32162306a36Sopenharmony_ci * If debugfs is not enabled in the kernel, the value -%ENODEV will be 32262306a36Sopenharmony_ci * returned. 32362306a36Sopenharmony_ci */ 32462306a36Sopenharmony_cistruct dentry *debugfs_lookup(const char *name, struct dentry *parent) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct dentry *dentry; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (!debugfs_initialized() || IS_ERR_OR_NULL(name) || IS_ERR(parent)) 32962306a36Sopenharmony_ci return NULL; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (!parent) 33262306a36Sopenharmony_ci parent = debugfs_mount->mnt_root; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci dentry = lookup_positive_unlocked(name, parent, strlen(name)); 33562306a36Sopenharmony_ci if (IS_ERR(dentry)) 33662306a36Sopenharmony_ci return NULL; 33762306a36Sopenharmony_ci return dentry; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(debugfs_lookup); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic struct dentry *start_creating(const char *name, struct dentry *parent) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct dentry *dentry; 34462306a36Sopenharmony_ci int error; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (!(debugfs_allow & DEBUGFS_ALLOW_API)) 34762306a36Sopenharmony_ci return ERR_PTR(-EPERM); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (!debugfs_initialized()) 35062306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci pr_debug("creating file '%s'\n", name); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (IS_ERR(parent)) 35562306a36Sopenharmony_ci return parent; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci error = simple_pin_fs(&debug_fs_type, &debugfs_mount, 35862306a36Sopenharmony_ci &debugfs_mount_count); 35962306a36Sopenharmony_ci if (error) { 36062306a36Sopenharmony_ci pr_err("Unable to pin filesystem for file '%s'\n", name); 36162306a36Sopenharmony_ci return ERR_PTR(error); 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* If the parent is not specified, we create it in the root. 36562306a36Sopenharmony_ci * We need the root dentry to do this, which is in the super 36662306a36Sopenharmony_ci * block. A pointer to that is in the struct vfsmount that we 36762306a36Sopenharmony_ci * have around. 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci if (!parent) 37062306a36Sopenharmony_ci parent = debugfs_mount->mnt_root; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci inode_lock(d_inode(parent)); 37362306a36Sopenharmony_ci if (unlikely(IS_DEADDIR(d_inode(parent)))) 37462306a36Sopenharmony_ci dentry = ERR_PTR(-ENOENT); 37562306a36Sopenharmony_ci else 37662306a36Sopenharmony_ci dentry = lookup_one_len(name, parent, strlen(name)); 37762306a36Sopenharmony_ci if (!IS_ERR(dentry) && d_really_is_positive(dentry)) { 37862306a36Sopenharmony_ci if (d_is_dir(dentry)) 37962306a36Sopenharmony_ci pr_err("Directory '%s' with parent '%s' already present!\n", 38062306a36Sopenharmony_ci name, parent->d_name.name); 38162306a36Sopenharmony_ci else 38262306a36Sopenharmony_ci pr_err("File '%s' in directory '%s' already present!\n", 38362306a36Sopenharmony_ci name, parent->d_name.name); 38462306a36Sopenharmony_ci dput(dentry); 38562306a36Sopenharmony_ci dentry = ERR_PTR(-EEXIST); 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (IS_ERR(dentry)) { 38962306a36Sopenharmony_ci inode_unlock(d_inode(parent)); 39062306a36Sopenharmony_ci simple_release_fs(&debugfs_mount, &debugfs_mount_count); 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return dentry; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic struct dentry *failed_creating(struct dentry *dentry) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci inode_unlock(d_inode(dentry->d_parent)); 39962306a36Sopenharmony_ci dput(dentry); 40062306a36Sopenharmony_ci simple_release_fs(&debugfs_mount, &debugfs_mount_count); 40162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic struct dentry *end_creating(struct dentry *dentry) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci inode_unlock(d_inode(dentry->d_parent)); 40762306a36Sopenharmony_ci return dentry; 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic struct dentry *__debugfs_create_file(const char *name, umode_t mode, 41162306a36Sopenharmony_ci struct dentry *parent, void *data, 41262306a36Sopenharmony_ci const struct file_operations *proxy_fops, 41362306a36Sopenharmony_ci const struct file_operations *real_fops) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct dentry *dentry; 41662306a36Sopenharmony_ci struct inode *inode; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (!(mode & S_IFMT)) 41962306a36Sopenharmony_ci mode |= S_IFREG; 42062306a36Sopenharmony_ci BUG_ON(!S_ISREG(mode)); 42162306a36Sopenharmony_ci dentry = start_creating(name, parent); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (IS_ERR(dentry)) 42462306a36Sopenharmony_ci return dentry; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (!(debugfs_allow & DEBUGFS_ALLOW_API)) { 42762306a36Sopenharmony_ci failed_creating(dentry); 42862306a36Sopenharmony_ci return ERR_PTR(-EPERM); 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci inode = debugfs_get_inode(dentry->d_sb); 43262306a36Sopenharmony_ci if (unlikely(!inode)) { 43362306a36Sopenharmony_ci pr_err("out of free dentries, can not create file '%s'\n", 43462306a36Sopenharmony_ci name); 43562306a36Sopenharmony_ci return failed_creating(dentry); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci inode->i_mode = mode; 43962306a36Sopenharmony_ci inode->i_private = data; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci inode->i_op = &debugfs_file_inode_operations; 44262306a36Sopenharmony_ci inode->i_fop = proxy_fops; 44362306a36Sopenharmony_ci dentry->d_fsdata = (void *)((unsigned long)real_fops | 44462306a36Sopenharmony_ci DEBUGFS_FSDATA_IS_REAL_FOPS_BIT); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci d_instantiate(dentry, inode); 44762306a36Sopenharmony_ci fsnotify_create(d_inode(dentry->d_parent), dentry); 44862306a36Sopenharmony_ci return end_creating(dentry); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci/** 45262306a36Sopenharmony_ci * debugfs_create_file - create a file in the debugfs filesystem 45362306a36Sopenharmony_ci * @name: a pointer to a string containing the name of the file to create. 45462306a36Sopenharmony_ci * @mode: the permission that the file should have. 45562306a36Sopenharmony_ci * @parent: a pointer to the parent dentry for this file. This should be a 45662306a36Sopenharmony_ci * directory dentry if set. If this parameter is NULL, then the 45762306a36Sopenharmony_ci * file will be created in the root of the debugfs filesystem. 45862306a36Sopenharmony_ci * @data: a pointer to something that the caller will want to get to later 45962306a36Sopenharmony_ci * on. The inode.i_private pointer will point to this value on 46062306a36Sopenharmony_ci * the open() call. 46162306a36Sopenharmony_ci * @fops: a pointer to a struct file_operations that should be used for 46262306a36Sopenharmony_ci * this file. 46362306a36Sopenharmony_ci * 46462306a36Sopenharmony_ci * This is the basic "create a file" function for debugfs. It allows for a 46562306a36Sopenharmony_ci * wide range of flexibility in creating a file, or a directory (if you want 46662306a36Sopenharmony_ci * to create a directory, the debugfs_create_dir() function is 46762306a36Sopenharmony_ci * recommended to be used instead.) 46862306a36Sopenharmony_ci * 46962306a36Sopenharmony_ci * This function will return a pointer to a dentry if it succeeds. This 47062306a36Sopenharmony_ci * pointer must be passed to the debugfs_remove() function when the file is 47162306a36Sopenharmony_ci * to be removed (no automatic cleanup happens if your module is unloaded, 47262306a36Sopenharmony_ci * you are responsible here.) If an error occurs, ERR_PTR(-ERROR) will be 47362306a36Sopenharmony_ci * returned. 47462306a36Sopenharmony_ci * 47562306a36Sopenharmony_ci * If debugfs is not enabled in the kernel, the value -%ENODEV will be 47662306a36Sopenharmony_ci * returned. 47762306a36Sopenharmony_ci * 47862306a36Sopenharmony_ci * NOTE: it's expected that most callers should _ignore_ the errors returned 47962306a36Sopenharmony_ci * by this function. Other debugfs functions handle the fact that the "dentry" 48062306a36Sopenharmony_ci * passed to them could be an error and they don't crash in that case. 48162306a36Sopenharmony_ci * Drivers should generally work fine even if debugfs fails to init anyway. 48262306a36Sopenharmony_ci */ 48362306a36Sopenharmony_cistruct dentry *debugfs_create_file(const char *name, umode_t mode, 48462306a36Sopenharmony_ci struct dentry *parent, void *data, 48562306a36Sopenharmony_ci const struct file_operations *fops) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci return __debugfs_create_file(name, mode, parent, data, 48962306a36Sopenharmony_ci fops ? &debugfs_full_proxy_file_operations : 49062306a36Sopenharmony_ci &debugfs_noop_file_operations, 49162306a36Sopenharmony_ci fops); 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(debugfs_create_file); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci/** 49662306a36Sopenharmony_ci * debugfs_create_file_unsafe - create a file in the debugfs filesystem 49762306a36Sopenharmony_ci * @name: a pointer to a string containing the name of the file to create. 49862306a36Sopenharmony_ci * @mode: the permission that the file should have. 49962306a36Sopenharmony_ci * @parent: a pointer to the parent dentry for this file. This should be a 50062306a36Sopenharmony_ci * directory dentry if set. If this parameter is NULL, then the 50162306a36Sopenharmony_ci * file will be created in the root of the debugfs filesystem. 50262306a36Sopenharmony_ci * @data: a pointer to something that the caller will want to get to later 50362306a36Sopenharmony_ci * on. The inode.i_private pointer will point to this value on 50462306a36Sopenharmony_ci * the open() call. 50562306a36Sopenharmony_ci * @fops: a pointer to a struct file_operations that should be used for 50662306a36Sopenharmony_ci * this file. 50762306a36Sopenharmony_ci * 50862306a36Sopenharmony_ci * debugfs_create_file_unsafe() is completely analogous to 50962306a36Sopenharmony_ci * debugfs_create_file(), the only difference being that the fops 51062306a36Sopenharmony_ci * handed it will not get protected against file removals by the 51162306a36Sopenharmony_ci * debugfs core. 51262306a36Sopenharmony_ci * 51362306a36Sopenharmony_ci * It is your responsibility to protect your struct file_operation 51462306a36Sopenharmony_ci * methods against file removals by means of debugfs_file_get() 51562306a36Sopenharmony_ci * and debugfs_file_put(). ->open() is still protected by 51662306a36Sopenharmony_ci * debugfs though. 51762306a36Sopenharmony_ci * 51862306a36Sopenharmony_ci * Any struct file_operations defined by means of 51962306a36Sopenharmony_ci * DEFINE_DEBUGFS_ATTRIBUTE() is protected against file removals and 52062306a36Sopenharmony_ci * thus, may be used here. 52162306a36Sopenharmony_ci */ 52262306a36Sopenharmony_cistruct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode, 52362306a36Sopenharmony_ci struct dentry *parent, void *data, 52462306a36Sopenharmony_ci const struct file_operations *fops) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci return __debugfs_create_file(name, mode, parent, data, 52862306a36Sopenharmony_ci fops ? &debugfs_open_proxy_file_operations : 52962306a36Sopenharmony_ci &debugfs_noop_file_operations, 53062306a36Sopenharmony_ci fops); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(debugfs_create_file_unsafe); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci/** 53562306a36Sopenharmony_ci * debugfs_create_file_size - create a file in the debugfs filesystem 53662306a36Sopenharmony_ci * @name: a pointer to a string containing the name of the file to create. 53762306a36Sopenharmony_ci * @mode: the permission that the file should have. 53862306a36Sopenharmony_ci * @parent: a pointer to the parent dentry for this file. This should be a 53962306a36Sopenharmony_ci * directory dentry if set. If this parameter is NULL, then the 54062306a36Sopenharmony_ci * file will be created in the root of the debugfs filesystem. 54162306a36Sopenharmony_ci * @data: a pointer to something that the caller will want to get to later 54262306a36Sopenharmony_ci * on. The inode.i_private pointer will point to this value on 54362306a36Sopenharmony_ci * the open() call. 54462306a36Sopenharmony_ci * @fops: a pointer to a struct file_operations that should be used for 54562306a36Sopenharmony_ci * this file. 54662306a36Sopenharmony_ci * @file_size: initial file size 54762306a36Sopenharmony_ci * 54862306a36Sopenharmony_ci * This is the basic "create a file" function for debugfs. It allows for a 54962306a36Sopenharmony_ci * wide range of flexibility in creating a file, or a directory (if you want 55062306a36Sopenharmony_ci * to create a directory, the debugfs_create_dir() function is 55162306a36Sopenharmony_ci * recommended to be used instead.) 55262306a36Sopenharmony_ci */ 55362306a36Sopenharmony_civoid debugfs_create_file_size(const char *name, umode_t mode, 55462306a36Sopenharmony_ci struct dentry *parent, void *data, 55562306a36Sopenharmony_ci const struct file_operations *fops, 55662306a36Sopenharmony_ci loff_t file_size) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci struct dentry *de = debugfs_create_file(name, mode, parent, data, fops); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (!IS_ERR(de)) 56162306a36Sopenharmony_ci d_inode(de)->i_size = file_size; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(debugfs_create_file_size); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci/** 56662306a36Sopenharmony_ci * debugfs_create_dir - create a directory in the debugfs filesystem 56762306a36Sopenharmony_ci * @name: a pointer to a string containing the name of the directory to 56862306a36Sopenharmony_ci * create. 56962306a36Sopenharmony_ci * @parent: a pointer to the parent dentry for this file. This should be a 57062306a36Sopenharmony_ci * directory dentry if set. If this parameter is NULL, then the 57162306a36Sopenharmony_ci * directory will be created in the root of the debugfs filesystem. 57262306a36Sopenharmony_ci * 57362306a36Sopenharmony_ci * This function creates a directory in debugfs with the given name. 57462306a36Sopenharmony_ci * 57562306a36Sopenharmony_ci * This function will return a pointer to a dentry if it succeeds. This 57662306a36Sopenharmony_ci * pointer must be passed to the debugfs_remove() function when the file is 57762306a36Sopenharmony_ci * to be removed (no automatic cleanup happens if your module is unloaded, 57862306a36Sopenharmony_ci * you are responsible here.) If an error occurs, ERR_PTR(-ERROR) will be 57962306a36Sopenharmony_ci * returned. 58062306a36Sopenharmony_ci * 58162306a36Sopenharmony_ci * If debugfs is not enabled in the kernel, the value -%ENODEV will be 58262306a36Sopenharmony_ci * returned. 58362306a36Sopenharmony_ci * 58462306a36Sopenharmony_ci * NOTE: it's expected that most callers should _ignore_ the errors returned 58562306a36Sopenharmony_ci * by this function. Other debugfs functions handle the fact that the "dentry" 58662306a36Sopenharmony_ci * passed to them could be an error and they don't crash in that case. 58762306a36Sopenharmony_ci * Drivers should generally work fine even if debugfs fails to init anyway. 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_cistruct dentry *debugfs_create_dir(const char *name, struct dentry *parent) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci struct dentry *dentry = start_creating(name, parent); 59262306a36Sopenharmony_ci struct inode *inode; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (IS_ERR(dentry)) 59562306a36Sopenharmony_ci return dentry; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (!(debugfs_allow & DEBUGFS_ALLOW_API)) { 59862306a36Sopenharmony_ci failed_creating(dentry); 59962306a36Sopenharmony_ci return ERR_PTR(-EPERM); 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci inode = debugfs_get_inode(dentry->d_sb); 60362306a36Sopenharmony_ci if (unlikely(!inode)) { 60462306a36Sopenharmony_ci pr_err("out of free dentries, can not create directory '%s'\n", 60562306a36Sopenharmony_ci name); 60662306a36Sopenharmony_ci return failed_creating(dentry); 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; 61062306a36Sopenharmony_ci inode->i_op = &debugfs_dir_inode_operations; 61162306a36Sopenharmony_ci inode->i_fop = &simple_dir_operations; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* directory inodes start off with i_nlink == 2 (for "." entry) */ 61462306a36Sopenharmony_ci inc_nlink(inode); 61562306a36Sopenharmony_ci d_instantiate(dentry, inode); 61662306a36Sopenharmony_ci inc_nlink(d_inode(dentry->d_parent)); 61762306a36Sopenharmony_ci fsnotify_mkdir(d_inode(dentry->d_parent), dentry); 61862306a36Sopenharmony_ci return end_creating(dentry); 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(debugfs_create_dir); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci/** 62362306a36Sopenharmony_ci * debugfs_create_automount - create automount point in the debugfs filesystem 62462306a36Sopenharmony_ci * @name: a pointer to a string containing the name of the file to create. 62562306a36Sopenharmony_ci * @parent: a pointer to the parent dentry for this file. This should be a 62662306a36Sopenharmony_ci * directory dentry if set. If this parameter is NULL, then the 62762306a36Sopenharmony_ci * file will be created in the root of the debugfs filesystem. 62862306a36Sopenharmony_ci * @f: function to be called when pathname resolution steps on that one. 62962306a36Sopenharmony_ci * @data: opaque argument to pass to f(). 63062306a36Sopenharmony_ci * 63162306a36Sopenharmony_ci * @f should return what ->d_automount() would. 63262306a36Sopenharmony_ci */ 63362306a36Sopenharmony_cistruct dentry *debugfs_create_automount(const char *name, 63462306a36Sopenharmony_ci struct dentry *parent, 63562306a36Sopenharmony_ci debugfs_automount_t f, 63662306a36Sopenharmony_ci void *data) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct dentry *dentry = start_creating(name, parent); 63962306a36Sopenharmony_ci struct debugfs_fsdata *fsd; 64062306a36Sopenharmony_ci struct inode *inode; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (IS_ERR(dentry)) 64362306a36Sopenharmony_ci return dentry; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci fsd = kzalloc(sizeof(*fsd), GFP_KERNEL); 64662306a36Sopenharmony_ci if (!fsd) { 64762306a36Sopenharmony_ci failed_creating(dentry); 64862306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci fsd->automount = f; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci if (!(debugfs_allow & DEBUGFS_ALLOW_API)) { 65462306a36Sopenharmony_ci failed_creating(dentry); 65562306a36Sopenharmony_ci kfree(fsd); 65662306a36Sopenharmony_ci return ERR_PTR(-EPERM); 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci inode = debugfs_get_inode(dentry->d_sb); 66062306a36Sopenharmony_ci if (unlikely(!inode)) { 66162306a36Sopenharmony_ci pr_err("out of free dentries, can not create automount '%s'\n", 66262306a36Sopenharmony_ci name); 66362306a36Sopenharmony_ci kfree(fsd); 66462306a36Sopenharmony_ci return failed_creating(dentry); 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci make_empty_dir_inode(inode); 66862306a36Sopenharmony_ci inode->i_flags |= S_AUTOMOUNT; 66962306a36Sopenharmony_ci inode->i_private = data; 67062306a36Sopenharmony_ci dentry->d_fsdata = fsd; 67162306a36Sopenharmony_ci /* directory inodes start off with i_nlink == 2 (for "." entry) */ 67262306a36Sopenharmony_ci inc_nlink(inode); 67362306a36Sopenharmony_ci d_instantiate(dentry, inode); 67462306a36Sopenharmony_ci inc_nlink(d_inode(dentry->d_parent)); 67562306a36Sopenharmony_ci fsnotify_mkdir(d_inode(dentry->d_parent), dentry); 67662306a36Sopenharmony_ci return end_creating(dentry); 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ciEXPORT_SYMBOL(debugfs_create_automount); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci/** 68162306a36Sopenharmony_ci * debugfs_create_symlink- create a symbolic link in the debugfs filesystem 68262306a36Sopenharmony_ci * @name: a pointer to a string containing the name of the symbolic link to 68362306a36Sopenharmony_ci * create. 68462306a36Sopenharmony_ci * @parent: a pointer to the parent dentry for this symbolic link. This 68562306a36Sopenharmony_ci * should be a directory dentry if set. If this parameter is NULL, 68662306a36Sopenharmony_ci * then the symbolic link will be created in the root of the debugfs 68762306a36Sopenharmony_ci * filesystem. 68862306a36Sopenharmony_ci * @target: a pointer to a string containing the path to the target of the 68962306a36Sopenharmony_ci * symbolic link. 69062306a36Sopenharmony_ci * 69162306a36Sopenharmony_ci * This function creates a symbolic link with the given name in debugfs that 69262306a36Sopenharmony_ci * links to the given target path. 69362306a36Sopenharmony_ci * 69462306a36Sopenharmony_ci * This function will return a pointer to a dentry if it succeeds. This 69562306a36Sopenharmony_ci * pointer must be passed to the debugfs_remove() function when the symbolic 69662306a36Sopenharmony_ci * link is to be removed (no automatic cleanup happens if your module is 69762306a36Sopenharmony_ci * unloaded, you are responsible here.) If an error occurs, ERR_PTR(-ERROR) 69862306a36Sopenharmony_ci * will be returned. 69962306a36Sopenharmony_ci * 70062306a36Sopenharmony_ci * If debugfs is not enabled in the kernel, the value -%ENODEV will be 70162306a36Sopenharmony_ci * returned. 70262306a36Sopenharmony_ci */ 70362306a36Sopenharmony_cistruct dentry *debugfs_create_symlink(const char *name, struct dentry *parent, 70462306a36Sopenharmony_ci const char *target) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci struct dentry *dentry; 70762306a36Sopenharmony_ci struct inode *inode; 70862306a36Sopenharmony_ci char *link = kstrdup(target, GFP_KERNEL); 70962306a36Sopenharmony_ci if (!link) 71062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci dentry = start_creating(name, parent); 71362306a36Sopenharmony_ci if (IS_ERR(dentry)) { 71462306a36Sopenharmony_ci kfree(link); 71562306a36Sopenharmony_ci return dentry; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci inode = debugfs_get_inode(dentry->d_sb); 71962306a36Sopenharmony_ci if (unlikely(!inode)) { 72062306a36Sopenharmony_ci pr_err("out of free dentries, can not create symlink '%s'\n", 72162306a36Sopenharmony_ci name); 72262306a36Sopenharmony_ci kfree(link); 72362306a36Sopenharmony_ci return failed_creating(dentry); 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci inode->i_mode = S_IFLNK | S_IRWXUGO; 72662306a36Sopenharmony_ci inode->i_op = &debugfs_symlink_inode_operations; 72762306a36Sopenharmony_ci inode->i_link = link; 72862306a36Sopenharmony_ci d_instantiate(dentry, inode); 72962306a36Sopenharmony_ci return end_creating(dentry); 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(debugfs_create_symlink); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic void __debugfs_file_removed(struct dentry *dentry) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci struct debugfs_fsdata *fsd; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* 73862306a36Sopenharmony_ci * Paired with the closing smp_mb() implied by a successful 73962306a36Sopenharmony_ci * cmpxchg() in debugfs_file_get(): either 74062306a36Sopenharmony_ci * debugfs_file_get() must see a dead dentry or we must see a 74162306a36Sopenharmony_ci * debugfs_fsdata instance at ->d_fsdata here (or both). 74262306a36Sopenharmony_ci */ 74362306a36Sopenharmony_ci smp_mb(); 74462306a36Sopenharmony_ci fsd = READ_ONCE(dentry->d_fsdata); 74562306a36Sopenharmony_ci if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT) 74662306a36Sopenharmony_ci return; 74762306a36Sopenharmony_ci if (!refcount_dec_and_test(&fsd->active_users)) 74862306a36Sopenharmony_ci wait_for_completion(&fsd->active_users_drained); 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_cistatic void remove_one(struct dentry *victim) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci if (d_is_reg(victim)) 75462306a36Sopenharmony_ci __debugfs_file_removed(victim); 75562306a36Sopenharmony_ci simple_release_fs(&debugfs_mount, &debugfs_mount_count); 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci/** 75962306a36Sopenharmony_ci * debugfs_remove - recursively removes a directory 76062306a36Sopenharmony_ci * @dentry: a pointer to a the dentry of the directory to be removed. If this 76162306a36Sopenharmony_ci * parameter is NULL or an error value, nothing will be done. 76262306a36Sopenharmony_ci * 76362306a36Sopenharmony_ci * This function recursively removes a directory tree in debugfs that 76462306a36Sopenharmony_ci * was previously created with a call to another debugfs function 76562306a36Sopenharmony_ci * (like debugfs_create_file() or variants thereof.) 76662306a36Sopenharmony_ci * 76762306a36Sopenharmony_ci * This function is required to be called in order for the file to be 76862306a36Sopenharmony_ci * removed, no automatic cleanup of files will happen when a module is 76962306a36Sopenharmony_ci * removed, you are responsible here. 77062306a36Sopenharmony_ci */ 77162306a36Sopenharmony_civoid debugfs_remove(struct dentry *dentry) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci if (IS_ERR_OR_NULL(dentry)) 77462306a36Sopenharmony_ci return; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci simple_pin_fs(&debug_fs_type, &debugfs_mount, &debugfs_mount_count); 77762306a36Sopenharmony_ci simple_recursive_removal(dentry, remove_one); 77862306a36Sopenharmony_ci simple_release_fs(&debugfs_mount, &debugfs_mount_count); 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(debugfs_remove); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci/** 78362306a36Sopenharmony_ci * debugfs_lookup_and_remove - lookup a directory or file and recursively remove it 78462306a36Sopenharmony_ci * @name: a pointer to a string containing the name of the item to look up. 78562306a36Sopenharmony_ci * @parent: a pointer to the parent dentry of the item. 78662306a36Sopenharmony_ci * 78762306a36Sopenharmony_ci * This is the equlivant of doing something like 78862306a36Sopenharmony_ci * debugfs_remove(debugfs_lookup(..)) but with the proper reference counting 78962306a36Sopenharmony_ci * handled for the directory being looked up. 79062306a36Sopenharmony_ci */ 79162306a36Sopenharmony_civoid debugfs_lookup_and_remove(const char *name, struct dentry *parent) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci struct dentry *dentry; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci dentry = debugfs_lookup(name, parent); 79662306a36Sopenharmony_ci if (!dentry) 79762306a36Sopenharmony_ci return; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci debugfs_remove(dentry); 80062306a36Sopenharmony_ci dput(dentry); 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(debugfs_lookup_and_remove); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci/** 80562306a36Sopenharmony_ci * debugfs_rename - rename a file/directory in the debugfs filesystem 80662306a36Sopenharmony_ci * @old_dir: a pointer to the parent dentry for the renamed object. This 80762306a36Sopenharmony_ci * should be a directory dentry. 80862306a36Sopenharmony_ci * @old_dentry: dentry of an object to be renamed. 80962306a36Sopenharmony_ci * @new_dir: a pointer to the parent dentry where the object should be 81062306a36Sopenharmony_ci * moved. This should be a directory dentry. 81162306a36Sopenharmony_ci * @new_name: a pointer to a string containing the target name. 81262306a36Sopenharmony_ci * 81362306a36Sopenharmony_ci * This function renames a file/directory in debugfs. The target must not 81462306a36Sopenharmony_ci * exist for rename to succeed. 81562306a36Sopenharmony_ci * 81662306a36Sopenharmony_ci * This function will return a pointer to old_dentry (which is updated to 81762306a36Sopenharmony_ci * reflect renaming) if it succeeds. If an error occurs, ERR_PTR(-ERROR) 81862306a36Sopenharmony_ci * will be returned. 81962306a36Sopenharmony_ci * 82062306a36Sopenharmony_ci * If debugfs is not enabled in the kernel, the value -%ENODEV will be 82162306a36Sopenharmony_ci * returned. 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_cistruct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, 82462306a36Sopenharmony_ci struct dentry *new_dir, const char *new_name) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci int error; 82762306a36Sopenharmony_ci struct dentry *dentry = NULL, *trap; 82862306a36Sopenharmony_ci struct name_snapshot old_name; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci if (IS_ERR(old_dir)) 83162306a36Sopenharmony_ci return old_dir; 83262306a36Sopenharmony_ci if (IS_ERR(new_dir)) 83362306a36Sopenharmony_ci return new_dir; 83462306a36Sopenharmony_ci if (IS_ERR_OR_NULL(old_dentry)) 83562306a36Sopenharmony_ci return old_dentry; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci trap = lock_rename(new_dir, old_dir); 83862306a36Sopenharmony_ci /* Source or destination directories don't exist? */ 83962306a36Sopenharmony_ci if (d_really_is_negative(old_dir) || d_really_is_negative(new_dir)) 84062306a36Sopenharmony_ci goto exit; 84162306a36Sopenharmony_ci /* Source does not exist, cyclic rename, or mountpoint? */ 84262306a36Sopenharmony_ci if (d_really_is_negative(old_dentry) || old_dentry == trap || 84362306a36Sopenharmony_ci d_mountpoint(old_dentry)) 84462306a36Sopenharmony_ci goto exit; 84562306a36Sopenharmony_ci dentry = lookup_one_len(new_name, new_dir, strlen(new_name)); 84662306a36Sopenharmony_ci /* Lookup failed, cyclic rename or target exists? */ 84762306a36Sopenharmony_ci if (IS_ERR(dentry) || dentry == trap || d_really_is_positive(dentry)) 84862306a36Sopenharmony_ci goto exit; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci take_dentry_name_snapshot(&old_name, old_dentry); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci error = simple_rename(&nop_mnt_idmap, d_inode(old_dir), old_dentry, 85362306a36Sopenharmony_ci d_inode(new_dir), dentry, 0); 85462306a36Sopenharmony_ci if (error) { 85562306a36Sopenharmony_ci release_dentry_name_snapshot(&old_name); 85662306a36Sopenharmony_ci goto exit; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci d_move(old_dentry, dentry); 85962306a36Sopenharmony_ci fsnotify_move(d_inode(old_dir), d_inode(new_dir), &old_name.name, 86062306a36Sopenharmony_ci d_is_dir(old_dentry), 86162306a36Sopenharmony_ci NULL, old_dentry); 86262306a36Sopenharmony_ci release_dentry_name_snapshot(&old_name); 86362306a36Sopenharmony_ci unlock_rename(new_dir, old_dir); 86462306a36Sopenharmony_ci dput(dentry); 86562306a36Sopenharmony_ci return old_dentry; 86662306a36Sopenharmony_ciexit: 86762306a36Sopenharmony_ci if (dentry && !IS_ERR(dentry)) 86862306a36Sopenharmony_ci dput(dentry); 86962306a36Sopenharmony_ci unlock_rename(new_dir, old_dir); 87062306a36Sopenharmony_ci if (IS_ERR(dentry)) 87162306a36Sopenharmony_ci return dentry; 87262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(debugfs_rename); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci/** 87762306a36Sopenharmony_ci * debugfs_initialized - Tells whether debugfs has been registered 87862306a36Sopenharmony_ci */ 87962306a36Sopenharmony_cibool debugfs_initialized(void) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci return debugfs_registered; 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(debugfs_initialized); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic int __init debugfs_kernel(char *str) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci if (str) { 88862306a36Sopenharmony_ci if (!strcmp(str, "on")) 88962306a36Sopenharmony_ci debugfs_allow = DEBUGFS_ALLOW_API | DEBUGFS_ALLOW_MOUNT; 89062306a36Sopenharmony_ci else if (!strcmp(str, "no-mount")) 89162306a36Sopenharmony_ci debugfs_allow = DEBUGFS_ALLOW_API; 89262306a36Sopenharmony_ci else if (!strcmp(str, "off")) 89362306a36Sopenharmony_ci debugfs_allow = 0; 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci return 0; 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ciearly_param("debugfs", debugfs_kernel); 89962306a36Sopenharmony_cistatic int __init debugfs_init(void) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci int retval; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (!(debugfs_allow & DEBUGFS_ALLOW_MOUNT)) 90462306a36Sopenharmony_ci return -EPERM; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci retval = sysfs_create_mount_point(kernel_kobj, "debug"); 90762306a36Sopenharmony_ci if (retval) 90862306a36Sopenharmony_ci return retval; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci retval = register_filesystem(&debug_fs_type); 91162306a36Sopenharmony_ci if (retval) 91262306a36Sopenharmony_ci sysfs_remove_mount_point(kernel_kobj, "debug"); 91362306a36Sopenharmony_ci else 91462306a36Sopenharmony_ci debugfs_registered = true; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci return retval; 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_cicore_initcall(debugfs_init); 919