aboutsummaryrefslogtreecommitdiffstats
path: root/fs/debugfs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/debugfs/inode.c')
-rw-r--r--fs/debugfs/inode.c114
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}
310EXPORT_SYMBOL_GPL(debugfs_create_symlink); 310EXPORT_SYMBOL_GPL(debugfs_create_symlink);
311 311
312static 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);
325void debugfs_remove(struct dentry *dentry) 350void 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: 366EXPORT_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 */
380void 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}
360EXPORT_SYMBOL_GPL(debugfs_remove); 438EXPORT_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