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;
+}
+