linux/fs/tracefs/inode.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  inode.c - part of tracefs, a pseudo file system for activating tracing
   4 *
   5 * Based on debugfs by: Greg Kroah-Hartman <greg@kroah.com>
   6 *
   7 *  Copyright (C) 2014 Red Hat Inc, author: Steven Rostedt <srostedt@redhat.com>
   8 *
   9 * tracefs is the file system that is used by the tracing infrastructure.
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/fs.h>
  14#include <linux/mount.h>
  15#include <linux/kobject.h>
  16#include <linux/namei.h>
  17#include <linux/tracefs.h>
  18#include <linux/fsnotify.h>
  19#include <linux/security.h>
  20#include <linux/seq_file.h>
  21#include <linux/parser.h>
  22#include <linux/magic.h>
  23#include <linux/slab.h>
  24
  25#define TRACEFS_DEFAULT_MODE    0700
  26
  27static struct vfsmount *tracefs_mount;
  28static int tracefs_mount_count;
  29static bool tracefs_registered;
  30
  31static ssize_t default_read_file(struct file *file, char __user *buf,
  32                                 size_t count, loff_t *ppos)
  33{
  34        return 0;
  35}
  36
  37static ssize_t default_write_file(struct file *file, const char __user *buf,
  38                                   size_t count, loff_t *ppos)
  39{
  40        return count;
  41}
  42
  43static const struct file_operations tracefs_file_operations = {
  44        .read =         default_read_file,
  45        .write =        default_write_file,
  46        .open =         simple_open,
  47        .llseek =       noop_llseek,
  48};
  49
  50static struct tracefs_dir_ops {
  51        int (*mkdir)(const char *name);
  52        int (*rmdir)(const char *name);
  53} tracefs_ops __ro_after_init;
  54
  55static char *get_dname(struct dentry *dentry)
  56{
  57        const char *dname;
  58        char *name;
  59        int len = dentry->d_name.len;
  60
  61        dname = dentry->d_name.name;
  62        name = kmalloc(len + 1, GFP_KERNEL);
  63        if (!name)
  64                return NULL;
  65        memcpy(name, dname, len);
  66        name[len] = 0;
  67        return name;
  68}
  69
  70static int tracefs_syscall_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode)
  71{
  72        char *name;
  73        int ret;
  74
  75        name = get_dname(dentry);
  76        if (!name)
  77                return -ENOMEM;
  78
  79        /*
  80         * The mkdir call can call the generic functions that create
  81         * the files within the tracefs system. It is up to the individual
  82         * mkdir routine to handle races.
  83         */
  84        inode_unlock(inode);
  85        ret = tracefs_ops.mkdir(name);
  86        inode_lock(inode);
  87
  88        kfree(name);
  89
  90        return ret;
  91}
  92
  93static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry)
  94{
  95        char *name;
  96        int ret;
  97
  98        name = get_dname(dentry);
  99        if (!name)
 100                return -ENOMEM;
 101
 102        /*
 103         * The rmdir call can call the generic functions that create
 104         * the files within the tracefs system. It is up to the individual
 105         * rmdir routine to handle races.
 106         * This time we need to unlock not only the parent (inode) but
 107         * also the directory that is being deleted.
 108         */
 109        inode_unlock(inode);
 110        inode_unlock(dentry->d_inode);
 111
 112        ret = tracefs_ops.rmdir(name);
 113
 114        inode_lock_nested(inode, I_MUTEX_PARENT);
 115        inode_lock(dentry->d_inode);
 116
 117        kfree(name);
 118
 119        return ret;
 120}
 121
 122static const struct inode_operations tracefs_dir_inode_operations = {
 123        .lookup         = simple_lookup,
 124        .mkdir          = tracefs_syscall_mkdir,
 125        .rmdir          = tracefs_syscall_rmdir,
 126};
 127
 128static struct inode *tracefs_get_inode(struct super_block *sb)
 129{
 130        struct inode *inode = new_inode(sb);
 131        if (inode) {
 132                inode->i_ino = get_next_ino();
 133                inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
 134        }
 135        return inode;
 136}
 137
 138struct tracefs_mount_opts {
 139        kuid_t uid;
 140        kgid_t gid;
 141        umode_t mode;
 142};
 143
 144enum {
 145        Opt_uid,
 146        Opt_gid,
 147        Opt_mode,
 148        Opt_err
 149};
 150
 151static const match_table_t tokens = {
 152        {Opt_uid, "uid=%u"},
 153        {Opt_gid, "gid=%u"},
 154        {Opt_mode, "mode=%o"},
 155        {Opt_err, NULL}
 156};
 157
 158struct tracefs_fs_info {
 159        struct tracefs_mount_opts mount_opts;
 160};
 161
 162static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
 163{
 164        substring_t args[MAX_OPT_ARGS];
 165        int option;
 166        int token;
 167        kuid_t uid;
 168        kgid_t gid;
 169        char *p;
 170
 171        opts->mode = TRACEFS_DEFAULT_MODE;
 172
 173        while ((p = strsep(&data, ",")) != NULL) {
 174                if (!*p)
 175                        continue;
 176
 177                token = match_token(p, tokens, args);
 178                switch (token) {
 179                case Opt_uid:
 180                        if (match_int(&args[0], &option))
 181                                return -EINVAL;
 182                        uid = make_kuid(current_user_ns(), option);
 183                        if (!uid_valid(uid))
 184                                return -EINVAL;
 185                        opts->uid = uid;
 186                        break;
 187                case Opt_gid:
 188                        if (match_int(&args[0], &option))
 189                                return -EINVAL;
 190                        gid = make_kgid(current_user_ns(), option);
 191                        if (!gid_valid(gid))
 192                                return -EINVAL;
 193                        opts->gid = gid;
 194                        break;
 195                case Opt_mode:
 196                        if (match_octal(&args[0], &option))
 197                                return -EINVAL;
 198                        opts->mode = option & S_IALLUGO;
 199                        break;
 200                /*
 201                 * We might like to report bad mount options here;
 202                 * but traditionally tracefs has ignored all mount options
 203                 */
 204                }
 205        }
 206
 207        return 0;
 208}
 209
 210static int tracefs_apply_options(struct super_block *sb)
 211{
 212        struct tracefs_fs_info *fsi = sb->s_fs_info;
 213        struct inode *inode = sb->s_root->d_inode;
 214        struct tracefs_mount_opts *opts = &fsi->mount_opts;
 215
 216        inode->i_mode &= ~S_IALLUGO;
 217        inode->i_mode |= opts->mode;
 218
 219        inode->i_uid = opts->uid;
 220        inode->i_gid = opts->gid;
 221
 222        return 0;
 223}
 224
 225static int tracefs_remount(struct super_block *sb, int *flags, char *data)
 226{
 227        int err;
 228        struct tracefs_fs_info *fsi = sb->s_fs_info;
 229
 230        sync_filesystem(sb);
 231        err = tracefs_parse_options(data, &fsi->mount_opts);
 232        if (err)
 233                goto fail;
 234
 235        tracefs_apply_options(sb);
 236
 237fail:
 238        return err;
 239}
 240
 241static int tracefs_show_options(struct seq_file *m, struct dentry *root)
 242{
 243        struct tracefs_fs_info *fsi = root->d_sb->s_fs_info;
 244        struct tracefs_mount_opts *opts = &fsi->mount_opts;
 245
 246        if (!uid_eq(opts->uid, GLOBAL_ROOT_UID))
 247                seq_printf(m, ",uid=%u",
 248                           from_kuid_munged(&init_user_ns, opts->uid));
 249        if (!gid_eq(opts->gid, GLOBAL_ROOT_GID))
 250                seq_printf(m, ",gid=%u",
 251                           from_kgid_munged(&init_user_ns, opts->gid));
 252        if (opts->mode != TRACEFS_DEFAULT_MODE)
 253                seq_printf(m, ",mode=%o", opts->mode);
 254
 255        return 0;
 256}
 257
 258static const struct super_operations tracefs_super_operations = {
 259        .statfs         = simple_statfs,
 260        .remount_fs     = tracefs_remount,
 261        .show_options   = tracefs_show_options,
 262};
 263
 264static int trace_fill_super(struct super_block *sb, void *data, int silent)
 265{
 266        static const struct tree_descr trace_files[] = {{""}};
 267        struct tracefs_fs_info *fsi;
 268        int err;
 269
 270        fsi = kzalloc(sizeof(struct tracefs_fs_info), GFP_KERNEL);
 271        sb->s_fs_info = fsi;
 272        if (!fsi) {
 273                err = -ENOMEM;
 274                goto fail;
 275        }
 276
 277        err = tracefs_parse_options(data, &fsi->mount_opts);
 278        if (err)
 279                goto fail;
 280
 281        err  =  simple_fill_super(sb, TRACEFS_MAGIC, trace_files);
 282        if (err)
 283                goto fail;
 284
 285        sb->s_op = &tracefs_super_operations;
 286
 287        tracefs_apply_options(sb);
 288
 289        return 0;
 290
 291fail:
 292        kfree(fsi);
 293        sb->s_fs_info = NULL;
 294        return err;
 295}
 296
 297static struct dentry *trace_mount(struct file_system_type *fs_type,
 298                        int flags, const char *dev_name,
 299                        void *data)
 300{
 301        return mount_single(fs_type, flags, data, trace_fill_super);
 302}
 303
 304static struct file_system_type trace_fs_type = {
 305        .owner =        THIS_MODULE,
 306        .name =         "tracefs",
 307        .mount =        trace_mount,
 308        .kill_sb =      kill_litter_super,
 309};
 310MODULE_ALIAS_FS("tracefs");
 311
 312static struct dentry *start_creating(const char *name, struct dentry *parent)
 313{
 314        struct dentry *dentry;
 315        int error;
 316
 317        pr_debug("tracefs: creating file '%s'\n",name);
 318
 319        error = simple_pin_fs(&trace_fs_type, &tracefs_mount,
 320                              &tracefs_mount_count);
 321        if (error)
 322                return ERR_PTR(error);
 323
 324        /* If the parent is not specified, we create it in the root.
 325         * We need the root dentry to do this, which is in the super
 326         * block. A pointer to that is in the struct vfsmount that we
 327         * have around.
 328         */
 329        if (!parent)
 330                parent = tracefs_mount->mnt_root;
 331
 332        inode_lock(parent->d_inode);
 333        if (unlikely(IS_DEADDIR(parent->d_inode)))
 334                dentry = ERR_PTR(-ENOENT);
 335        else
 336                dentry = lookup_one_len(name, parent, strlen(name));
 337        if (!IS_ERR(dentry) && dentry->d_inode) {
 338                dput(dentry);
 339                dentry = ERR_PTR(-EEXIST);
 340        }
 341
 342        if (IS_ERR(dentry)) {
 343                inode_unlock(parent->d_inode);
 344                simple_release_fs(&tracefs_mount, &tracefs_mount_count);
 345        }
 346
 347        return dentry;
 348}
 349
 350static struct dentry *failed_creating(struct dentry *dentry)
 351{
 352        inode_unlock(dentry->d_parent->d_inode);
 353        dput(dentry);
 354        simple_release_fs(&tracefs_mount, &tracefs_mount_count);
 355        return NULL;
 356}
 357
 358static struct dentry *end_creating(struct dentry *dentry)
 359{
 360        inode_unlock(dentry->d_parent->d_inode);
 361        return dentry;
 362}
 363
 364/**
 365 * tracefs_create_file - create a file in the tracefs filesystem
 366 * @name: a pointer to a string containing the name of the file to create.
 367 * @mode: the permission that the file should have.
 368 * @parent: a pointer to the parent dentry for this file.  This should be a
 369 *          directory dentry if set.  If this parameter is NULL, then the
 370 *          file will be created in the root of the tracefs filesystem.
 371 * @data: a pointer to something that the caller will want to get to later
 372 *        on.  The inode.i_private pointer will point to this value on
 373 *        the open() call.
 374 * @fops: a pointer to a struct file_operations that should be used for
 375 *        this file.
 376 *
 377 * This is the basic "create a file" function for tracefs.  It allows for a
 378 * wide range of flexibility in creating a file, or a directory (if you want
 379 * to create a directory, the tracefs_create_dir() function is
 380 * recommended to be used instead.)
 381 *
 382 * This function will return a pointer to a dentry if it succeeds.  This
 383 * pointer must be passed to the tracefs_remove() function when the file is
 384 * to be removed (no automatic cleanup happens if your module is unloaded,
 385 * you are responsible here.)  If an error occurs, %NULL will be returned.
 386 *
 387 * If tracefs is not enabled in the kernel, the value -%ENODEV will be
 388 * returned.
 389 */
 390struct dentry *tracefs_create_file(const char *name, umode_t mode,
 391                                   struct dentry *parent, void *data,
 392                                   const struct file_operations *fops)
 393{
 394        struct dentry *dentry;
 395        struct inode *inode;
 396
 397        if (security_locked_down(LOCKDOWN_TRACEFS))
 398                return NULL;
 399
 400        if (!(mode & S_IFMT))
 401                mode |= S_IFREG;
 402        BUG_ON(!S_ISREG(mode));
 403        dentry = start_creating(name, parent);
 404
 405        if (IS_ERR(dentry))
 406                return NULL;
 407
 408        inode = tracefs_get_inode(dentry->d_sb);
 409        if (unlikely(!inode))
 410                return failed_creating(dentry);
 411
 412        inode->i_mode = mode;
 413        inode->i_fop = fops ? fops : &tracefs_file_operations;
 414        inode->i_private = data;
 415        d_instantiate(dentry, inode);
 416        fsnotify_create(dentry->d_parent->d_inode, dentry);
 417        return end_creating(dentry);
 418}
 419
 420static struct dentry *__create_dir(const char *name, struct dentry *parent,
 421                                   const struct inode_operations *ops)
 422{
 423        struct dentry *dentry = start_creating(name, parent);
 424        struct inode *inode;
 425
 426        if (IS_ERR(dentry))
 427                return NULL;
 428
 429        inode = tracefs_get_inode(dentry->d_sb);
 430        if (unlikely(!inode))
 431                return failed_creating(dentry);
 432
 433        inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
 434        inode->i_op = ops;
 435        inode->i_fop = &simple_dir_operations;
 436
 437        /* directory inodes start off with i_nlink == 2 (for "." entry) */
 438        inc_nlink(inode);
 439        d_instantiate(dentry, inode);
 440        inc_nlink(dentry->d_parent->d_inode);
 441        fsnotify_mkdir(dentry->d_parent->d_inode, dentry);
 442        return end_creating(dentry);
 443}
 444
 445/**
 446 * tracefs_create_dir - create a directory in the tracefs filesystem
 447 * @name: a pointer to a string containing the name of the directory to
 448 *        create.
 449 * @parent: a pointer to the parent dentry for this file.  This should be a
 450 *          directory dentry if set.  If this parameter is NULL, then the
 451 *          directory will be created in the root of the tracefs filesystem.
 452 *
 453 * This function creates a directory in tracefs with the given name.
 454 *
 455 * This function will return a pointer to a dentry if it succeeds.  This
 456 * pointer must be passed to the tracefs_remove() function when the file is
 457 * to be removed. If an error occurs, %NULL will be returned.
 458 *
 459 * If tracing is not enabled in the kernel, the value -%ENODEV will be
 460 * returned.
 461 */
 462struct dentry *tracefs_create_dir(const char *name, struct dentry *parent)
 463{
 464        return __create_dir(name, parent, &simple_dir_inode_operations);
 465}
 466
 467/**
 468 * tracefs_create_instance_dir - create the tracing instances directory
 469 * @name: The name of the instances directory to create
 470 * @parent: The parent directory that the instances directory will exist
 471 * @mkdir: The function to call when a mkdir is performed.
 472 * @rmdir: The function to call when a rmdir is performed.
 473 *
 474 * Only one instances directory is allowed.
 475 *
 476 * The instances directory is special as it allows for mkdir and rmdir to
 477 * to be done by userspace. When a mkdir or rmdir is performed, the inode
 478 * locks are released and the methhods passed in (@mkdir and @rmdir) are
 479 * called without locks and with the name of the directory being created
 480 * within the instances directory.
 481 *
 482 * Returns the dentry of the instances directory.
 483 */
 484__init struct dentry *tracefs_create_instance_dir(const char *name,
 485                                          struct dentry *parent,
 486                                          int (*mkdir)(const char *name),
 487                                          int (*rmdir)(const char *name))
 488{
 489        struct dentry *dentry;
 490
 491        /* Only allow one instance of the instances directory. */
 492        if (WARN_ON(tracefs_ops.mkdir || tracefs_ops.rmdir))
 493                return NULL;
 494
 495        dentry = __create_dir(name, parent, &tracefs_dir_inode_operations);
 496        if (!dentry)
 497                return NULL;
 498
 499        tracefs_ops.mkdir = mkdir;
 500        tracefs_ops.rmdir = rmdir;
 501
 502        return dentry;
 503}
 504
 505static void remove_one(struct dentry *victim)
 506{
 507        simple_release_fs(&tracefs_mount, &tracefs_mount_count);
 508}
 509
 510/**
 511 * tracefs_remove - recursively removes a directory
 512 * @dentry: a pointer to a the dentry of the directory to be removed.
 513 *
 514 * This function recursively removes a directory tree in tracefs that
 515 * was previously created with a call to another tracefs function
 516 * (like tracefs_create_file() or variants thereof.)
 517 */
 518void tracefs_remove(struct dentry *dentry)
 519{
 520        if (IS_ERR_OR_NULL(dentry))
 521                return;
 522
 523        simple_pin_fs(&trace_fs_type, &tracefs_mount, &tracefs_mount_count);
 524        simple_recursive_removal(dentry, remove_one);
 525        simple_release_fs(&tracefs_mount, &tracefs_mount_count);
 526}
 527
 528/**
 529 * tracefs_initialized - Tells whether tracefs has been registered
 530 */
 531bool tracefs_initialized(void)
 532{
 533        return tracefs_registered;
 534}
 535
 536static int __init tracefs_init(void)
 537{
 538        int retval;
 539
 540        retval = sysfs_create_mount_point(kernel_kobj, "tracing");
 541        if (retval)
 542                return -EINVAL;
 543
 544        retval = register_filesystem(&trace_fs_type);
 545        if (!retval)
 546                tracefs_registered = true;
 547
 548        return retval;
 549}
 550core_initcall(tracefs_init);
 551