async: Rename _special -> _domain for clarity.
[safe/jmp/linux-2.6] / fs / super.c
index fc8ebed..61dce00 100644 (file)
@@ -15,7 +15,7 @@
  *  Added kerneld support: Jacques Gelinas and Bjorn Ekwall
  *  Added change_root: Werner Almesberger & Hans Lermen, Feb '96
  *  Added options to /proc/mounts:
- *    Torbjörn Lindh (torbjorn.lindh@gopta.se), April 14, 1996.
+ *    Torbjörn Lindh (torbjorn.lindh@gopta.se), April 14, 1996.
  *  Added devfs support: Richard Gooch <rgooch@atnf.csiro.au>, 13-JAN-1998
  *  Heavily rewritten for 'one fs - one tree' dcache architecture. AV, Mar 2000
  */
 #include <linux/idr.h>
 #include <linux/kobject.h>
 #include <linux/mutex.h>
+#include <linux/file.h>
+#include <linux/async.h>
 #include <asm/uaccess.h>
+#include "internal.h"
 
 
-void get_filesystem(struct file_system_type *fs);
-void put_filesystem(struct file_system_type *fs);
-struct file_system_type *get_fs_type(const char *name);
-
 LIST_HEAD(super_blocks);
 DEFINE_SPINLOCK(sb_lock);
 
@@ -67,10 +66,13 @@ static struct super_block *alloc_super(struct file_system_type *type)
                }
                INIT_LIST_HEAD(&s->s_dirty);
                INIT_LIST_HEAD(&s->s_io);
+               INIT_LIST_HEAD(&s->s_more_io);
                INIT_LIST_HEAD(&s->s_files);
                INIT_LIST_HEAD(&s->s_instances);
                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);
@@ -108,6 +110,7 @@ static inline void destroy_super(struct super_block *s)
 {
        security_sb_free(s);
        kfree(s->s_subtype);
+       kfree(s->s_options);
        kfree(s);
 }
 
@@ -117,7 +120,7 @@ static inline void destroy_super(struct super_block *s)
  * Drop a superblock's refcount.  Returns non-zero if the superblock was
  * destroyed.  The caller must hold sb_lock.
  */
-int __put_super(struct super_block *sb)
+static int __put_super(struct super_block *sb)
 {
        int ret = 0;
 
@@ -179,7 +182,7 @@ void deactivate_super(struct super_block *s)
        if (atomic_dec_and_lock(&s->s_active, &sb_lock)) {
                s->s_count -= S_BIAS-1;
                spin_unlock(&sb_lock);
-               DQUOT_OFF(s);
+               DQUOT_OFF(s, 0);
                down_write(&s->s_umount);
                fs->kill_sb(s);
                put_filesystem(fs);
@@ -288,11 +291,18 @@ void generic_shutdown_super(struct super_block *sb)
 {
        const struct super_operations *sop = sb->s_op;
 
+
        if (sb->s_root) {
                shrink_dcache_for_umount(sb);
                fsync_super(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();
@@ -335,21 +345,21 @@ struct super_block *sget(struct file_system_type *type,
                        void *data)
 {
        struct super_block *s = NULL;
-       struct list_head *p;
+       struct super_block *old;
        int err;
 
 retry:
        spin_lock(&sb_lock);
-       if (test) list_for_each(p, &type->fs_supers) {
-               struct super_block *old;
-               old = list_entry(p, struct super_block, s_instances);
-               if (!test(old, data))
-                       continue;
-               if (!grab_super(old))
-                       goto retry;
-               if (s)
-                       destroy_super(s);
-               return old;
+       if (test) {
+               list_for_each_entry(old, &type->fs_supers, s_instances) {
+                       if (!test(old, data))
+                               continue;
+                       if (!grab_super(old))
+                               goto retry;
+                       if (s)
+                               destroy_super(s);
+                       return old;
+               }
        }
        if (!s) {
                spin_unlock(&sb_lock);
@@ -420,7 +430,7 @@ restart:
 }
 
 /*
- * Call the ->sync_fs super_op against all filesytems which are r/w and
+ * 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
@@ -428,7 +438,7 @@ restart:
  * 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_filesytems and then process B
+ * 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.
@@ -460,6 +470,7 @@ restart:
                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);
@@ -533,7 +544,7 @@ rescan:
        return NULL;
 }
 
-asmlinkage long sys_ustat(unsigned dev, struct ustat __user * ubuf)
+SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf)
 {
         struct super_block *s;
         struct ustat tmp;
@@ -558,21 +569,40 @@ out:
 }
 
 /**
- *     mark_files_ro
+ *     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
+ *     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) {
-               if (S_ISREG(f->f_path.dentry->d_inode->i_mode) && file_count(f))
-                       f->f_mode &= ~FMODE_WRITE;
+               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();
 }
@@ -589,6 +619,7 @@ static void mark_files_ro(struct super_block *sb)
 int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
 {
        int retval;
+       int remount_rw;
        
 #ifdef CONFIG_BLOCK
        if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))
@@ -606,7 +637,11 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
                        mark_files_ro(sb);
                else if (!fs_may_remount_ro(sb))
                        return -EBUSY;
+               retval = DQUOT_OFF(sb, 1);
+               if (retval < 0 && retval != -ENOSYS)
+                       return -EBUSY;
        }
+       remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);
 
        if (sb->s_op->remount_fs) {
                lock_super(sb);
@@ -616,6 +651,8 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
                        return retval;
        }
        sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
+       if (remount_rw)
+               DQUOT_ON_REMOUNT(sb);
        return 0;
 }
 
@@ -655,7 +692,7 @@ void emergency_remount(void)
  * filesystems which don't use real block-devices.  -- jrs
  */
 
-static struct idr unnamed_dev_idr;
+static DEFINE_IDA(unnamed_dev_ida);
 static DEFINE_SPINLOCK(unnamed_dev_lock);/* protects the above */
 
 int set_anon_super(struct super_block *s, void *data)
@@ -664,10 +701,10 @@ int set_anon_super(struct super_block *s, void *data)
        int error;
 
  retry:
-       if (idr_pre_get(&unnamed_dev_idr, GFP_ATOMIC) == 0)
+       if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0)
                return -ENOMEM;
        spin_lock(&unnamed_dev_lock);
-       error = idr_get_new(&unnamed_dev_idr, NULL, &dev);
+       error = ida_get_new(&unnamed_dev_ida, &dev);
        spin_unlock(&unnamed_dev_lock);
        if (error == -EAGAIN)
                /* We raced and lost with another CPU. */
@@ -677,7 +714,7 @@ int set_anon_super(struct super_block *s, void *data)
 
        if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {
                spin_lock(&unnamed_dev_lock);
-               idr_remove(&unnamed_dev_idr, dev);
+               ida_remove(&unnamed_dev_ida, dev);
                spin_unlock(&unnamed_dev_lock);
                return -EMFILE;
        }
@@ -693,17 +730,12 @@ void kill_anon_super(struct super_block *sb)
 
        generic_shutdown_super(sb);
        spin_lock(&unnamed_dev_lock);
-       idr_remove(&unnamed_dev_idr, slot);
+       ida_remove(&unnamed_dev_ida, slot);
        spin_unlock(&unnamed_dev_lock);
 }
 
 EXPORT_SYMBOL(kill_anon_super);
 
-void __init unnamed_dev_init(void)
-{
-       idr_init(&unnamed_dev_idr);
-}
-
 void kill_litter_super(struct super_block *sb)
 {
        if (sb->s_root)
@@ -733,9 +765,13 @@ int get_sb_bdev(struct file_system_type *fs_type,
 {
        struct block_device *bdev;
        struct super_block *s;
+       fmode_t mode = FMODE_READ;
        int error = 0;
 
-       bdev = open_bdev_excl(dev_name, flags, fs_type);
+       if (!(flags & MS_RDONLY))
+               mode |= FMODE_WRITE;
+
+       bdev = open_bdev_exclusive(dev_name, mode, fs_type);
        if (IS_ERR(bdev))
                return PTR_ERR(bdev);
 
@@ -758,11 +794,12 @@ int get_sb_bdev(struct file_system_type *fs_type,
                        goto error_bdev;
                }
 
-               close_bdev_excl(bdev);
+               close_bdev_exclusive(bdev, mode);
        } else {
                char b[BDEVNAME_SIZE];
 
                s->s_flags = flags;
+               s->s_mode = mode;
                strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
                sb_set_blocksize(s, block_size(bdev));
                error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
@@ -773,6 +810,7 @@ int get_sb_bdev(struct file_system_type *fs_type,
                }
 
                s->s_flags |= MS_ACTIVE;
+               bdev->bd_super = s;
        }
 
        return simple_set_mnt(mnt, s);
@@ -780,7 +818,7 @@ int get_sb_bdev(struct file_system_type *fs_type,
 error_s:
        error = PTR_ERR(s);
 error_bdev:
-       close_bdev_excl(bdev);
+       close_bdev_exclusive(bdev, mode);
 error:
        return error;
 }
@@ -790,10 +828,12 @@ EXPORT_SYMBOL(get_sb_bdev);
 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;
        generic_shutdown_super(sb);
        sync_blockdev(bdev);
-       close_bdev_excl(bdev);
+       close_bdev_exclusive(bdev, mode);
 }
 
 EXPORT_SYMBOL(kill_block_super);
@@ -871,12 +911,12 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
        if (!mnt)
                goto out;
 
-       if (data) {
+       if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
                secdata = alloc_secdata();
                if (!secdata)
                        goto out_mnt;
 
-               error = security_sb_copy_data(type, data, secdata);
+               error = security_sb_copy_data(data, secdata);
                if (error)
                        goto out_free_secdata;
        }
@@ -886,7 +926,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
                goto out_free_secdata;
        BUG_ON(!mnt->mnt_sb);
 
-       error = security_sb_kern_mount(mnt->mnt_sb, secdata);
+       error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);
        if (error)
                goto out_sb;
 
@@ -946,10 +986,11 @@ do_kern_mount(const char *fstype, int flags, const char *name, void *data)
        put_filesystem(type);
        return mnt;
 }
+EXPORT_SYMBOL_GPL(do_kern_mount);
 
-struct vfsmount *kern_mount(struct file_system_type *type)
+struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
 {
-       return vfs_kern_mount(type, 0, type->name, NULL);
+       return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
 }
 
-EXPORT_SYMBOL(kern_mount);
+EXPORT_SYMBOL_GPL(kern_mount_data);