| 1 | |
| 2 | |
| 3 | * inode.c - part of tracefs, a pseudo file system for activating tracing
|
| 4 | *
|
| 5 | * Based on debugfs by: Greg Kroah-Hartman <[email protected]>
|
| 6 | *
|
| 7 | * Copyright (C) 2014 Red Hat Inc, author: Steven Rostedt <[email protected]>
|
| 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/fs_context.h>
|
| 15 | #include <linux/fs_parser.h>
|
| 16 | #include <linux/kobject.h>
|
| 17 | #include <linux/namei.h>
|
| 18 | #include <linux/tracefs.h>
|
| 19 | #include <linux/fsnotify.h>
|
| 20 | #include <linux/security.h>
|
| 21 | #include <linux/seq_file.h>
|
| 22 | #include <linux/magic.h>
|
| 23 | #include <linux/slab.h>
|
| 24 | #include "internal.h"
|
| 25 |
|
| 26 | #define TRACEFS_DEFAULT_MODE 0700
|
| 27 | static struct kmem_cache *tracefs_inode_cachep __ro_after_init;
|
| 28 |
|
| 29 | static struct vfsmount *tracefs_mount;
|
| 30 | static int tracefs_mount_count;
|
| 31 | static bool tracefs_registered;
|
| 32 |
|
| 33 | |
| 34 | * Keep track of all tracefs_inodes in order to update their
|
| 35 | * flags if necessary on a remount.
|
| 36 |
|
| 37 | static DEFINE_SPINLOCK(tracefs_inode_lock);
|
| 38 | static LIST_HEAD(tracefs_inodes);
|
| 39 |
|
| 40 | static struct inode *tracefs_alloc_inode(struct super_block *sb)
|
| 41 | {
|
| 42 | struct tracefs_inode *ti;
|
| 43 | unsigned long flags;
|
| 44 |
|
| 45 | ti = alloc_inode_sb(sb, tracefs_inode_cachep, GFP_KERNEL);
|
| 46 | if (!ti)
|
| 47 | return NULL;
|
| 48 |
|
| 49 | spin_lock_irqsave(&tracefs_inode_lock, flags);
|
| 50 | list_add_rcu(&ti->list, &tracefs_inodes);
|
| 51 | spin_unlock_irqrestore(&tracefs_inode_lock, flags);
|
| 52 |
|
| 53 | return &ti->vfs_inode;
|
| 54 | }
|
| 55 |
|
| 56 | static void tracefs_free_inode(struct inode *inode)
|
| 57 | {
|
| 58 | struct tracefs_inode *ti = get_tracefs(inode);
|
| 59 |
|
| 60 | kmem_cache_free(tracefs_inode_cachep, ti);
|
| 61 | }
|
| 62 |
|
| 63 | static void tracefs_destroy_inode(struct inode *inode)
|
| 64 | {
|
| 65 | struct tracefs_inode *ti = get_tracefs(inode);
|
| 66 | unsigned long flags;
|
| 67 |
|
| 68 | spin_lock_irqsave(&tracefs_inode_lock, flags);
|
| 69 | list_del_rcu(&ti->list);
|
| 70 | spin_unlock_irqrestore(&tracefs_inode_lock, flags);
|
| 71 | }
|
| 72 |
|
| 73 | static ssize_t default_read_file(struct file *file, char __user *buf,
|
| 74 | size_t count, loff_t *ppos)
|
| 75 | {
|
| 76 | return 0;
|
| 77 | }
|
| 78 |
|
| 79 | static ssize_t default_write_file(struct file *file, const char __user *buf,
|
| 80 | size_t count, loff_t *ppos)
|
| 81 | {
|
| 82 | return count;
|
| 83 | }
|
| 84 |
|
| 85 | static const struct file_operations tracefs_file_operations = {
|
| 86 | .read = default_read_file,
|
| 87 | .write = default_write_file,
|
| 88 | .open = simple_open,
|
| 89 | .llseek = noop_llseek,
|
| 90 | };
|
| 91 |
|
| 92 | static struct tracefs_dir_ops {
|
| 93 | int (*mkdir)(const char *name);
|
| 94 | int (*rmdir)(const char *name);
|
| 95 | } tracefs_ops __ro_after_init;
|
| 96 |
|
| 97 | static struct dentry *tracefs_syscall_mkdir(const struct mnt_idmap *idmap,
|
| 98 | struct inode *inode, struct dentry *dentry,
|
| 99 | umode_t mode)
|
| 100 | {
|
| 101 | struct tracefs_inode *ti;
|
| 102 | struct name_snapshot name;
|
| 103 | int ret;
|
| 104 |
|
| 105 | |
| 106 | * This is a new directory that does not take the default of
|
| 107 | * the rootfs. It becomes the default permissions for all the
|
| 108 | * files and directories underneath it.
|
| 109 |
|
| 110 | ti = get_tracefs(inode);
|
| 111 | ti->flags |= TRACEFS_INSTANCE_INODE;
|
| 112 | ti->private = inode;
|
| 113 |
|
| 114 | |
| 115 | * The mkdir call can call the generic functions that create
|
| 116 | * the files within the tracefs system. It is up to the individual
|
| 117 | * mkdir routine to handle races.
|
| 118 |
|
| 119 | take_dentry_name_snapshot(&name, dentry);
|
| 120 | inode_unlock(inode);
|
| 121 | ret = tracefs_ops.mkdir(name.name.name);
|
| 122 | inode_lock(inode);
|
| 123 | release_dentry_name_snapshot(&name);
|
| 124 |
|
| 125 | return ERR_PTR(ret);
|
| 126 | }
|
| 127 |
|
| 128 | static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry)
|
| 129 | {
|
| 130 | struct name_snapshot name;
|
| 131 | int ret;
|
| 132 |
|
| 133 | |
| 134 | * The rmdir call can call the generic functions that create
|
| 135 | * the files within the tracefs system. It is up to the individual
|
| 136 | * rmdir routine to handle races.
|
| 137 | * This time we need to unlock not only the parent (inode) but
|
| 138 | * also the directory that is being deleted.
|
| 139 |
|
| 140 | take_dentry_name_snapshot(&name, dentry);
|
| 141 | inode_unlock(inode);
|
| 142 | inode_unlock(d_inode(dentry));
|
| 143 |
|
| 144 | ret = tracefs_ops.rmdir(name.name.name);
|
| 145 |
|
| 146 | inode_lock_nested(inode, I_MUTEX_PARENT);
|
| 147 | inode_lock(d_inode(dentry));
|
| 148 | release_dentry_name_snapshot(&name);
|
| 149 |
|
| 150 | return ret;
|
| 151 | }
|
| 152 |
|
| 153 | static void set_tracefs_inode_owner(struct inode *inode)
|
| 154 | {
|
| 155 | struct tracefs_inode *ti = get_tracefs(inode);
|
| 156 | struct inode *root_inode = ti->private;
|
| 157 | kuid_t uid;
|
| 158 | kgid_t gid;
|
| 159 |
|
| 160 | uid = root_inode->i_uid;
|
| 161 | gid = root_inode->i_gid;
|
| 162 |
|
| 163 | |
| 164 | * If the root is not the mount point, then check the root's
|
| 165 | * permissions. If it was never set, then default to the
|
| 166 | * mount point.
|
| 167 |
|
| 168 | if (root_inode != d_inode(root_inode->i_sb->s_root)) {
|
| 169 | struct tracefs_inode *rti;
|
| 170 |
|
| 171 | rti = get_tracefs(root_inode);
|
| 172 | root_inode = d_inode(root_inode->i_sb->s_root);
|
| 173 |
|
| 174 | if (!(rti->flags & TRACEFS_UID_PERM_SET))
|
| 175 | uid = root_inode->i_uid;
|
| 176 |
|
| 177 | if (!(rti->flags & TRACEFS_GID_PERM_SET))
|
| 178 | gid = root_inode->i_gid;
|
| 179 | }
|
| 180 |
|
| 181 | |
| 182 | * If this inode has never been referenced, then update
|
| 183 | * the permissions to the superblock.
|
| 184 |
|
| 185 | if (!(ti->flags & TRACEFS_UID_PERM_SET))
|
| 186 | inode->i_uid = uid;
|
| 187 |
|
| 188 | if (!(ti->flags & TRACEFS_GID_PERM_SET))
|
| 189 | inode->i_gid = gid;
|
| 190 | }
|
| 191 |
|
| 192 | static int tracefs_permission(const struct mnt_idmap *idmap,
|
| 193 | struct inode *inode, int mask)
|
| 194 | {
|
| 195 | set_tracefs_inode_owner(inode);
|
| 196 | return generic_permission(idmap, inode, mask);
|
| 197 | }
|
| 198 |
|
| 199 | static int tracefs_getattr(const struct mnt_idmap *idmap,
|
| 200 | const struct path *path, struct kstat *stat,
|
| 201 | u32 request_mask, unsigned int flags)
|
| 202 | {
|
| 203 | struct inode *inode = d_backing_inode(path->dentry);
|
| 204 |
|
| 205 | set_tracefs_inode_owner(inode);
|
| 206 | generic_fillattr(idmap, request_mask, inode, stat);
|
| 207 | return 0;
|
| 208 | }
|
| 209 |
|
| 210 | static int tracefs_setattr(const struct mnt_idmap *idmap, struct dentry *dentry,
|
| 211 | struct iattr *attr)
|
| 212 | {
|
| 213 | unsigned int ia_valid = attr->ia_valid;
|
| 214 | struct inode *inode = d_inode(dentry);
|
| 215 | struct tracefs_inode *ti = get_tracefs(inode);
|
| 216 |
|
| 217 | if (ia_valid & ATTR_UID)
|
| 218 | ti->flags |= TRACEFS_UID_PERM_SET;
|
| 219 |
|
| 220 | if (ia_valid & ATTR_GID)
|
| 221 | ti->flags |= TRACEFS_GID_PERM_SET;
|
| 222 |
|
| 223 | return simple_setattr(idmap, dentry, attr);
|
| 224 | }
|
| 225 |
|
| 226 | static const struct inode_operations tracefs_instance_dir_inode_operations = {
|
| 227 | .lookup = simple_lookup,
|
| 228 | .mkdir = tracefs_syscall_mkdir,
|
| 229 | .rmdir = tracefs_syscall_rmdir,
|
| 230 | .permission = tracefs_permission,
|
| 231 | .getattr = tracefs_getattr,
|
| 232 | .setattr = tracefs_setattr,
|
| 233 | };
|
| 234 |
|
| 235 | static const struct inode_operations tracefs_dir_inode_operations = {
|
| 236 | .lookup = simple_lookup,
|
| 237 | .permission = tracefs_permission,
|
| 238 | .getattr = tracefs_getattr,
|
| 239 | .setattr = tracefs_setattr,
|
| 240 | };
|
| 241 |
|
| 242 | static const struct inode_operations tracefs_file_inode_operations = {
|
| 243 | .permission = tracefs_permission,
|
| 244 | .getattr = tracefs_getattr,
|
| 245 | .setattr = tracefs_setattr,
|
| 246 | };
|
| 247 |
|
| 248 | struct inode *tracefs_get_inode(struct super_block *sb)
|
| 249 | {
|
| 250 | struct inode *inode = new_inode(sb);
|
| 251 | if (inode) {
|
| 252 | inode->i_ino = get_next_ino();
|
| 253 | simple_inode_init_ts(inode);
|
| 254 | }
|
| 255 | return inode;
|
| 256 | }
|
| 257 |
|
| 258 | struct tracefs_fs_info {
|
| 259 | kuid_t uid;
|
| 260 | kgid_t gid;
|
| 261 | umode_t mode;
|
| 262 |
|
| 263 | unsigned int opts;
|
| 264 | };
|
| 265 |
|
| 266 | enum {
|
| 267 | Opt_uid,
|
| 268 | Opt_gid,
|
| 269 | Opt_mode,
|
| 270 | };
|
| 271 |
|
| 272 | static const struct fs_parameter_spec tracefs_param_specs[] = {
|
| 273 | fsparam_gid ("gid", Opt_gid),
|
| 274 | fsparam_u32oct ("mode", Opt_mode),
|
| 275 | fsparam_uid ("uid", Opt_uid),
|
| 276 | {}
|
| 277 | };
|
| 278 |
|
| 279 | static int tracefs_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
| 280 | {
|
| 281 | struct tracefs_fs_info *opts = fc->s_fs_info;
|
| 282 | struct fs_parse_result result;
|
| 283 | int opt;
|
| 284 |
|
| 285 | opt = fs_parse(fc, tracefs_param_specs, param, &result);
|
| 286 | if (opt < 0)
|
| 287 | return opt;
|
| 288 |
|
| 289 | switch (opt) {
|
| 290 | case Opt_uid:
|
| 291 | opts->uid = result.uid;
|
| 292 | break;
|
| 293 | case Opt_gid:
|
| 294 | opts->gid = result.gid;
|
| 295 | break;
|
| 296 | case Opt_mode:
|
| 297 | opts->mode = result.uint_32 & S_IALLUGO;
|
| 298 | break;
|
| 299 | |
| 300 | * We might like to report bad mount options here;
|
| 301 | * but traditionally tracefs has ignored all mount options
|
| 302 |
|
| 303 | }
|
| 304 |
|
| 305 | opts->opts |= BIT(opt);
|
| 306 |
|
| 307 | return 0;
|
| 308 | }
|
| 309 |
|
| 310 | static int tracefs_apply_options(struct super_block *sb, bool remount)
|
| 311 | {
|
| 312 | struct tracefs_fs_info *fsi = sb->s_fs_info;
|
| 313 | struct inode *inode = d_inode(sb->s_root);
|
| 314 | struct tracefs_inode *ti;
|
| 315 | bool update_uid, update_gid;
|
| 316 | int srcu_idx;
|
| 317 | umode_t tmp_mode;
|
| 318 |
|
| 319 | |
| 320 | * On remount, only reset mode/uid/gid if they were provided as mount
|
| 321 | * options.
|
| 322 |
|
| 323 |
|
| 324 | if (!remount || fsi->opts & BIT(Opt_mode)) {
|
| 325 | tmp_mode = READ_ONCE(inode->i_mode) & ~S_IALLUGO;
|
| 326 | tmp_mode |= fsi->mode;
|
| 327 | WRITE_ONCE(inode->i_mode, tmp_mode);
|
| 328 | }
|
| 329 |
|
| 330 | if (!remount || fsi->opts & BIT(Opt_uid))
|
| 331 | inode->i_uid = fsi->uid;
|
| 332 |
|
| 333 | if (!remount || fsi->opts & BIT(Opt_gid))
|
| 334 | inode->i_gid = fsi->gid;
|
| 335 |
|
| 336 | if (remount && (fsi->opts & BIT(Opt_uid) || fsi->opts & BIT(Opt_gid))) {
|
| 337 |
|
| 338 | update_uid = fsi->opts & BIT(Opt_uid);
|
| 339 | update_gid = fsi->opts & BIT(Opt_gid);
|
| 340 |
|
| 341 | srcu_idx = eventfs_remount_lock();
|
| 342 | rcu_read_lock();
|
| 343 | list_for_each_entry_rcu(ti, &tracefs_inodes, list) {
|
| 344 | if (update_uid) {
|
| 345 | ti->flags &= ~TRACEFS_UID_PERM_SET;
|
| 346 | ti->vfs_inode.i_uid = fsi->uid;
|
| 347 | }
|
| 348 |
|
| 349 | if (update_gid) {
|
| 350 | ti->flags &= ~TRACEFS_GID_PERM_SET;
|
| 351 | ti->vfs_inode.i_gid = fsi->gid;
|
| 352 | }
|
| 353 |
|
| 354 | |
| 355 | * Note, the above ti->vfs_inode updates are
|
| 356 | * used in eventfs_remount() so they must come
|
| 357 | * before calling it.
|
| 358 |
|
| 359 | if (ti->flags & TRACEFS_EVENT_INODE)
|
| 360 | eventfs_remount(ti, update_uid, update_gid);
|
| 361 | }
|
| 362 | rcu_read_unlock();
|
| 363 | eventfs_remount_unlock(srcu_idx);
|
| 364 | }
|
| 365 |
|
| 366 | return 0;
|
| 367 | }
|
| 368 |
|
| 369 | static int tracefs_reconfigure(struct fs_context *fc)
|
| 370 | {
|
| 371 | struct super_block *sb = fc->root->d_sb;
|
| 372 | struct tracefs_fs_info *sb_opts = sb->s_fs_info;
|
| 373 | struct tracefs_fs_info *new_opts = fc->s_fs_info;
|
| 374 |
|
| 375 | if (!new_opts)
|
| 376 | return 0;
|
| 377 |
|
| 378 | sync_filesystem(sb);
|
| 379 |
|
| 380 | *sb_opts = *new_opts;
|
| 381 |
|
| 382 | return tracefs_apply_options(sb, true);
|
| 383 | }
|
| 384 |
|
| 385 | static int tracefs_show_options(struct seq_file *m, struct dentry *root)
|
| 386 | {
|
| 387 | struct tracefs_fs_info *fsi = root->d_sb->s_fs_info;
|
| 388 |
|
| 389 | if (!uid_eq(fsi->uid, GLOBAL_ROOT_UID))
|
| 390 | seq_printf(m, ",uid=%u",
|
| 391 | from_kuid_munged(&init_user_ns, fsi->uid));
|
| 392 | if (!gid_eq(fsi->gid, GLOBAL_ROOT_GID))
|
| 393 | seq_printf(m, ",gid=%u",
|
| 394 | from_kgid_munged(&init_user_ns, fsi->gid));
|
| 395 | if (fsi->mode != TRACEFS_DEFAULT_MODE)
|
| 396 | seq_printf(m, ",mode=%o", fsi->mode);
|
| 397 |
|
| 398 | return 0;
|
| 399 | }
|
| 400 |
|
| 401 | static int tracefs_drop_inode(struct inode *inode)
|
| 402 | {
|
| 403 | struct tracefs_inode *ti = get_tracefs(inode);
|
| 404 |
|
| 405 | |
| 406 | * This inode is being freed and cannot be used for
|
| 407 | * eventfs. Clear the flag so that it doesn't call into
|
| 408 | * eventfs during the remount flag updates. The eventfs_inode
|
| 409 | * gets freed after an SRCU cycle, so the content will still
|
| 410 | * be safe if the iteration is going on now.
|
| 411 |
|
| 412 | ti->flags &= ~TRACEFS_EVENT_INODE;
|
| 413 |
|
| 414 | return 1;
|
| 415 | }
|
| 416 |
|
| 417 | static const struct super_operations tracefs_super_operations = {
|
| 418 | .alloc_inode = tracefs_alloc_inode,
|
| 419 | .free_inode = tracefs_free_inode,
|
| 420 | .destroy_inode = tracefs_destroy_inode,
|
| 421 | .drop_inode = tracefs_drop_inode,
|
| 422 | .statfs = simple_statfs,
|
| 423 | .show_options = tracefs_show_options,
|
| 424 | };
|
| 425 |
|
| 426 | |
| 427 | * It would be cleaner if eventfs had its own dentry ops.
|
| 428 | *
|
| 429 | * Note that d_revalidate is called potentially under RCU,
|
| 430 | * so it can't take the eventfs mutex etc. It's fine - if
|
| 431 | * we open a file just as it's marked dead, things will
|
| 432 | * still work just fine, and just see the old stale case.
|
| 433 |
|
| 434 | static void tracefs_d_release(struct dentry *dentry)
|
| 435 | {
|
| 436 | if (dentry->d_fsdata)
|
| 437 | eventfs_d_release(dentry);
|
| 438 | }
|
| 439 |
|
| 440 | static int tracefs_d_revalidate(struct inode *inode, const struct qstr *name,
|
| 441 | struct dentry *dentry, unsigned int flags)
|
| 442 | {
|
| 443 | struct eventfs_inode *ei = dentry->d_fsdata;
|
| 444 |
|
| 445 | return !(ei && ei->is_freed);
|
| 446 | }
|
| 447 |
|
| 448 | static int tracefs_d_delete(const struct dentry *dentry)
|
| 449 | {
|
| 450 | |
| 451 | * We want to keep eventfs dentries around but not tracefs
|
| 452 | * ones. eventfs dentries have content in d_fsdata.
|
| 453 | * Use d_fsdata to determine if it's a eventfs dentry or not.
|
| 454 |
|
| 455 | return dentry->d_fsdata == NULL;
|
| 456 | }
|
| 457 |
|
| 458 | static const struct dentry_operations tracefs_dentry_operations = {
|
| 459 | .d_revalidate = tracefs_d_revalidate,
|
| 460 | .d_release = tracefs_d_release,
|
| 461 | .d_delete = tracefs_d_delete,
|
| 462 | };
|
| 463 |
|
| 464 | static int tracefs_fill_super(struct super_block *sb, struct fs_context *fc)
|
| 465 | {
|
| 466 | static const struct tree_descr trace_files[] = {{""}};
|
| 467 | int err;
|
| 468 |
|
| 469 | err = simple_fill_super(sb, TRACEFS_MAGIC, trace_files);
|
| 470 | if (err)
|
| 471 | return err;
|
| 472 |
|
| 473 | sb->s_op = &tracefs_super_operations;
|
| 474 | tracefs_apply_options(sb, false);
|
| 475 | set_default_d_op(sb, &tracefs_dentry_operations);
|
| 476 |
|
| 477 | return 0;
|
| 478 | }
|
| 479 |
|
| 480 | static int tracefs_get_tree(struct fs_context *fc)
|
| 481 | {
|
| 482 | int err = get_tree_single(fc, tracefs_fill_super);
|
| 483 |
|
| 484 | if (err)
|
| 485 | return err;
|
| 486 |
|
| 487 | return tracefs_reconfigure(fc);
|
| 488 | }
|
| 489 |
|
| 490 | static void tracefs_free_fc(struct fs_context *fc)
|
| 491 | {
|
| 492 | kfree(fc->s_fs_info);
|
| 493 | }
|
| 494 |
|
| 495 | static const struct fs_context_operations tracefs_context_ops = {
|
| 496 | .free = tracefs_free_fc,
|
| 497 | .parse_param = tracefs_parse_param,
|
| 498 | .get_tree = tracefs_get_tree,
|
| 499 | .reconfigure = tracefs_reconfigure,
|
| 500 | };
|
| 501 |
|
| 502 | static int tracefs_init_fs_context(struct fs_context *fc)
|
| 503 | {
|
| 504 | struct tracefs_fs_info *fsi;
|
| 505 |
|
| 506 | fsi = kzalloc_obj(struct tracefs_fs_info);
|
| 507 | if (!fsi)
|
| 508 | return -ENOMEM;
|
| 509 |
|
| 510 | fsi->mode = TRACEFS_DEFAULT_MODE;
|
| 511 |
|
| 512 | fc->s_fs_info = fsi;
|
| 513 | fc->ops = &tracefs_context_ops;
|
| 514 | return 0;
|
| 515 | }
|
| 516 |
|
| 517 | static struct file_system_type trace_fs_type = {
|
| 518 | .owner = THIS_MODULE,
|
| 519 | .name = "tracefs",
|
| 520 | .init_fs_context = tracefs_init_fs_context,
|
| 521 | .parameters = tracefs_param_specs,
|
| 522 | .kill_sb = kill_anon_super,
|
| 523 | };
|
| 524 | MODULE_ALIAS_FS("tracefs");
|
| 525 |
|
| 526 | struct dentry *tracefs_start_creating(const char *name, struct dentry *parent)
|
| 527 | {
|
| 528 | struct dentry *dentry;
|
| 529 | int error;
|
| 530 |
|
| 531 | pr_debug("tracefs: creating file '%s'\n",name);
|
| 532 |
|
| 533 | error = simple_pin_fs(&trace_fs_type, &tracefs_mount,
|
| 534 | &tracefs_mount_count);
|
| 535 | if (error)
|
| 536 | return ERR_PTR(error);
|
| 537 |
|
| 538 | |
| 539 | * We need the root dentry to do this, which is in the super
|
| 540 | * block. A pointer to that is in the struct vfsmount that we
|
| 541 | * have around.
|
| 542 |
|
| 543 | if (!parent)
|
| 544 | parent = tracefs_mount->mnt_root;
|
| 545 |
|
| 546 | dentry = simple_start_creating(parent, name);
|
| 547 | if (IS_ERR(dentry))
|
| 548 | simple_release_fs(&tracefs_mount, &tracefs_mount_count);
|
| 549 |
|
| 550 | return dentry;
|
| 551 | }
|
| 552 |
|
| 553 | struct dentry *tracefs_failed_creating(struct dentry *dentry)
|
| 554 | {
|
| 555 | simple_done_creating(dentry);
|
| 556 | simple_release_fs(&tracefs_mount, &tracefs_mount_count);
|
| 557 | return NULL;
|
| 558 | }
|
| 559 |
|
| 560 | struct dentry *tracefs_end_creating(struct dentry *dentry)
|
| 561 | {
|
| 562 | simple_done_creating(dentry);
|
| 563 | return dentry; |
| 564 | }
|
| 565 |
|
| 566 |
|
| 567 | static struct inode *instance_inode(struct dentry *parent, struct inode *inode)
|
| 568 | {
|
| 569 | struct tracefs_inode *ti;
|
| 570 |
|
| 571 |
|
| 572 | if (!parent)
|
| 573 | return d_inode(inode->i_sb->s_root);
|
| 574 |
|
| 575 |
|
| 576 | while (!IS_ROOT(parent)) {
|
| 577 | ti = get_tracefs(d_inode(parent));
|
| 578 | if (ti->flags & TRACEFS_INSTANCE_INODE)
|
| 579 | break;
|
| 580 | parent = parent->d_parent;
|
| 581 | }
|
| 582 |
|
| 583 | return d_inode(parent);
|
| 584 | }
|
| 585 |
|
| 586 | |
| 587 | * tracefs_create_file - create a file in the tracefs filesystem
|
| 588 | * @name: a pointer to a string containing the name of the file to create.
|
| 589 | * @mode: the permission that the file should have.
|
| 590 | * @parent: a pointer to the parent dentry for this file. This should be a
|
| 591 | * directory dentry if set. If this parameter is NULL, then the
|
| 592 | * file will be created in the root of the tracefs filesystem.
|
| 593 | * @data: a pointer to something that the caller will want to get to later
|
| 594 | * on. The inode.i_private pointer will point to this value on
|
| 595 | * the open() call.
|
| 596 | * @fops: a pointer to a struct file_operations that should be used for
|
| 597 | * this file.
|
| 598 | *
|
| 599 | * This is the basic "create a file" function for tracefs. It allows for a
|
| 600 | * wide range of flexibility in creating a file, or a directory (if you want
|
| 601 | * to create a directory, the tracefs_create_dir() function is
|
| 602 | * recommended to be used instead.)
|
| 603 | *
|
| 604 | * This function will return a pointer to a dentry if it succeeds. This
|
| 605 | * pointer must be passed to the tracefs_remove() function when the file is
|
| 606 | * to be removed (no automatic cleanup happens if your module is unloaded,
|
| 607 | * you are responsible here.) If an error occurs, %NULL will be returned.
|
| 608 | *
|
| 609 | * If tracefs is not enabled in the kernel, the value -%ENODEV will be
|
| 610 | * returned.
|
| 611 |
|
| 612 | struct dentry *tracefs_create_file(const char *name, umode_t mode,
|
| 613 | struct dentry *parent, void *data,
|
| 614 | const struct file_operations *fops)
|
| 615 | {
|
| 616 | struct tracefs_inode *ti;
|
| 617 | struct dentry *dentry;
|
| 618 | struct inode *inode;
|
| 619 |
|
| 620 | if (security_locked_down(LOCKDOWN_TRACEFS))
|
| 621 | return NULL;
|
| 622 |
|
| 623 | if (!(mode & S_IFMT))
|
| 624 | mode |= S_IFREG;
|
| 625 | BUG_ON(!S_ISREG(mode));
|
| 626 | dentry = tracefs_start_creating(name, parent);
|
| 627 |
|
| 628 | if (IS_ERR(dentry))
|
| 629 | return NULL;
|
| 630 |
|
| 631 | inode = tracefs_get_inode(dentry->d_sb);
|
| 632 | if (unlikely(!inode))
|
| 633 | return tracefs_failed_creating(dentry);
|
| 634 |
|
| 635 | ti = get_tracefs(inode);
|
| 636 | ti->private = instance_inode(parent, inode);
|
| 637 |
|
| 638 | inode->i_mode = mode;
|
| 639 | inode->i_op = &tracefs_file_inode_operations;
|
| 640 | inode->i_fop = fops ? fops : &tracefs_file_operations;
|
| 641 | inode->i_private = data;
|
| 642 | inode->i_uid = d_inode(dentry->d_parent)->i_uid;
|
| 643 | inode->i_gid = d_inode(dentry->d_parent)->i_gid;
|
| 644 | d_make_persistent(dentry, inode);
|
| 645 | fsnotify_create(d_inode(dentry->d_parent), dentry);
|
| 646 | return tracefs_end_creating(dentry);
|
| 647 | }
|
| 648 | EXPORT_SYMBOL_GPL(tracefs_create_file);
|
| 649 |
|
| 650 | static struct dentry *__create_dir(const char *name, struct dentry *parent,
|
| 651 | const struct inode_operations *ops)
|
| 652 | {
|
| 653 | struct tracefs_inode *ti;
|
| 654 | struct dentry *dentry = tracefs_start_creating(name, parent);
|
| 655 | struct inode *inode;
|
| 656 |
|
| 657 | if (IS_ERR(dentry))
|
| 658 | return NULL;
|
| 659 |
|
| 660 | inode = tracefs_get_inode(dentry->d_sb);
|
| 661 | if (unlikely(!inode))
|
| 662 | return tracefs_failed_creating(dentry);
|
| 663 |
|
| 664 |
|
| 665 | inode->i_mode = S_IFDIR | S_IRWXU | S_IRUSR| S_IRGRP | S_IXUSR | S_IXGRP;
|
| 666 | inode->i_op = ops;
|
| 667 | inode->i_fop = &simple_dir_operations;
|
| 668 | inode->i_uid = d_inode(dentry->d_parent)->i_uid;
|
| 669 | inode->i_gid = d_inode(dentry->d_parent)->i_gid;
|
| 670 |
|
| 671 | ti = get_tracefs(inode);
|
| 672 | ti->private = instance_inode(parent, inode);
|
| 673 |
|
| 674 |
|
| 675 | inc_nlink(inode);
|
| 676 | d_make_persistent(dentry, inode);
|
| 677 | inc_nlink(d_inode(dentry->d_parent));
|
| 678 | fsnotify_mkdir(d_inode(dentry->d_parent), dentry);
|
| 679 | return tracefs_end_creating(dentry);
|
| 680 | }
|
| 681 |
|
| 682 | |
| 683 | * tracefs_create_dir - create a directory in the tracefs filesystem
|
| 684 | * @name: a pointer to a string containing the name of the directory to
|
| 685 | * create.
|
| 686 | * @parent: a pointer to the parent dentry for this file. This should be a
|
| 687 | * directory dentry if set. If this parameter is NULL, then the
|
| 688 | * directory will be created in the root of the tracefs filesystem.
|
| 689 | *
|
| 690 | * This function creates a directory in tracefs with the given name.
|
| 691 | *
|
| 692 | * This function will return a pointer to a dentry if it succeeds. This
|
| 693 | * pointer must be passed to the tracefs_remove() function when the file is
|
| 694 | * to be removed. If an error occurs, %NULL will be returned.
|
| 695 | *
|
| 696 | * If tracing is not enabled in the kernel, the value -%ENODEV will be
|
| 697 | * returned.
|
| 698 |
|
| 699 | struct dentry *tracefs_create_dir(const char *name, struct dentry *parent)
|
| 700 | {
|
| 701 | if (security_locked_down(LOCKDOWN_TRACEFS))
|
| 702 | return NULL;
|
| 703 |
|
| 704 | return __create_dir(name, parent, &tracefs_dir_inode_operations);
|
| 705 | }
|
| 706 |
|
| 707 | |
| 708 | * tracefs_create_instance_dir - create the tracing instances directory
|
| 709 | * @name: The name of the instances directory to create
|
| 710 | * @parent: The parent directory that the instances directory will exist
|
| 711 | * @mkdir: The function to call when a mkdir is performed.
|
| 712 | * @rmdir: The function to call when a rmdir is performed.
|
| 713 | *
|
| 714 | * Only one instances directory is allowed.
|
| 715 | *
|
| 716 | * The instances directory is special as it allows for mkdir and rmdir
|
| 717 | * to be done by userspace. When a mkdir or rmdir is performed, the inode
|
| 718 | * locks are released and the methods passed in (@mkdir and @rmdir) are
|
| 719 | * called without locks and with the name of the directory being created
|
| 720 | * within the instances directory.
|
| 721 | *
|
| 722 | * Returns the dentry of the instances directory.
|
| 723 |
|
| 724 | __init struct dentry *tracefs_create_instance_dir(const char *name,
|
| 725 | struct dentry *parent,
|
| 726 | int (*mkdir)(const char *name),
|
| 727 | int (*rmdir)(const char *name))
|
| 728 | {
|
| 729 | struct dentry *dentry;
|
| 730 |
|
| 731 |
|
| 732 | if (WARN_ON(tracefs_ops.mkdir || tracefs_ops.rmdir))
|
| 733 | return NULL;
|
| 734 |
|
| 735 | dentry = __create_dir(name, parent, &tracefs_instance_dir_inode_operations);
|
| 736 | if (!dentry)
|
| 737 | return NULL;
|
| 738 |
|
| 739 | tracefs_ops.mkdir = mkdir;
|
| 740 | tracefs_ops.rmdir = rmdir;
|
| 741 |
|
| 742 | return dentry;
|
| 743 | }
|
| 744 |
|
| 745 | static void remove_one(struct dentry *victim)
|
| 746 | {
|
| 747 | simple_release_fs(&tracefs_mount, &tracefs_mount_count);
|
| 748 | }
|
| 749 |
|
| 750 | |
| 751 | * tracefs_remove - recursively removes a directory
|
| 752 | * @dentry: a pointer to a the dentry of the directory to be removed.
|
| 753 | *
|
| 754 | * This function recursively removes a directory tree in tracefs that
|
| 755 | * was previously created with a call to another tracefs function
|
| 756 | * (like tracefs_create_file() or variants thereof.)
|
| 757 |
|
| 758 | void tracefs_remove(struct dentry *dentry)
|
| 759 | {
|
| 760 | if (IS_ERR_OR_NULL(dentry))
|
| 761 | return;
|
| 762 |
|
| 763 | simple_pin_fs(&trace_fs_type, &tracefs_mount, &tracefs_mount_count);
|
| 764 | simple_recursive_removal(dentry, remove_one);
|
| 765 | simple_release_fs(&tracefs_mount, &tracefs_mount_count);
|
| 766 | }
|
| 767 |
|
| 768 | |
| 769 | * tracefs_initialized - Tells whether tracefs has been registered
|
| 770 |
|
| 771 | bool tracefs_initialized(void)
|
| 772 | {
|
| 773 | return tracefs_registered;
|
| 774 | }
|
| 775 |
|
| 776 | static void init_once(void *foo)
|
| 777 | {
|
| 778 | struct tracefs_inode *ti = (struct tracefs_inode *) foo;
|
| 779 |
|
| 780 |
|
| 781 | inode_init_once(&ti->vfs_inode);
|
| 782 |
|
| 783 |
|
| 784 | memset_after(ti, 0, vfs_inode);
|
| 785 | }
|
| 786 |
|
| 787 | static int __init tracefs_init(void)
|
| 788 | {
|
| 789 | int retval;
|
| 790 |
|
| 791 | tracefs_inode_cachep = kmem_cache_create("tracefs_inode_cache",
|
| 792 | sizeof(struct tracefs_inode),
|
| 793 | 0, (SLAB_RECLAIM_ACCOUNT|
|
| 794 | SLAB_ACCOUNT),
|
| 795 | init_once);
|
| 796 | if (!tracefs_inode_cachep)
|
| 797 | return -ENOMEM;
|
| 798 |
|
| 799 | retval = sysfs_create_mount_point(kernel_kobj, "tracing");
|
| 800 | if (retval)
|
| 801 | return -EINVAL;
|
| 802 |
|
| 803 | retval = register_filesystem(&trace_fs_type);
|
| 804 | if (!retval)
|
| 805 | tracefs_registered = true;
|
| 806 |
|
| 807 | return retval;
|
| 808 | }
|
| 809 | core_initcall(tracefs_init);
|