]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/super.c
cleanup sync_supers
[net-next-2.6.git] / fs / super.c
index 786fe7d72790ac5646197224fc2af88222dade0a..cb19fffc7681f9d5b96bfa22c8050df0728bcaca 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/blkdev.h>
 #include <linux/quotaops.h>
 #include <linux/namei.h>
-#include <linux/buffer_head.h>         /* for fsync_super() */
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
@@ -38,7 +37,6 @@
 #include <linux/kobject.h>
 #include <linux/mutex.h>
 #include <linux/file.h>
-#include <linux/async.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
@@ -72,7 +70,6 @@ static struct super_block *alloc_super(struct file_system_type *type)
                INIT_HLIST_HEAD(&s->s_anon);
                INIT_LIST_HEAD(&s->s_inodes);
                INIT_LIST_HEAD(&s->s_dentry_lru);
-               INIT_LIST_HEAD(&s->s_async_list);
                init_rwsem(&s->s_umount);
                mutex_init(&s->s_lock);
                lockdep_set_class(&s->s_umount, &type->s_umount_key);
@@ -207,6 +204,34 @@ void deactivate_super(struct super_block *s)
 
 EXPORT_SYMBOL(deactivate_super);
 
+/**
+ *     deactivate_locked_super -       drop an active reference to superblock
+ *     @s: superblock to deactivate
+ *
+ *     Equivalent of up_write(&s->s_umount); deactivate_super(s);, except that
+ *     it does not unlock it until it's all over.  As the result, it's safe to
+ *     use to dispose of new superblock on ->get_sb() failure exits - nobody
+ *     will see the sucker until it's all over.  Equivalent using up_write +
+ *     deactivate_super is safe for that purpose only if superblock is either
+ *     safe to use or has NULL ->s_root when we unlock.
+ */
+void deactivate_locked_super(struct super_block *s)
+{
+       struct file_system_type *fs = s->s_type;
+       if (atomic_dec_and_lock(&s->s_active, &sb_lock)) {
+               s->s_count -= S_BIAS-1;
+               spin_unlock(&sb_lock);
+               vfs_dq_off(s, 0);
+               fs->kill_sb(s);
+               put_filesystem(fs);
+               put_super(s);
+       } else {
+               up_write(&s->s_umount);
+       }
+}
+
+EXPORT_SYMBOL(deactivate_locked_super);
+
 /**
  *     grab_super - acquire an active reference
  *     @s: reference we are trying to make active
@@ -257,38 +282,6 @@ void unlock_super(struct super_block * sb)
 EXPORT_SYMBOL(lock_super);
 EXPORT_SYMBOL(unlock_super);
 
-/*
- * Write out and wait upon all dirty data associated with this
- * superblock.  Filesystem data as well as the underlying block
- * device.  Takes the superblock lock.  Requires a second blkdev
- * flush by the caller to complete the operation.
- */
-void __fsync_super(struct super_block *sb)
-{
-       sync_inodes_sb(sb, 0);
-       vfs_dq_sync(sb);
-       lock_super(sb);
-       if (sb->s_dirt && sb->s_op->write_super)
-               sb->s_op->write_super(sb);
-       unlock_super(sb);
-       if (sb->s_op->sync_fs)
-               sb->s_op->sync_fs(sb, 1);
-       sync_blockdev(sb->s_bdev);
-       sync_inodes_sb(sb, 1);
-}
-
-/*
- * Write out and wait upon all dirty data associated with this
- * superblock.  Filesystem data as well as the underlying block
- * device.  Takes the superblock lock.
- */
-int fsync_super(struct super_block *sb)
-{
-       __fsync_super(sb);
-       return sync_blockdev(sb->s_bdev);
-}
-EXPORT_SYMBOL_GPL(fsync_super);
-
 /**
  *     generic_shutdown_super  -       common helper for ->kill_sb()
  *     @sb: superblock to kill
@@ -310,21 +303,14 @@ void generic_shutdown_super(struct super_block *sb)
 
        if (sb->s_root) {
                shrink_dcache_for_umount(sb);
-               fsync_super(sb);
+               sync_filesystem(sb);
                lock_super(sb);
                sb->s_flags &= ~MS_ACTIVE;
 
-               /*
-                * wait for asynchronous fs operations to finish before going further
-                */
-               async_synchronize_full_domain(&sb->s_async_list);
-
                /* bad name - it should be evict_inodes() */
                invalidate_inodes(sb);
                lock_kernel();
 
