diff options
Diffstat (limited to 'fs/debugfs')
| -rw-r--r-- | fs/debugfs/inode.c | 114 |
1 files changed, 96 insertions, 18 deletions
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index e9602d85c11d..08e28c9bb416 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
| @@ -309,6 +309,31 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent, | |||
| 309 | } | 309 | } |
| 310 | EXPORT_SYMBOL_GPL(debugfs_create_symlink); | 310 | EXPORT_SYMBOL_GPL(debugfs_create_symlink); |
| 311 | 311 | ||
| 312 | static void __debugfs_remove(struct dentry *dentry, struct dentry *parent) | ||
| 313 | { | ||
| 314 | int ret = 0; | ||
| 315 | |||
| 316 | if (debugfs_positive(dentry)) { | ||
| 317 | if (dentry->d_inode) { | ||
| 318 | dget(dentry); | ||
| 319 | switch (dentry->d_inode->i_mode & S_IFMT) { | ||
| 320 | case S_IFDIR: | ||
| 321 | ret = simple_rmdir(parent->d_inode, dentry); | ||
| 322 | break; | ||
| 323 | case S_IFLNK: | ||
| 324 | kfree(dentry->d_inode->i_private); | ||
| 325 | /* fall through */ | ||
| 326 | default: | ||
| 327 | simple_unlink(parent->d_inode, dentry); | ||
| 328 | break; | ||
| 329 | } | ||
| 330 | if (!ret) | ||
| 331 | d_delete(dentry); | ||
| 332 | dput(dentry); | ||
| 333 | } | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 312 | /** | 337 | /** |
| 313 | * debugfs_remove - removes a file or directory from the debugfs filesystem | 338 | * 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 | 339 | * @dentry: a pointer to a the dentry of the file or directory to be |
| @@ -325,7 +350,6 @@ EXPORT_SYMBOL_GPL(debugfs_create_symlink); | |||
| 325 | void debugfs_remove(struct dentry *dentry) | 350 | void debugfs_remove(struct dentry *dentry) |
| 326 | { | 351 | { |
| 327 | struct dentry *parent; | 352 | struct dentry *parent; |
| 328 | int ret = 0; | ||
| 329 | 353 | ||
| 330 | if (!dentry) | 354 | if (!dentry) |
| 331 | return; | 355 | return; |
| @@ -335,29 +359,83 @@ void debugfs_remove(struct dentry *dentry) | |||
| 335 | return; | 359 | return; |
| 336 | 360 | ||
| 337 | mutex_lock(&parent->d_inode->i_mutex); | 361 | mutex_lock(&parent->d_inode->i_mutex); |
| 338 | if (debugfs_positive(dentry)) { | 362 | __debugfs_remove(dentry, parent); |
| 339 | if (dentry->d_inode) { | 363 | mutex_unlock(&parent->d_inode->i_mutex); |
| 340 | dget(dentry); | 364 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); |
| 341 | switch (dentry->d_inode->i_mode & S_IFMT) { | 365 | } |
| 342 | case S_IFDIR: | 366 | EXPORT_SYMBOL_GPL(debugfs_remove); |
| 343 | ret = simple_rmdir(parent->d_inode, dentry); | 367 | |
| 344 | break; | 368 | /** |
| 345 | case S_IFLNK: | 369 | * debugfs_remove_recursive - recursively removes a directory |
| 346 | kfree(dentry->d_inode->i_private); | 370 | * @dentry: a pointer to a the dentry of the directory to be removed. |
| 347 | /* fall through */ | 371 | * |
| 348 | default: | 372 | * This function recursively removes a directory tree in debugfs that |
| 349 | simple_unlink(parent->d_inode, dentry); | 373 | * was previously created with a call to another debugfs function |
| 374 | * (like debugfs_create_file() or variants thereof.) | ||
| 375 | * | ||
| 376 | * This function is required to be called in order for the file to be | ||
| 377 | * removed, no automatic cleanup of files will happen when a module is | ||
| 378 | * removed, you are responsible here. | ||
| 379 | */ | ||
| 380 | void debugfs_remove_recursive(struct dentry *dentry) | ||
| 381 | { | ||
| 382 | struct dentry *child; | ||
| 383 | struct dentry *parent; | ||
| 384 | |||
| 385 | if (!dentry) | ||
| 386 | return; | ||
| 387 | |||
| 388 | parent = dentry->d_parent; | ||
| 389 | if (!parent || !parent->d_inode) | ||
| 390 | return; | ||
| 391 | |||
| 392 | parent = dentry; | ||
| 393 | mutex_lock(&parent->d_inode->i_mutex); | ||
| 394 | |||
| 395 | while (1) { | ||
| 396 | /* | ||
| 397 | * When all dentries under "parent" has been removed, | ||
| 398 | * walk up the tree until we reach our starting point. | ||
| 399 | */ | ||
| 400 | if (list_empty(&parent->d_subdirs)) { | ||
| 401 | mutex_unlock(&parent->d_inode->i_mutex); | ||
| 402 | if (parent == dentry) | ||
| 350 | break; | 403 | break; |
| 351 | } | 404 | parent = parent->d_parent; |
| 352 | if (!ret) | 405 | mutex_lock(&parent->d_inode->i_mutex); |
| 353 | d_delete(dentry); | 406 | } |
| 354 | dput(dentry); | 407 | child = list_entry(parent->d_subdirs.next, struct dentry, |
| 408 | d_u.d_child); | ||
| 409 | |||
| 410 | /* | ||
| 411 | * If "child" isn't empty, walk down the tree and | ||
| 412 | * remove all its descendants first. | ||
| 413 | */ | ||
| 414 | if (!list_empty(&child->d_subdirs)) { | ||
| 415 | mutex_unlock(&parent->d_inode->i_mutex); | ||
| 416 | parent = child; | ||
| 417 | mutex_lock(&parent->d_inode->i_mutex); | ||
| 418 | continue; | ||
| 355 | } | 419 | } |
| 420 | __debugfs_remove(child, parent); | ||
| 421 | if (parent->d_subdirs.next == &child->d_u.d_child) { | ||
| 422 | /* | ||
| 423 | * Avoid infinite loop if we fail to remove | ||
| 424 | * one dentry. | ||
| 425 | */ | ||
| 426 | mutex_unlock(&parent->d_inode->i_mutex); | ||
| 427 | break; | ||
| 428 | } | ||
| 429 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | ||
| 356 | } | 430 | } |
| 431 | |||
| 432 | parent = dentry->d_parent; | ||
| 433 | mutex_lock(&parent->d_inode->i_mutex); | ||
| 434 | __debugfs_remove(dentry, parent); | ||
| 357 | mutex_unlock(&parent->d_inode->i_mutex); | 435 | mutex_unlock(&parent->d_inode->i_mutex); |
| 358 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | 436 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); |
| 359 | } | 437 | } |
| 360 | EXPORT_SYMBOL_GPL(debugfs_remove); | 438 | EXPORT_SYMBOL_GPL(debugfs_remove_recursive); |
| 361 | 439 | ||
| 362 | /** | 440 | /** |
| 363 | * debugfs_rename - rename a file/directory in the debugfs filesystem | 441 | * debugfs_rename - rename a file/directory in the debugfs filesystem |
