diff --git a/fs/buffer.c b/fs/buffer.c index ded29b0fdac3..2914d9adfb50 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -560,25 +560,17 @@ repeat: return err; } +static void do_thaw_one(struct super_block *sb, void *unused) +{ + char b[BDEVNAME_SIZE]; + while (sb->s_bdev && !thaw_bdev(sb->s_bdev, sb)) + printk(KERN_WARNING "Emergency Thaw on %s\n", + bdevname(sb->s_bdev, b)); +} + static void do_thaw_all(struct work_struct *work) { - struct super_block *sb, *n; - char b[BDEVNAME_SIZE]; - - spin_lock(&sb_lock); - list_for_each_entry_safe(sb, n, &super_blocks, s_list) { - if (list_empty(&sb->s_instances)) - continue; - sb->s_count++; - spin_unlock(&sb_lock); - down_read(&sb->s_umount); - while (sb->s_bdev && !thaw_bdev(sb->s_bdev, sb)) - printk(KERN_WARNING "Emergency Thaw on %s\n", - bdevname(sb->s_bdev, b)); - up_read(&sb->s_umount); - spin_lock(&sb_lock); - } - spin_unlock(&sb_lock); + iterate_supers(do_thaw_one, NULL); kfree(work); printk(KERN_WARNING "Emergency Thaw complete\n"); } diff --git a/fs/drop_caches.c b/fs/drop_caches.c index 52047cf4177f..83c4f600786a 100644 --- a/fs/drop_caches.c +++ b/fs/drop_caches.c @@ -8,12 +8,11 @@ #include #include #include -#include "internal.h" /* A global variable is a bit ugly, but it keeps the code simple */ int sysctl_drop_caches; -static void drop_pagecache_sb(struct super_block *sb) +static void drop_pagecache_sb(struct super_block *sb, void *unused) { struct inode *inode, *toput_inode = NULL; @@ -34,26 +33,6 @@ static void drop_pagecache_sb(struct super_block *sb) iput(toput_inode); } -static void drop_pagecache(void) -{ - struct super_block *sb, *n; - - spin_lock(&sb_lock); - list_for_each_entry_safe(sb, n, &super_blocks, s_list) { - if (list_empty(&sb->s_instances)) - continue; - sb->s_count++; - spin_unlock(&sb_lock); - down_read(&sb->s_umount); - if (sb->s_root) - drop_pagecache_sb(sb); - up_read(&sb->s_umount); - spin_lock(&sb_lock); - __put_super(sb); - } - spin_unlock(&sb_lock); -} - static void drop_slab(void) { int nr_objects; @@ -69,7 +48,7 @@ int drop_caches_sysctl_handler(ctl_table *table, int write, proc_dointvec_minmax(table, write, buffer, length, ppos); if (write) { if (sysctl_drop_caches & 1) - drop_pagecache(); + iterate_supers(drop_pagecache_sb, NULL); if (sysctl_drop_caches & 2) drop_slab(); } diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 3ce1553ea7eb..ce3dfd066f59 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -18,7 +18,6 @@ #include #include #include -#include "../internal.h" static int check_quotactl_permission(struct super_block *sb, int type, int cmd, qid_t id) @@ -46,36 +45,22 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd, return security_quotactl(cmd, type, id, sb); } +static void quota_sync_one(struct super_block *sb, void *arg) +{ + if (sb->s_qcop && sb->s_qcop->quota_sync) + sb->s_qcop->quota_sync(sb, *(int *)arg, 1); +} + static int quota_sync_all(int type) { - struct super_block *sb, *n; int ret; if (type >= MAXQUOTAS) return -EINVAL; ret = security_quotactl(Q_SYNC, type, 0, NULL); - if (ret) - return ret; - - spin_lock(&sb_lock); - list_for_each_entry_safe(sb, n, &super_blocks, s_list) { - if (list_empty(&sb->s_instances)) - continue; - if (!sb->s_qcop || !sb->s_qcop->quota_sync) - continue; - - sb->s_count++; - spin_unlock(&sb_lock); - down_read(&sb->s_umount); - if (sb->s_root) - sb->s_qcop->quota_sync(sb, type, 1); - up_read(&sb->s_umount); - spin_lock(&sb_lock); - __put_super(sb); - } - spin_unlock(&sb_lock); - - return 0; + if (!ret) + iterate_supers(quota_sync_one, &type); + return ret; } static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id, diff --git a/fs/super.c b/fs/super.c index 95adbb3d8e58..2c3e370c60d9 100644 --- a/fs/super.c +++ b/fs/super.c @@ -391,6 +391,36 @@ void sync_supers(void) spin_unlock(&sb_lock); } +/** + * iterate_supers - 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 + * locked superblock and given argument. + */ +void iterate_supers(void (*f)(struct super_block *, void *), void *arg) +{ + struct super_block *sb, *n; + + spin_lock(&sb_lock); + list_for_each_entry_safe(sb, n, &super_blocks, s_list) { + if (list_empty(&sb->s_instances)) + continue; + sb->s_count++; + spin_unlock(&sb_lock); + + down_read(&sb->s_umount); + if (sb->s_root) + f(sb, arg); + up_read(&sb->s_umount); + + spin_lock(&sb_lock); + __put_super(sb); + } + spin_unlock(&sb_lock); +} + /** * get_super - get the superblock of a device * @bdev: device to get the superblock for diff --git a/fs/sync.c b/fs/sync.c index f3f0a0e1948f..d5369203f8e4 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -77,31 +77,18 @@ int sync_filesystem(struct super_block *sb) } EXPORT_SYMBOL_GPL(sync_filesystem); +static void sync_one_sb(struct super_block *sb, void *arg) +{ + if (!(sb->s_flags & MS_RDONLY) && sb->s_bdi) + __sync_filesystem(sb, *(int *)arg); +} /* * Sync all the data for all the filesystems (called by sys_sync() and * emergency sync) */ static void sync_filesystems(int wait) { - struct super_block *sb, *n; - - spin_lock(&sb_lock); - list_for_each_entry_safe(sb, n, &super_blocks, s_list) { - if (list_empty(&sb->s_instances)) - continue; - sb->s_count++; - spin_unlock(&sb_lock); - - down_read(&sb->s_umount); - if (!(sb->s_flags & MS_RDONLY) && sb->s_root && sb->s_bdi) - __sync_filesystem(sb, wait); - up_read(&sb->s_umount); - - /* restart only when sb is no longer on the list */ - spin_lock(&sb_lock); - __put_super(sb); - } - spin_unlock(&sb_lock); + iterate_supers(sync_one_sb, &wait); } /* diff --git a/include/linux/fs.h b/include/linux/fs.h index 523086714c74..eeb04ba17b63 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2324,6 +2324,7 @@ extern struct super_block *get_super(struct block_device *); extern struct super_block *get_active_super(struct block_device *bdev); extern struct super_block *user_get_super(dev_t); extern void drop_super(struct super_block *sb); +extern void iterate_supers(void (*)(struct super_block *, void *), void *); extern int dcache_dir_open(struct inode *, struct file *); extern int dcache_dir_close(struct inode *, struct file *);