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

debugfs: Implement debugfs_remove_recursive()

debugfs_remove_recursive() will remove a dentry and all its children.
Drivers can use this to zap their whole debugfs tree so that they don't
need to keep track of every single debugfs dentry they created.

It may fail to remove the whole tree in certain cases:

sh-3.2# rmmod atmel-mci < /sys/kernel/debug/mmc0/ios/clock
mmc0: card b368 removed
atmel_mci atmel_mci.0: Lost dma0chan1, falling back to PIO
sh-3.2# ls /sys/kernel/debug/mmc0/
ios

But I'm not sure if that case can be handled in any sane manner.

Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
Cc: Pierre Ossman <drzeus-list@drzeus.cx>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Haavard Skinnemoen and committed by
Greg Kroah-Hartman
9505e637 43166141

+105 -23
+101 -23
fs/debugfs/inode.c
··· 309 309 } 310 310 EXPORT_SYMBOL_GPL(debugfs_create_symlink); 311 311 312 - /** 313 - * debugfs_remove - removes a file or directory from the debugfs filesystem 314 - * @dentry: a pointer to a the dentry of the file or directory to be 315 - * removed. 316 - * 317 - * This function removes a file or directory in debugfs that was previously 318 - * created with a call to another debugfs function (like 319 - * debugfs_create_file() or variants thereof.) 320 - * 321 - * This function is required to be called in order for the file to be 322 - * removed, no automatic cleanup of files will happen when a module is 323 - * removed, you are responsible here. 324 - */ 325 - void debugfs_remove(struct dentry *dentry) 312 + static void __debugfs_remove(struct dentry *dentry, struct dentry *parent) 326 313 { 327 - struct dentry *parent; 328 314 int ret = 0; 329 - 330 - if (!dentry) 331 - return; 332 315 333 - parent = dentry->d_parent; 334 - if (!parent || !parent->d_inode) 335 - return; 336 - 337 - mutex_lock(&parent->d_inode->i_mutex); 338 316 if (debugfs_positive(dentry)) { 339 317 if (dentry->d_inode) { 340 318 dget(dentry); ··· 332 354 dput(dentry); 333 355 } 334 356 } 357 + } 358 + 359 + /** 360 + * debugfs_remove - removes a file or directory from the debugfs filesystem 361 + * @dentry: a pointer to a the dentry of the file or directory to be 362 + * removed. 363 + * 364 + * This function removes a file or directory in debugfs that was previously 365 + * created with a call to another debugfs function (like 366 + * debugfs_create_file() or variants thereof.) 367 + * 368 + * This function is required to be called in order for the file to be 369 + * removed, no automatic cleanup of files will happen when a module is 370 + * removed, you are responsible here. 371 + */ 372 + void debugfs_remove(struct dentry *dentry) 373 + { 374 + struct dentry *parent; 375 + 376 + if (!dentry) 377 + return; 378 + 379 + parent = dentry->d_parent; 380 + if (!parent || !parent->d_inode) 381 + return; 382 + 383 + mutex_lock(&parent->d_inode->i_mutex); 384 + __debugfs_remove(dentry, parent); 335 385 mutex_unlock(&parent->d_inode->i_mutex); 336 386 simple_release_fs(&debugfs_mount, &debugfs_mount_count); 337 387 } 338 388 EXPORT_SYMBOL_GPL(debugfs_remove); 389 + 390 + /** 391 + * debugfs_remove_recursive - recursively removes a directory 392 + * @dentry: a pointer to a the dentry of the directory to be removed. 393 + * 394 + * This function recursively removes a directory tree in debugfs that 395 + * was previously created with a call to another debugfs function 396 + * (like debugfs_create_file() or variants thereof.) 397 + * 398 + * This function is required to be called in order for the file to be 399 + * removed, no automatic cleanup of files will happen when a module is 400 + * removed, you are responsible here. 401 + */ 402 + void debugfs_remove_recursive(struct dentry *dentry) 403 + { 404 + struct dentry *child; 405 + struct dentry *parent; 406 + 407 + if (!dentry) 408 + return; 409 + 410 + parent = dentry->d_parent; 411 + if (!parent || !parent->d_inode) 412 + return; 413 + 414 + parent = dentry; 415 + mutex_lock(&parent->d_inode->i_mutex); 416 + 417 + while (1) { 418 + /* 419 + * When all dentries under "parent" has been removed, 420 + * walk up the tree until we reach our starting point. 421 + */ 422 + if (list_empty(&parent->d_subdirs)) { 423 + mutex_unlock(&parent->d_inode->i_mutex); 424 + if (parent == dentry) 425 + break; 426 + parent = parent->d_parent; 427 + mutex_lock(&parent->d_inode->i_mutex); 428 + } 429 + child = list_entry(parent->d_subdirs.next, struct dentry, 430 + d_u.d_child); 431 + 432 + /* 433 + * If "child" isn't empty, walk down the tree and 434 + * remove all its descendants first. 435 + */ 436 + if (!list_empty(&child->d_subdirs)) { 437 + mutex_unlock(&parent->d_inode->i_mutex); 438 + parent = child; 439 + mutex_lock(&parent->d_inode->i_mutex); 440 + continue; 441 + } 442 + __debugfs_remove(child, parent); 443 + if (parent->d_subdirs.next == &child->d_u.d_child) { 444 + /* 445 + * Avoid infinite loop if we fail to remove 446 + * one dentry. 447 + */ 448 + mutex_unlock(&parent->d_inode->i_mutex); 449 + break; 450 + } 451 + simple_release_fs(&debugfs_mount, &debugfs_mount_count); 452 + } 453 + 454 + parent = dentry->d_parent; 455 + mutex_lock(&parent->d_inode->i_mutex); 456 + __debugfs_remove(dentry, parent); 457 + mutex_unlock(&parent->d_inode->i_mutex); 458 + simple_release_fs(&debugfs_mount, &debugfs_mount_count); 459 + } 460 + EXPORT_SYMBOL_GPL(debugfs_remove_recursive); 339 461 340 462 /** 341 463 * debugfs_rename - rename a file/directory in the debugfs filesystem
+4
include/linux/debugfs.h
··· 44 44 const char *dest); 45 45 46 46 void debugfs_remove(struct dentry *dentry); 47 + void debugfs_remove_recursive(struct dentry *dentry); 47 48 48 49 struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, 49 50 struct dentry *new_dir, const char *new_name); ··· 100 99 } 101 100 102 101 static inline void debugfs_remove(struct dentry *dentry) 102 + { } 103 + 104 + static inline void debugfs_remove_recursive(struct dentry *dentry) 103 105 { } 104 106 105 107 static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,