video: tegra: dc: Add quick for Vizio P series
[linux-3.10.git] / fs / sync.c
index 412dc89..905f3f6 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -6,14 +6,14 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
-#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/namei.h>
 #include <linux/sched.h>
 #include <linux/writeback.h>
 #include <linux/syscalls.h>
 #include <linux/linkage.h>
 #include <linux/pagemap.h>
 #include <linux/quotaops.h>
-#include <linux/buffer_head.h>
 #include <linux/backing-dev.h>
 #include "internal.h"
 
  */
 static int __sync_filesystem(struct super_block *sb, int wait)
 {
-       /*
-        * This should be safe, as we require bdi backing to actually
-        * write out data in the first place
-        */
-       if (sb->s_bdi == &noop_backing_dev_info)
-               return 0;
-
-       if (sb->s_qcop && sb->s_qcop->quota_sync)
-               sb->s_qcop->quota_sync(sb, -1, wait);
-
        if (wait)
                sync_inodes_sb(sb);
        else
-               writeback_inodes_sb(sb);
+               writeback_inodes_sb(sb, WB_REASON_SYNC);
 
        if (sb->s_op->sync_fs)
                sb->s_op->sync_fs(sb, wait);
@@ -77,29 +67,48 @@ int sync_filesystem(struct super_block *sb)
 }
 EXPORT_SYMBOL_GPL(sync_filesystem);
 
-static void sync_one_sb(struct super_block *sb, void *arg)
+static void sync_inodes_one_sb(struct super_block *sb, void *arg)
 {
        if (!(sb->s_flags & MS_RDONLY))
-               __sync_filesystem(sb, *(int *)arg);
+               sync_inodes_sb(sb);
 }
-/*
- * Sync all the data for all the filesystems (called by sys_sync() and
- * emergency sync)
- */
-static void sync_filesystems(int wait)
+
+static void sync_fs_one_sb(struct super_block *sb, void *arg)
 {
-       iterate_supers(sync_one_sb, &wait);
+       if (!(sb->s_flags & MS_RDONLY) && sb->s_op->sync_fs)
+               sb->s_op->sync_fs(sb, *(int *)arg);
+}
+
+static void fdatawrite_one_bdev(struct block_device *bdev, void *arg)
+{
+       filemap_fdatawrite(bdev->bd_inode->i_mapping);
+}
+
+static void fdatawait_one_bdev(struct block_device *bdev, void *arg)
+{
+       filemap_fdatawait(bdev->bd_inode->i_mapping);
 }
 
 /*
- * sync everything.  Start out by waking pdflush, because that writes back
- * all queues in parallel.
+ * Sync everything. We start by waking flusher threads so that most of
+ * writeback runs on all devices in parallel. Then we sync all inodes reliably
+ * which effectively also waits for all flusher threads to finish doing
+ * writeback. At this point all data is on disk so metadata should be stable
+ * and we tell filesystems to sync their metadata via ->sync_fs() calls.
+ * Finally, we writeout all block devices because some filesystems (e.g. ext2)
+ * just write metadata (such as inodes or bitmaps) to block device page cache
+ * and do not sync it on their own in ->sync_fs().
  */
 SYSCALL_DEFINE0(sync)
 {
-       wakeup_flusher_threads(0);
-       sync_filesystems(0);
-       sync_filesystems(1);
+       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_bdevs(fdatawrite_one_bdev, NULL);
+       iterate_bdevs(fdatawait_one_bdev, NULL);
        if (unlikely(laptop_mode))
                laptop_sync_completion();
        return 0;
@@ -107,12 +116,18 @@ SYSCALL_DEFINE0(sync)
 
 static void do_sync_work(struct work_struct *work)
 {
+       int nowait = 0;
+
        /*
         * Sync twice to reduce the possibility we skipped some inodes / pages
         * because they were temporarily locked
         */
-       sync_filesystems(0);
-       sync_filesystems(0);
+       iterate_supers(sync_inodes_one_sb, &nowait);
+       iterate_supers(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_bdevs(fdatawrite_one_bdev, NULL);
        printk("Emergency Sync complete\n");
        kfree(work);
 }
@@ -128,6 +143,27 @@ void emergency_sync(void)
        }
 }
 
