iterate_supers() calls a function provided by the caller with the s_umount semaphore taken in read mode. However, there may be cases where write mode is preferable, so we add __iterate_supers(), which lets one specify the mode of the lock, and replace iterate_supers with two helpers around __iterate_supers(), iterate_supers_read() and iterate_supers_write(). This will be used to fix the emergency thaw (filesystem unfreeze) code, which iterates over the list of superblocks but needs to hold the s_umount semaphore in _write_ mode bebore carrying out the actual thaw operation. This patch introduces no semantic changes since current iterate_supers() callers are just updated to use iterate_supers_read() instead. Cc: linux-fsdevel@xxxxxxxxxxxxxxx Cc: Josef Bacik <jbacik@xxxxxxxxxxxx> Cc: Eric Sandeen <sandeen@xxxxxxxxxx> Cc: Christoph Hellwig <hch@xxxxxxxxxxxxx> Cc: Dave Chinner <dchinner@xxxxxxxxxx> Cc: Luiz Capitulino <lcapitulino@xxxxxxxxxx> Reviewed-by: Jan Kara <jack@xxxxxxx> Signed-off-by: Fernando Luis Vazquez Cao <fernando@xxxxxxxxxxxxx> --- diff -urNp linux-3.8-rc1-orig/fs/buffer.c linux-3.8-rc1/fs/buffer.c --- linux-3.8-rc1-orig/fs/buffer.c 2012-12-25 10:27:41.166737000 +0900 +++ linux-3.8-rc1/fs/buffer.c 2012-12-25 11:14:41.304018000 +0900 @@ -520,7 +520,7 @@ static void do_thaw_one(struct super_blo static void do_thaw_all(struct work_struct *work) { - iterate_supers(do_thaw_one, NULL); + iterate_supers_read(do_thaw_one, NULL); kfree(work); printk(KERN_WARNING "Emergency Thaw complete\n"); } diff -urNp linux-3.8-rc1-orig/fs/drop_caches.c linux-3.8-rc1/fs/drop_caches.c --- linux-3.8-rc1-orig/fs/drop_caches.c 2012-12-11 12:30:57.000000000 +0900 +++ linux-3.8-rc1/fs/drop_caches.c 2012-12-25 11:14:41.304018000 +0900 @@ -59,7 +59,7 @@ int drop_caches_sysctl_handler(ctl_table return ret; if (write) { if (sysctl_drop_caches & 1) - iterate_supers(drop_pagecache_sb, NULL); + iterate_supers_read(drop_pagecache_sb, NULL); if (sysctl_drop_caches & 2) drop_slab(); } diff -urNp linux-3.8-rc1-orig/fs/quota/quota.c linux-3.8-rc1/fs/quota/quota.c --- linux-3.8-rc1-orig/fs/quota/quota.c 2012-12-25 10:27:42.034737000 +0900 +++ linux-3.8-rc1/fs/quota/quota.c 2012-12-25 11:14:41.304018000 +0900 @@ -58,7 +58,7 @@ static int quota_sync_all(int type) return -EINVAL; ret = security_quotactl(Q_SYNC, type, 0, NULL); if (!ret) - iterate_supers(quota_sync_one, &type); + iterate_supers_read(quota_sync_one, &type); return ret; } diff -urNp linux-3.8-rc1-orig/fs/super.c linux-3.8-rc1/fs/super.c --- linux-3.8-rc1-orig/fs/super.c 2012-12-11 12:30:57.000000000 +0900 +++ linux-3.8-rc1/fs/super.c 2012-12-25 11:14:41.308018000 +0900 @@ -508,14 +508,16 @@ void drop_super(struct super_block *sb) EXPORT_SYMBOL(drop_super); /** - * iterate_supers - call function for all active superblocks + * __iterate_supers - call function for all active superblocks * @f: function to call * @arg: argument to pass to it + * @wlock: mode of superblock lock (false->read lock, true->write lock) * * Scans the superblock list and calls given function, passing it * locked superblock and given argument. */ -void iterate_supers(void (*f)(struct super_block *, void *), void *arg) +static void __iterate_supers(void (*f)(struct super_block *, void *), void *arg, + bool wlock) { struct super_block *sb, *p = NULL; @@ -526,10 +528,18 @@ void iterate_supers(void (*f)(struct sup sb->s_count++; spin_unlock(&sb_lock); - down_read(&sb->s_umount); + if (wlock) + down_write(&sb->s_umount); + else + down_read(&sb->s_umount); + if (sb->s_root && (sb->s_flags & MS_BORN)) f(sb, arg); - up_read(&sb->s_umount); + + if (wlock) + up_write(&sb->s_umount); + else + up_read(&sb->s_umount); spin_lock(&sb_lock); if (p) @@ -542,6 +552,34 @@ void iterate_supers(void (*f)(struct sup } /** + * iterate_supers_read - call function for all active superblocks + * @f: function to call + * @arg: argument to pass to it + * + * Scans the superblock list and calls given function, passing it + * a superblock locked in _read_ mode and given argument. The lock + * is automatically relased after the function returns. + */ +void iterate_supers_read(void (*f)(struct super_block *, void *), void *arg) +{ + __iterate_supers(f, arg , false); +} + +/** + * iterate_supers_write - call function for all active superblocks + * @f: function to call + * @arg: argument to pass to it + * + * Scans the superblock list and calls given function, passing it + * a superblock locked in _write_ mode and given argument. The lock + * is automatically relased after the function returns. + */ +void iterate_supers_write(void (*f)(struct super_block *, void *), void *arg) +{ + __iterate_supers(f, arg , true); +} + +/** * iterate_supers_type - call function for superblocks of given type * @type: fs type * @f: function to call diff -urNp linux-3.8-rc1-orig/fs/sync.c linux-3.8-rc1/fs/sync.c --- linux-3.8-rc1-orig/fs/sync.c 2012-12-11 12:30:57.000000000 +0900 +++ linux-3.8-rc1/fs/sync.c 2012-12-25 11:14:41.312018000 +0900 @@ -104,9 +104,9 @@ SYSCALL_DEFINE0(sync) int nowait = 0, wait = 1; wakeup_flusher_threads(0, WB_REASON_SYNC); - iterate_supers(sync_inodes_one_sb, NULL); - iterate_supers(sync_fs_one_sb, &nowait); - iterate_supers(sync_fs_one_sb, &wait); + iterate_supers_read(sync_inodes_one_sb, NULL); + iterate_supers_read(sync_fs_one_sb, &nowait); + iterate_supers_read(sync_fs_one_sb, &wait); iterate_bdevs(fdatawrite_one_bdev, NULL); iterate_bdevs(fdatawait_one_bdev, NULL); if (unlikely(laptop_mode)) @@ -122,11 +122,11 @@ static void do_sync_work(struct work_str * Sync twice to reduce the possibility we skipped some inodes / pages * because they were temporarily locked */ - iterate_supers(sync_inodes_one_sb, &nowait); - iterate_supers(sync_fs_one_sb, &nowait); + iterate_supers_read(sync_inodes_one_sb, &nowait); + iterate_supers_read(sync_fs_one_sb, &nowait); iterate_bdevs(fdatawrite_one_bdev, NULL); - iterate_supers(sync_inodes_one_sb, &nowait); - iterate_supers(sync_fs_one_sb, &nowait); + iterate_supers_read(sync_inodes_one_sb, &nowait); + iterate_supers_read(sync_fs_one_sb, &nowait); iterate_bdevs(fdatawrite_one_bdev, NULL); printk("Emergency Sync complete\n"); kfree(work); diff -urNp linux-3.8-rc1-orig/include/linux/fs.h linux-3.8-rc1/include/linux/fs.h --- linux-3.8-rc1-orig/include/linux/fs.h 2012-12-25 10:27:42.198737000 +0900 +++ linux-3.8-rc1/include/linux/fs.h 2012-12-25 11:14:41.312018000 +0900 @@ -2494,7 +2494,8 @@ extern struct super_block *get_super(str extern struct super_block *get_super_thawed(struct block_device *); extern struct super_block *get_active_super(struct block_device *bdev); extern void drop_super(struct super_block *sb); -extern void iterate_supers(void (*)(struct super_block *, void *), void *); +extern void iterate_supers_read(void (*)(struct super_block *, void *), void *); +extern void iterate_supers_write(void (*)(struct super_block *, void *), void *); extern void iterate_supers_type(struct file_system_type *, void (*)(struct super_block *, void *), void *); diff -urNp linux-3.8-rc1-orig/security/selinux/hooks.c linux-3.8-rc1/security/selinux/hooks.c --- linux-3.8-rc1-orig/security/selinux/hooks.c 2012-12-11 12:30:57.000000000 +0900 +++ linux-3.8-rc1/security/selinux/hooks.c 2012-12-25 11:14:41.312018000 +0900 @@ -5720,7 +5720,7 @@ void selinux_complete_init(void) /* Set up any superblocks initialized prior to the policy load. */ printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n"); - iterate_supers(delayed_superblock_init, NULL); + iterate_supers_read(delayed_superblock_init, NULL); } /* SELinux requires early initialization in order to label -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html