genalloc: make it possible to use a custom allocation algorithm
[firefly-linux-kernel-4.4.55.git] / fs / sync.c
index 11e3d1c449018dcf9a95c352746f46d6522c4cb2..14eefeb44636bd1e24240ae09fe0dd046ed013fa 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
  */
 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
@@ -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)
 {
+       int nowait = 0, wait = 1;
+
        wakeup_flusher_threads(0, WB_REASON_SYNC);
-       sync_filesystems(0);
-       sync_filesystems(1);
+       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);
 }
@@ -133,21 +148,19 @@ void emergency_sync(void)
  */
 SYSCALL_DEFINE1(syncfs, int, fd)
 {
-       struct file *file;
+       struct fd f = fdget(fd);
        struct super_block *sb;
        int ret;
-       int fput_needed;
 
-       file = fget_light(fd, &fput_needed);
-       if (!file)
+       if (!f.file)
                return -EBADF;
-       sb = file->f_dentry->d_sb;
+       sb = f.file->f_dentry->d_sb;
 
        down_read(&sb->s_umount);
        ret = sync_filesystem(sb);
        up_read(&sb->s_umount);
 
-       fput_light(file, fput_needed);
+       fdput(f);
        return ret;
 }
 
@@ -186,14 +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;
-       int fput_needed;
 
-       file = fget_light(fd, &fput_needed);
-       if (file) {
-               ret = vfs_fsync(file, datasync);
-               fput_light(file, fput_needed);
+       if (f.file) {
+               ret = vfs_fsync(f.file, datasync);
+               fdput(f);
        }
        return ret;
 }
@@ -276,10 +287,9 @@ SYSCALL_DEFINE(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;
@@ -318,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 = f.file->f_path.dentry->d_inode->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;
@@ -351,7 +361,7 @@ 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;
 }