+/*
+ * sync a single super
+ */
+SYSCALL_DEFINE1(syncfs, int, fd)
+{
+       struct fd f = fdget(fd);
+       struct super_block *sb;
+       int ret;
+
+       if (!f.file)
+               return -EBADF;
+       sb = f.file->f_dentry->d_sb;
+
+       down_read(&sb->s_umount);
+       ret = sync_filesystem(sb);
+       up_read(&sb->s_umount);
+
+       fdput(f);
+       return ret;
+}
+
 /**
  * vfs_fsync_range - helper to sync a range of data & metadata to disk
  * @file:              file to sync
@@ -141,28 +177,9 @@ void emergency_sync(void)
  */
 int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync)
 {
-       struct address_space *mapping = file->f_mapping;
-       int err, ret;
-
-       if (!file->f_op || !file->f_op->fsync) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       ret = filemap_write_and_wait_range(mapping, start, end);
-
-       /*
-        * We need to protect against concurrent writers, which could cause
-        * livelocks in fsync_buffers_list().
-        */
-       mutex_lock(&mapping->host->i_mutex);
-       err = file->f_op->fsync(file, datasync);
-       if (!ret)
-               ret = err;
-       mutex_unlock(&mapping->host->i_mutex);
-
-out:
-       return ret;
+       if (!file->f_op || !file->f_op->fsync)
+               return -EINVAL;
+       return file->f_op->fsync(file, start, end, datasync);
 }
 EXPORT_SYMBOL(vfs_fsync_range);
 
@@ -182,13 +199,12 @@ EXPORT_SYMBOL(vfs_fsync);
 
 static int do_fsync(unsigned int fd, int datasync)
 {
-       struct file *file;
+       struct fd f = fdget(fd);
        int ret = -EBADF;
 
-       file = fget(fd);
-       if (file) {
-               ret = vfs_fsync(file, datasync);
-               fput(file);
+       if (f.file) {
+               ret = vfs_fsync(f.file, datasync);
+               fdput(f);
        }
        return ret;
 }
@@ -267,14 +283,13 @@ EXPORT_SYMBOL(generic_write_sync);
  * already-instantiated disk blocks, there are no guarantees here that the data
  * will be available after a crash.
  */
-SYSCALL_DEFINE(sync_file_range)(int fd, loff_t offset, loff_t nbytes,
-                               unsigned int flags)
+SYSCALL_DEFINE4(sync_file_range, int, fd, loff_t, offset, loff_t, nbytes,
+                               unsigned int, flags)
 {
        int ret;
-       struct file *file;
+       struct fd f;
        struct address_space *mapping;
        loff_t endbyte;                 /* inclusive */
-       int fput_needed;
        umode_t i_mode;
 
        ret = -EINVAL;
@@ -313,17 +328,17 @@ SYSCALL_DEFINE(sync_file_range)(int fd, loff_t offset, loff_t nbytes,
                endbyte--;              /* inclusive */
 
        ret = -EBADF;
-       file = fget_light(fd, &fput_needed);
-       if (!file)
+       f = fdget(fd);
+       if (!f.file)
                goto out;
 
-       i_mode = file->f_path.dentry->d_inode->i_mode;
+       i_mode = file_inode(f.file)->i_mode;
        ret = -ESPIPE;
        if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) &&
                        !S_ISLNK(i_mode))
                goto out_put;
 
-       mapping = file->f_mapping;
+       mapping = f.file->f_mapping;
        if (!mapping) {
                ret = -EINVAL;
                goto out_put;
@@ -346,33 +361,15 @@ SYSCALL_DEFINE(sync_file_range)(int fd, loff_t offset, loff_t nbytes,
                ret = filemap_fdatawait_range(mapping, offset, endbyte);
 
 out_put:
-       fput_light(file, fput_needed);
+       fdput(f);
 out:
        return ret;
 }
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_sync_file_range(long fd, loff_t offset, loff_t nbytes,
-                                   long flags)
-{
-       return SYSC_sync_file_range((int) fd, offset, nbytes,
-                                   (unsigned int) flags);
-}
-SYSCALL_ALIAS(sys_sync_file_range, SyS_sync_file_range);
-#endif
 
 /* It would be nice if people remember that not all the world's an i386
    when they introduce new system calls */
-SYSCALL_DEFINE(sync_file_range2)(int fd, unsigned int flags,
-                                loff_t offset, loff_t nbytes)
+SYSCALL_DEFINE4(sync_file_range2, int, fd, unsigned int, flags,
+                                loff_t, offset, loff_t, nbytes)
 {
        return sys_sync_file_range(fd, offset, nbytes, flags);
 }
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_sync_file_range2(long fd, long flags,
-                                    loff_t offset, loff_t nbytes)
-{
-       return SYSC_sync_file_range2((int) fd, (unsigned int) flags,
-                                    offset, nbytes);
-}
-SYSCALL_ALIAS(sys_sync_file_range2, SyS_sync_file_range2);
-#endif