-               if (sop->write_super && sb->s_dirt)
-                       sop->write_super(sb);
                if (sop->put_super)
                        sop->put_super(sb);
 
@@ -413,16 +399,14 @@ void drop_super(struct super_block *sb)
 
 EXPORT_SYMBOL(drop_super);
 
-static inline void write_super(struct super_block *sb)
-{
-       lock_super(sb);
-       if (sb->s_root && sb->s_dirt)
-               if (sb->s_op->write_super)
-                       sb->s_op->write_super(sb);
-       unlock_super(sb);
-}
-
-/*
+/**
+ * sync_supers - helper for periodic superblock writeback
+ *
+ * Call the write_super method if present on all dirty superblocks in
+ * the system.  This is for the periodic writeback used by most older
+ * filesystems.  For data integrity superblock writeback use
+ * sync_filesystems() instead.
+ *
  * Note: check the dirty flag before waiting, so we don't
  * hold up the sync while mounting a device. (The newly
  * mounted device won't need syncing.)
@@ -434,12 +418,17 @@ void sync_supers(void)
        spin_lock(&sb_lock);
 restart:
        list_for_each_entry(sb, &super_blocks, s_list) {
-               if (sb->s_dirt) {
+               if (sb->s_op->write_super && sb->s_dirt) {
                        sb->s_count++;
                        spin_unlock(&sb_lock);
+
                        down_read(&sb->s_umount);
-                       write_super(sb);
+                       lock_super(sb);
+                       if (sb->s_root && sb->s_dirt)
+                               sb->s_op->write_super(sb);
+                       unlock_super(sb);
                        up_read(&sb->s_umount);
+
                        spin_lock(&sb_lock);
                        if (__put_super_and_need_restart(sb))
                                goto restart;
@@ -448,60 +437,6 @@ restart:
        spin_unlock(&sb_lock);
 }
 
-/*
- * Call the ->sync_fs super_op against all filesystems which are r/w and
- * which implement it.
- *
- * This operation is careful to avoid the livelock which could easily happen
- * if two or more filesystems are being continuously dirtied.  s_need_sync_fs
- * is used only here.  We set it against all filesystems and then clear it as
- * we sync them.  So redirtied filesystems are skipped.
- *
- * But if process A is currently running sync_filesystems and then process B
- * calls sync_filesystems as well, process B will set all the s_need_sync_fs
- * flags again, which will cause process A to resync everything.  Fix that with
- * a local mutex.
- *
- * (Fabian) Avoid sync_fs with clean fs & wait mode 0
- */
-void sync_filesystems(int wait)
-{
-       struct super_block *sb;
-       static DEFINE_MUTEX(mutex);
-
-       mutex_lock(&mutex);             /* Could be down_interruptible */
-       spin_lock(&sb_lock);
-       list_for_each_entry(sb, &super_blocks, s_list) {
-               if (!sb->s_op->sync_fs)
-                       continue;
-               if (sb->s_flags & MS_RDONLY)
-                       continue;
-               sb->s_need_sync_fs = 1;
-       }
-
-restart:
-       list_for_each_entry(sb, &super_blocks, s_list) {
-               if (!sb->s_need_sync_fs)
-                       continue;
-               sb->s_need_sync_fs = 0;
-               if (sb->s_flags & MS_RDONLY)
-                       continue;       /* hm.  Was remounted r/o meanwhile */
-               sb->s_count++;
-               spin_unlock(&sb_lock);
-               down_read(&sb->s_umount);
-               async_synchronize_full_domain(&sb->s_async_list);
-               if (sb->s_root && (wait || sb->s_dirt))
-                       sb->s_op->sync_fs(sb, wait);
-               up_read(&sb->s_umount);
-               /* restart only when sb is no longer on the list */
-               spin_lock(&sb_lock);
-               if (__put_super_and_need_restart(sb))
-                       goto restart;
-       }
-       spin_unlock(&sb_lock);
-       mutex_unlock(&mutex);
-}
-
 /**
  *     get_super - get the superblock of a device
  *     @bdev: device to get the superblock for
@@ -587,45 +522,6 @@ out:
        return err;
 }
 
-/**
- *     mark_files_ro - mark all files read-only
- *     @sb: superblock in question
- *
- *     All files are marked read-only.  We don't care about pending
- *     delete files so this should be used in 'force' mode only.
- */
-
-static void mark_files_ro(struct super_block *sb)
-{
-       struct file *f;
-
-retry:
-       file_list_lock();
-       list_for_each_entry(f, &sb->s_files, f_u.fu_list) {
-               struct vfsmount *mnt;
-               if (!S_ISREG(f->f_path.dentry->d_inode->i_mode))
-                      continue;
-               if (!file_count(f))
-                       continue;
-               if (!(f->f_mode & FMODE_WRITE))
-                       continue;
-               f->f_mode &= ~FMODE_WRITE;
-               if (file_check_writeable(f) != 0)
-                       continue;
-               file_release_write(f);
-               mnt = mntget(f->f_path.mnt);
-               file_list_unlock();
-               /*
-                * This can sleep, so we can't hold
-                * the file_list_lock() spinlock.
-                */
-               mnt_drop_write(mnt);
-               mntput(mnt);
-               goto retry;
-       }
-       file_list_unlock();
-}
-
 /**
  *     do_remount_sb - asks filesystem to change mount options.
  *     @sb:    superblock in question
@@ -647,7 +543,7 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
        if (flags & MS_RDONLY)
                acct_auto_close(sb);
        shrink_dcache_sb(sb);
-       fsync_super(sb);
+       sync_filesystem(sb);
 
        /* If we are remounting RDONLY and current sb is read/write,
           make sure there are no rw files opened */
