Thread (47 messages) 47 messages, 10 authors, 2018-04-22

Re: [PATCH 05/11] fs: add iterate_supers_excl() and iterate_supers_reverse_excl()

From: "Rafael J. Wysocki" <rafael@kernel.org>
Date: 2017-11-29 23:48:16
Also in: linux-block, linux-fsdevel, linux-xfs, lkml

On Thu, Nov 30, 2017 at 12:23 AM, Luis R. Rodriguez [off-list ref] wrote:
quoted hunk ↗ jump to hunk
There are use cases where we wish to traverse the superblock list
but also capture errors, and in which case we want to avoid having
our callers issue a lock themselves since we can do the locking for
the callers. Provide a iterate_supers_excl() which calls a function
with the write lock held. If an error occurs we capture it and
propagate it.

Likewise there are use cases where we wish to traverse the superblock
list but in reverse order. The new iterate_supers_reverse_excl() helpers
does this but also also captures any errors encountered.

Signed-off-by: Luis R. Rodriguez <mcgrof@kernel.org>
---
 fs/super.c         | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fs.h |  2 ++
 2 files changed, 93 insertions(+)
diff --git a/fs/super.c b/fs/super.c
index a63513d187e8..885711c1d35b 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -605,6 +605,97 @@ void iterate_supers(void (*f)(struct super_block *, void *), void *arg)
        spin_unlock(&sb_lock);
 }

+/**
+ *     iterate_supers_excl - exclusively call func for all active superblocks
+ *     @f: function to call
+ *     @arg: argument to pass to it
+ *
+ *     Scans the superblock list and calls given function, passing it
+ *     locked superblock and given argument. Returns 0 unless an error
+ *     occurred on calling the function on any superblock.
+ */
+int iterate_supers_excl(int (*f)(struct super_block *, void *), void *arg)
+{
+       struct super_block *sb, *p = NULL;
+       int error = 0;
+
+       spin_lock(&sb_lock);
+       list_for_each_entry(sb, &super_blocks, s_list) {
+               if (hlist_unhashed(&sb->s_instances))
+                       continue;
+               sb->s_count++;
+               spin_unlock(&sb_lock);
Can anything bad happen if the list is modified at this point by a
concurrent thread?
+
+               down_write(&sb->s_umount);
+               if (sb->s_root && (sb->s_flags & SB_BORN)) {
+                       error = f(sb, arg);
+                       if (error) {
+                               up_write(&sb->s_umount);
+                               spin_lock(&sb_lock);
+                               __put_super(sb);
+                               break;
+                       }
+               }
+               up_write(&sb->s_umount);
+
+               spin_lock(&sb_lock);
+               if (p)
+                       __put_super(p);
+               p = sb;
+       }
+       if (p)
+               __put_super(p);
+       spin_unlock(&sb_lock);
+
+       return error;
+}
+
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help