Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tracing: Have mkdir and rmdir be part of tracefs

The tracing "instances" directory can create sub tracing buffers
with mkdir, and remove them with rmdir. As a mkdir will also create
all the files and directories that control the sub buffer the inode
mutexes need to be released before this is done, to avoid deadlocks.
It is better to let the tracing system unlock the inode mutexes before
calling the functions that create the files within the new directory
(or deletes the files from the one being destroyed).

Now that tracing has been converted over to tracefs, the tracefs file
system can be modified to accommodate this feature. It still releases
the locks, but the filesystem itself can take care of the ugly
business and let the user just do what it needs.

The tracing system now attaches a descriptor to the directory dentry
that can have userspace create or remove sub directories. If this
descriptor does not exist for a dentry, then that dentry can not be
used to create other directories. This descriptor holds a mkdir and
rmdir method that only takes a character string as an argument.

The tracefs file system will first make a copy of the dentry name
before releasing the locks. Then it will pass the copied name to the
methods. It is up to the tracing system that supplied the methods to
handle races with duplicate names and such as all the inode mutexes
would be released when the functions are called.

Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

+145 -85
+136 -15
fs/tracefs/inode.c
··· 50 50 .llseek = noop_llseek, 51 51 }; 52 52 53 + static struct tracefs_dir_ops { 54 + int (*mkdir)(const char *name); 55 + int (*rmdir)(const char *name); 56 + } tracefs_ops; 57 + 58 + static char *get_dname(struct dentry *dentry) 59 + { 60 + const char *dname; 61 + char *name; 62 + int len = dentry->d_name.len; 63 + 64 + dname = dentry->d_name.name; 65 + name = kmalloc(len + 1, GFP_KERNEL); 66 + if (!name) 67 + return NULL; 68 + memcpy(name, dname, len); 69 + name[len] = 0; 70 + return name; 71 + } 72 + 73 + static int tracefs_syscall_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode) 74 + { 75 + char *name; 76 + int ret; 77 + 78 + name = get_dname(dentry); 79 + if (!name) 80 + return -ENOMEM; 81 + 82 + /* 83 + * The mkdir call can call the generic functions that create 84 + * the files within the tracefs system. It is up to the individual 85 + * mkdir routine to handle races. 86 + */ 87 + mutex_unlock(&inode->i_mutex); 88 + ret = tracefs_ops.mkdir(name); 89 + mutex_lock(&inode->i_mutex); 90 + 91 + kfree(name); 92 + 93 + return ret; 94 + } 95 + 96 + static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry) 97 + { 98 + char *name; 99 + int ret; 100 + 101 + name = get_dname(dentry); 102 + if (!name) 103 + return -ENOMEM; 104 + 105 + /* 106 + * The rmdir call can call the generic functions that create 107 + * the files within the tracefs system. It is up to the individual 108 + * rmdir routine to handle races. 109 + * This time we need to unlock not only the parent (inode) but 110 + * also the directory that is being deleted. 111 + */ 112 + mutex_unlock(&inode->i_mutex); 113 + mutex_unlock(&dentry->d_inode->i_mutex); 114 + 115 + ret = tracefs_ops.rmdir(name); 116 + 117 + mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); 118 + mutex_lock(&dentry->d_inode->i_mutex); 119 + 120 + kfree(name); 121 + 122 + return ret; 123 + } 124 + 125 + static const struct inode_operations tracefs_dir_inode_operations = { 126 + .lookup = simple_lookup, 127 + .mkdir = tracefs_syscall_mkdir, 128 + .rmdir = tracefs_syscall_rmdir, 129 + }; 130 + 53 131 static struct inode *tracefs_get_inode(struct super_block *sb) 54 132 { 55 133 struct inode *inode = new_inode(sb); ··· 412 334 return end_creating(dentry); 413 335 } 414 336 337 + static struct dentry *__create_dir(const char *name, struct dentry *parent, 338 + const struct inode_operations *ops) 339 + { 340 + struct dentry *dentry = start_creating(name, parent); 341 + struct inode *inode; 342 + 343 + if (IS_ERR(dentry)) 344 + return NULL; 345 + 346 + inode = tracefs_get_inode(dentry->d_sb); 347 + if (unlikely(!inode)) 348 + return failed_creating(dentry); 349 + 350 + inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; 351 + inode->i_op = ops; 352 + inode->i_fop = &simple_dir_operations; 353 + 354 + /* directory inodes start off with i_nlink == 2 (for "." entry) */ 355 + inc_nlink(inode); 356 + d_instantiate(dentry, inode); 357 + inc_nlink(dentry->d_parent->d_inode); 358 + fsnotify_mkdir(dentry->d_parent->d_inode, dentry); 359 + return end_creating(dentry); 360 + } 361 + 415 362 /** 416 363 * tracefs_create_dir - create a directory in the tracefs filesystem 417 364 * @name: a pointer to a string containing the name of the directory to ··· 456 353 */ 457 354 struct dentry *tracefs_create_dir(const char *name, struct dentry *parent) 458 355 { 459 - struct dentry *dentry = start_creating(name, parent); 460 - struct inode *inode; 356 + return __create_dir(name, parent, &simple_dir_inode_operations); 357 + } 461 358 462 - if (IS_ERR(dentry)) 359 + /** 360 + * tracefs_create_instance_dir - create the tracing instances directory 361 + * @name: The name of the instances directory to create 362 + * @parent: The parent directory that the instances directory will exist 363 + * @mkdir: The function to call when a mkdir is performed. 364 + * @rmdir: The function to call when a rmdir is performed. 365 + * 366 + * Only one instances directory is allowed. 367 + * 368 + * The instances directory is special as it allows for mkdir and rmdir to 369 + * to be done by userspace. When a mkdir or rmdir is performed, the inode 370 + * locks are released and the methhods passed in (@mkdir and @rmdir) are 371 + * called without locks and with the name of the directory being created 372 + * within the instances directory. 373 + * 374 + * Returns the dentry of the instances directory. 375 + */ 376 + struct dentry *tracefs_create_instance_dir(const char *name, struct dentry *parent, 377 + int (*mkdir)(const char *name), 378 + int (*rmdir)(const char *name)) 379 + { 380 + struct dentry *dentry; 381 + 382 + /* Only allow one instance of the instances directory. */ 383 + if (WARN_ON(tracefs_ops.mkdir || tracefs_ops.rmdir)) 463 384 return NULL; 464 385 465 - inode = tracefs_get_inode(dentry->d_sb); 466 - if (unlikely(!inode)) 467 - return failed_creating(dentry); 386 + dentry = __create_dir(name, parent, &tracefs_dir_inode_operations); 387 + if (!dentry) 388 + return NULL; 468 389 469 - inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; 470 - inode->i_op = &simple_dir_inode_operations; 471 - inode->i_fop = &simple_dir_operations; 390 + tracefs_ops.mkdir = mkdir; 391 + tracefs_ops.rmdir = rmdir; 472 392 473 - /* directory inodes start off with i_nlink == 2 (for "." entry) */ 474 - inc_nlink(inode); 475 - d_instantiate(dentry, inode); 476 - inc_nlink(dentry->d_parent->d_inode); 477 - fsnotify_mkdir(dentry->d_parent->d_inode, dentry); 478 - return end_creating(dentry); 393 + return dentry; 479 394 } 480 395 481 396 static inline int tracefs_positive(struct dentry *dentry)
+4
include/linux/tracefs.h
··· 34 34 void tracefs_remove(struct dentry *dentry); 35 35 void tracefs_remove_recursive(struct dentry *dentry); 36 36 37 + struct dentry *tracefs_create_instance_dir(const char *name, struct dentry *parent, 38 + int (*mkdir)(const char *name), 39 + int (*rmdir)(const char *name)); 40 + 37 41 bool tracefs_initialized(void); 38 42 39 43 #endif /* CONFIG_TRACING */
+5 -70
kernel/trace/trace.c
··· 6292 6292 #endif 6293 6293 } 6294 6294 6295 - static int new_instance_create(const char *name) 6295 + static int instance_mkdir(const char *name) 6296 6296 { 6297 6297 struct trace_array *tr; 6298 6298 int ret; ··· 6362 6362 6363 6363 } 6364 6364 6365 - static int instance_delete(const char *name) 6365 + static int instance_rmdir(const char *name) 6366 6366 { 6367 6367 struct trace_array *tr; 6368 6368 int found = 0; ··· 6403 6403 return ret; 6404 6404 } 6405 6405 6406 - static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t mode) 6407 - { 6408 - struct dentry *parent; 6409 - int ret; 6410 - 6411 - /* Paranoid: Make sure the parent is the "instances" directory */ 6412 - parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); 6413 - if (WARN_ON_ONCE(parent != trace_instance_dir)) 6414 - return -ENOENT; 6415 - 6416 - /* 6417 - * The inode mutex is locked, but tracefs_create_dir() will also 6418 - * take the mutex. As the instances directory can not be destroyed 6419 - * or changed in any other way, it is safe to unlock it, and 6420 - * let the dentry try. If two users try to make the same dir at 6421 - * the same time, then the new_instance_create() will determine the 6422 - * winner. 6423 - */ 6424 - mutex_unlock(&inode->i_mutex); 6425 - 6426 - ret = new_instance_create(dentry->d_iname); 6427 - 6428 - mutex_lock(&inode->i_mutex); 6429 - 6430 - return ret; 6431 - } 6432 - 6433 - static int instance_rmdir(struct inode *inode, struct dentry *dentry) 6434 - { 6435 - struct dentry *parent; 6436 - int ret; 6437 - 6438 - /* Paranoid: Make sure the parent is the "instances" directory */ 6439 - parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); 6440 - if (WARN_ON_ONCE(parent != trace_instance_dir)) 6441 - return -ENOENT; 6442 - 6443 - /* The caller did a dget() on dentry */ 6444 - mutex_unlock(&dentry->d_inode->i_mutex); 6445 - 6446 - /* 6447 - * The inode mutex is locked, but tracefs_create_dir() will also 6448 - * take the mutex. As the instances directory can not be destroyed 6449 - * or changed in any other way, it is safe to unlock it, and 6450 - * let the dentry try. If two users try to make the same dir at 6451 - * the same time, then the instance_delete() will determine the 6452 - * winner. 6453 - */ 6454 - mutex_unlock(&inode->i_mutex); 6455 - 6456 - ret = instance_delete(dentry->d_iname); 6457 - 6458 - mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); 6459 - mutex_lock(&dentry->d_inode->i_mutex); 6460 - 6461 - return ret; 6462 - } 6463 - 6464 - static const struct inode_operations instance_dir_inode_operations = { 6465 - .lookup = simple_lookup, 6466 - .mkdir = instance_mkdir, 6467 - .rmdir = instance_rmdir, 6468 - }; 6469 - 6470 6406 static __init void create_trace_instances(struct dentry *d_tracer) 6471 6407 { 6472 - trace_instance_dir = tracefs_create_dir("instances", d_tracer); 6408 + trace_instance_dir = tracefs_create_instance_dir("instances", d_tracer, 6409 + instance_mkdir, 6410 + instance_rmdir); 6473 6411 if (WARN_ON(!trace_instance_dir)) 6474 6412 return; 6475 - 6476 - /* Hijack the dir inode operations, to allow mkdir */ 6477 - trace_instance_dir->d_inode->i_op = &instance_dir_inode_operations; 6478 6413 } 6479 6414 6480 6415 static void