@@ -797,8 +693,7 @@ int get_sb_ns(struct file_system_type *fs_type, int flags, void *data,
                sb->s_flags = flags;
                err = fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
                if (err) {
-                       up_write(&sb->s_umount);
-                       deactivate_super(sb);
+                       deactivate_locked_super(sb);
                        return err;
                }
 
@@ -854,8 +749,7 @@ int get_sb_bdev(struct file_system_type *fs_type,
 
        if (s->s_root) {
                if ((flags ^ s->s_flags) & MS_RDONLY) {
-                       up_write(&s->s_umount);
-                       deactivate_super(s);
+                       deactivate_locked_super(s);
                        error = -EBUSY;
                        goto error_bdev;
                }
@@ -870,8 +764,7 @@ int get_sb_bdev(struct file_system_type *fs_type,
                sb_set_blocksize(s, block_size(bdev));
                error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
                if (error) {
-                       up_write(&s->s_umount);
-                       deactivate_super(s);
+                       deactivate_locked_super(s);
                        goto error;
                }
 
@@ -897,7 +790,7 @@ void kill_block_super(struct super_block *sb)
        struct block_device *bdev = sb->s_bdev;
        fmode_t mode = sb->s_mode;
 
-       bdev->bd_super = 0;
+       bdev->bd_super = NULL;
        generic_shutdown_super(sb);
        sync_blockdev(bdev);
        close_bdev_exclusive(bdev, mode);
@@ -921,8 +814,7 @@ int get_sb_nodev(struct file_system_type *fs_type,
 
        error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
        if (error) {
-               up_write(&s->s_umount);
-               deactivate_super(s);
+               deactivate_locked_super(s);
                return error;
        }
        s->s_flags |= MS_ACTIVE;
@@ -952,8 +844,7 @@ int get_sb_single(struct file_system_type *fs_type,
                s->s_flags = flags;
                error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
                if (error) {
-                       up_write(&s->s_umount);
-                       deactivate_super(s);
+                       deactivate_locked_super(s);
                        return error;
                }
                s->s_flags |= MS_ACTIVE;
@@ -1006,8 +897,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
        return mnt;
 out_sb:
        dput(mnt->mnt_root);
-       up_write(&mnt->mnt_sb->s_umount);
-       deactivate_super(mnt->mnt_sb);
+       deactivate_locked_super(mnt->mnt_sb);
 out_free_secdata:
        free_secdata(secdata);
 out_mnt: