introduce sys_syncfs to sync a single file system
authorSage Weil <sage@newdream.net>
Thu, 10 Mar 2011 19:31:30 +0000 (11:31 -0800)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 21 Mar 2011 04:40:29 +0000 (00:40 -0400)
It is frequently useful to sync a single file system, instead of all
mounted file systems via sync(2):

 - On machines with many mounts, it is not at all uncommon for some of
   them to hang (e.g. unresponsive NFS server).  sync(2) will get stuck on
   those and may never get to the one you do care about (e.g., /).
 - Some applications write lots of data to the file system and then
   want to make sure it is flushed to disk.  Calling fsync(2) on each
   file introduces unnecessary ordering constraints that result in a large
   amount of sub-optimal writeback/flush/commit behavior by the file
   system.

There are currently two ways (that I know of) to sync a single super_block:

 - BLKFLSBUF ioctl on the block device: That also invalidates the bdev
   mapping, which isn't usually desirable, and doesn't work for non-block
   file systems.
 - 'mount -o remount,rw' will call sync_filesystem as an artifact of the
   current implemention.  Relying on this little-known side effect for
   something like data safety sounds foolish.

Both of these approaches require root privileges, which some applications
do not have (nor should they need?) given that sync(2) is an unprivileged
operation.

This patch introduces a new system call syncfs(2) that takes an fd and
syncs only the file system it references.  Maybe someday we can

 $ sync /some/path

and not get

 sync: ignoring all arguments

The syscall is motivated by comments by Al and Christoph at the last LSF.
syncfs(2) seems like an appropriate name given statfs(2).

A similar ioctl was also proposed a while back, see
http://marc.info/?l=linux-fsdevel&m=127970513829285&w=2

Signed-off-by: Sage Weil <sage@newdream.net>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
arch/x86/ia32/ia32entry.S
arch/x86/include/asm/unistd_32.h
arch/x86/include/asm/unistd_64.h
arch/x86/kernel/syscall_table_32.S
fs/sync.c
include/asm-generic/unistd.h
include/linux/syscalls.h

index 430312ba6e3f3b0b9cee93427feb69b18c9a5ab2..849a9d23c71d5c11080d92edbb705343879aa15e 100644 (file)
@@ -847,4 +847,5 @@ ia32_sys_call_table:
        .quad sys_name_to_handle_at
        .quad compat_sys_open_by_handle_at
        .quad compat_sys_clock_adjtime
+       .quad sys_syncfs
 ia32_syscall_end:
index ffaf183c619a21f30c24384f8aa9e106e496dfa2..a755ef5e5977540cd52b63e85374e8c4d03e7b8c 100644 (file)
 #define __NR_name_to_handle_at 341
 #define __NR_open_by_handle_at  342
 #define __NR_clock_adjtime     343
+#define __NR_syncfs             344
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 344
+#define NR_syscalls 345
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index 5466bea670e7e3c14774c998fb0f90d089cb3d8a..160fa76bd5786e680da555ad96d8101a71edc99e 100644 (file)
@@ -675,6 +675,8 @@ __SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at)
 __SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at)
 #define __NR_clock_adjtime                     305
 __SYSCALL(__NR_clock_adjtime, sys_clock_adjtime)
+#define __NR_syncfs                             306
+__SYSCALL(__NR_syncfs, sys_syncfs)
 
 #ifndef __NO_STUBS
 #define __ARCH_WANT_OLD_READDIR
index 5f181742e8f91c9510fbac2e0fd0ec7e12daf34d..abce34d5c79de0ce7e6275640a3470ccca9e1805 100644 (file)
@@ -343,3 +343,4 @@ ENTRY(sys_call_table)
        .long sys_name_to_handle_at
        .long sys_open_by_handle_at
        .long sys_clock_adjtime
+       .long sys_syncfs
index ba76b9623e7e809f6b3c5e6223020836069dc4ab..92ca208777d562e64bfc769dc41a326f7c3da84e 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -7,6 +7,7 @@
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/namei.h>
 #include <linux/sched.h>
 #include <linux/writeback.h>
 #include <linux/syscalls.h>
@@ -128,6 +129,29 @@ void emergency_sync(void)
        }
 }
 
+/*
+ * sync a single super
+ */
+SYSCALL_DEFINE1(syncfs, int, fd)
+{
+       struct file *file;
+       struct super_block *sb;
+       int ret;
+       int fput_needed;
+
+       file = fget_light(fd, &fput_needed);
+       if (!file)
+               return -EBADF;
+       sb = file->f_dentry->d_sb;
+
+       down_read(&sb->s_umount);
+       ret = sync_filesystem(sb);
+       up_read(&sb->s_umount);
+
+       fput_light(file, fput_needed);
+       return ret;
+}
+
 /**
  * vfs_fsync_range - helper to sync a range of data & metadata to disk
  * @file:              file to sync
index d94f447c667a6ea61857e7ba968e7cb09b40fac9..176b825add52691cb5abb2b52780dd75923d3377 100644 (file)
@@ -652,9 +652,11 @@ __SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at)
 __SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at)
 #define __NR_clock_adjtime 266
 __SYSCALL(__NR_clock_adjtime, sys_clock_adjtime)
+#define __NR_syncfs 264
+__SYSCALL(__NR_syncfs, sys_syncfs)
 
 #undef __NR_syscalls
-#define __NR_syscalls 267
+#define __NR_syscalls 268
 
 /*
  * All syscalls below here should go away really,
index 1f5c18e6f4f17bedfbd38e64da3cc112d1cb90bb..83ecc1749ef6153581d295706d6c4768c11931e0 100644 (file)
@@ -825,6 +825,7 @@ asmlinkage long sys_fanotify_init(unsigned int flags, unsigned int event_f_flags
 asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags,
                                  u64 mask, int fd,
                                  const char  __user *pathname);
+asmlinkage long sys_syncfs(int fd);
 
 int kernel_execve(const char *filename, const char *const argv[], const char *const envp[]);