FSYNC versus FDATASYNC

Marcin Dalecki (dalecki@sub994.sub.uni-goettingen.de)
Tue, 14 Oct 1997 08:10:23 +0100 (MET)


Since there is the intention of changes to the VFS layer, which are going
to make it more Single UNIX conform, I decided, that it may be time to
care about this little issue presented here.

This little patch makes the fdatasync system call an reality. The
behaviour implemented was estimated by some experiments on a Solaris-2.5.4
box. Tought the patch is is little outdated, but despite of this it should
be possible for somebody with the right skills (esp. Richard Henderson)
to pass it over to the current developement kernels.

The idea behind this is to add an boolean flag to the fsync function
from the VFS, which will signal the actual implementation routine to
synchronize the inode data physically or not.
Interrestingly enough this makes the whole kernel text size smaller :-).

The only filesystem I implementid it is ext2. The networked fs's doesn't
need it either... Tough I was carfull to updated all the declarations in
the code for the other ones.

diff -urN linux-orig/drivers/block/floppy.c linux/drivers/block/floppy.c
--- linux-orig/drivers/block/floppy.c Mon Nov 18 19:33:10 1996
+++ linux/drivers/block/floppy.c Sat Dec 28 08:18:48 1996
@@ -3496,7 +3496,7 @@
if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
/* if the file is mounted OR (writable now AND writable at
* open time) Linus: Does this cover all cases? */
- block_fsync(inode,filp);
+ block_fsync(inode, filp, 1);

if (UDRS->fd_ref < 0)
UDRS->fd_ref=0;
diff -urN linux-orig/fs/block_dev.c linux/fs/block_dev.c
--- linux-orig/fs/block_dev.c Mon Oct 28 13:21:41 1996
+++ linux/fs/block_dev.c Sat Dec 28 07:39:39 1996
@@ -315,7 +315,11 @@
return read;
}

-int block_fsync(struct inode *inode, struct file *filp)
+/*
+ * This is the default, file synchronization routine for the
+ * struct file_operations for the case of raw block devices.
+ */
+int block_fsync(struct inode *inode, struct file *filp, int do_sync)
{
return fsync_dev (inode->i_rdev);
}
diff -urN linux-orig/fs/buffer.c linux/fs/buffer.c
--- linux-orig/fs/buffer.c Mon Dec 23 15:31:51 1996
+++ linux/fs/buffer.c Sat Dec 28 08:16:12 1996
@@ -269,12 +269,21 @@
return 0;
}

-int file_fsync (struct inode *inode, struct file *filp)
+/*
+ * This is the default, brute force, file synchronization routine for the
+ * struct file_operations.
+ */
+int file_fsync (struct inode *inode, struct file *filp, int do_sync)
{
return fsync_dev(inode->i_dev);
}

-asmlinkage int sys_fsync(unsigned int fd)
+/*
+ * Synchronize the file in core with the physical disk contents.
+ * If !do_sync, the inode information isn't synchronized (but it is still
+ * updated).
+ */
+static int do_fsync(unsigned int fd, int do_sync)
{
struct file * file;
struct inode * inode;
@@ -283,24 +292,19 @@
return -EBADF;
if (!file->f_op || !file->f_op->fsync)
return -EINVAL;
- if (file->f_op->fsync(inode,file))
+ if (file->f_op->fsync(inode, file, do_sync))
return -EIO;
return 0;
}

-asmlinkage int sys_fdatasync(unsigned int fd)
+asmlinkage int sys_fsync(unsigned int fd)
{
- struct file * file;
- struct inode * inode;
+ return do_fsync(fd, 1);
+}

- if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode))
- return -EBADF;
- if (!file->f_op || !file->f_op->fsync)
- return -EINVAL;
- /* this needs further work, at the moment it is identical to fsync() */
- if (file->f_op->fsync(inode,file))
- return -EIO;
- return 0;
+asmlinkage int sys_fdatasync(unsigned int fd)
+{
+ return do_fsync(fd, 0);
}

void invalidate_buffers(kdev_t dev)
@@ -2201,21 +2205,3 @@
}
}
}
-
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * End:
- */
diff -urN linux-orig/fs/ext/fsync.c linux/fs/ext/fsync.c
--- linux-orig/fs/ext/fsync.c Mon Oct 28 13:29:25 1996
+++ linux/fs/ext/fsync.c Sat Dec 28 16:05:10 1996
@@ -166,7 +166,7 @@
return err;
}

-int ext_sync_file(struct inode * inode, struct file *file)
+int ext_sync_file(struct inode * inode, struct file *file, int do_sync)
{
int wait, err = 0;

diff -urN linux-orig/fs/ext2/fsync.c linux/fs/ext2/fsync.c
--- linux-orig/fs/ext2/fsync.c Mon Nov 18 19:33:13 1996
+++ linux/fs/ext2/fsync.c Sat Dec 28 06:53:10 1996
@@ -263,7 +263,7 @@
return err;
}

-int ext2_sync_file (struct inode * inode, struct file * file)
+int ext2_sync_file (struct inode * inode, struct file * file, int do_sync)
{
int wait, err = 0;

@@ -290,6 +290,6 @@
wait);
}
skip:
- err |= ext2_sync_inode (inode);
+ err |= ext2_update_inode (inode, do_sync);
return (err < 0) ? -EIO : 0;
}
diff -urN linux-orig/fs/ext2/inode.c linux/fs/ext2/inode.c
--- linux-orig/fs/ext2/inode.c Mon Nov 18 19:33:13 1996
+++ linux/fs/ext2/inode.c Sat Dec 28 06:40:28 1996
@@ -29,8 +29,6 @@
#include <linux/locks.h>
#include <linux/mm.h>

-static int ext2_update_inode(struct inode * inode, int do_sync);
-
void ext2_put_inode (struct inode * inode)
{
ext2_discard_prealloc (inode);
@@ -597,7 +595,7 @@
inode->i_flags |= S_IMMUTABLE;
}

-static int ext2_update_inode(struct inode * inode, int do_sync)
+int ext2_update_inode(struct inode * inode, int do_sync)
{
struct buffer_head * bh;
struct ext2_inode * raw_inode;
@@ -686,8 +684,4 @@
ext2_update_inode (inode, 0);
}

-int ext2_sync_inode (struct inode *inode)
-{
- return ext2_update_inode (inode, 1);
-}

diff -urN linux-orig/fs/minix/fsync.c linux/fs/minix/fsync.c
--- linux-orig/fs/minix/fsync.c Mon Oct 28 13:29:26 1996
+++ linux/fs/minix/fsync.c Sat Dec 28 15:24:58 1996
@@ -330,7 +330,7 @@
/*
* The function which is called for file synchronization.
*/
-int minix_sync_file(struct inode * inode, struct file * file)
+int minix_sync_file(struct inode * inode, struct file * file, int do_sync)
{
if (INODE_VERSION(inode) == MINIX_V1)
return V1_minix_sync_file(inode, file);
diff -urN linux-orig/fs/nfs/file.c linux/fs/nfs/file.c
--- linux-orig/fs/nfs/file.c Mon Oct 28 13:29:26 1996
+++ linux/fs/nfs/file.c Sat Dec 28 16:09:51 1996
@@ -32,7 +32,7 @@
static int nfs_file_mmap(struct inode *, struct file *, struct vm_area_struct *);
static long nfs_file_read(struct inode *, struct file *, char *, unsigned long);
static long nfs_file_write(struct inode *, struct file *, const char *, unsigned long);
-static int nfs_fsync(struct inode *, struct file *);
+static int nfs_fsync(struct inode *, struct file *, int);

static struct file_operations nfs_file_operations = {
NULL, /* lseek - default */
@@ -100,7 +100,7 @@
return generic_file_mmap(inode, file, vma);
}

-static int nfs_fsync(struct inode *inode, struct file *file)
+static int nfs_fsync(struct inode *inode, struct file *file, int do_sync)
{
return 0;
}
diff -urN linux-orig/fs/smbfs/file.c linux/fs/smbfs/file.c
--- linux-orig/fs/smbfs/file.c Sat Dec 14 17:35:55 1996
+++ linux/fs/smbfs/file.c Sat Dec 28 16:15:51 1996
@@ -24,7 +24,7 @@
}

static int
-smb_fsync(struct inode *inode, struct file *file)
+smb_fsync(struct inode *inode, struct file *file, int do_sync)
{
return 0;
}
diff -urN linux-orig/fs/sysv/fsync.c linux/fs/sysv/fsync.c
--- linux-orig/fs/sysv/fsync.c Sun Nov 26 18:23:10 1995
+++ linux/fs/sysv/fsync.c Sat Dec 28 16:13:39 1996
@@ -178,7 +178,7 @@
return err;
}

-int sysv_sync_file(struct inode * inode, struct file * file)
+int sysv_sync_file(struct inode * inode, struct file * file, int do_sync)
{
int wait, err = 0;

diff -urN linux-orig/fs/xiafs/fsync.c linux/fs/xiafs/fsync.c
--- linux-orig/fs/xiafs/fsync.c Mon Oct 28 13:29:28 1996
+++ linux/fs/xiafs/fsync.c Sat Dec 28 16:11:16 1996
@@ -141,7 +141,7 @@
return err;
}

-int xiafs_sync_file(struct inode * inode, struct file * file)
+int xiafs_sync_file(struct inode * inode, struct file * file, int do_sync)
{
int wait, err = 0;

diff -urN linux-orig/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- linux-orig/include/linux/ext2_fs.h Fri Oct 11 06:57:17 1996
+++ linux/include/linux/ext2_fs.h Sat Dec 28 07:45:49 1996
@@ -458,7 +458,7 @@
extern int ext2_write (struct inode *, struct file *, char *, int);

/* fsync.c */
-extern int ext2_sync_file (struct inode *, struct file *);
+extern int ext2_sync_file (struct inode *, struct file *, int);

/* ialloc.c */
extern struct inode * ext2_new_inode (const struct inode *, int, int *);
@@ -474,10 +474,15 @@

extern int ext2_getcluster (struct inode * inode, long block);
extern void ext2_read_inode (struct inode *);
-extern void ext2_write_inode (struct inode *);
+extern void ext2_write_inode (struct inode * inode);
+extern int ext2_update_inode(struct inode * inode, int do_sync);
extern void ext2_put_inode (struct inode *);
-extern int ext2_sync_inode (struct inode *);
extern void ext2_discard_prealloc (struct inode *);
+
+static inline int ext2_sync_inode (struct inode *inode)
+{
+ return ext2_update_inode (inode, 1);
+}

/* ioctl.c */
extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
diff -urN linux-orig/include/linux/ext_fs.h linux/include/linux/ext_fs.h
--- linux-orig/include/linux/ext_fs.h Wed Jul 3 10:53:06 1996
+++ linux/include/linux/ext_fs.h Sat Dec 28 15:48:34 1996
@@ -97,7 +97,7 @@
extern void ext_put_inode(struct inode *);
extern void ext_statfs(struct super_block *, struct statfs *, int);
extern int ext_sync_inode(struct inode *);
-extern int ext_sync_file(struct inode *, struct file *);
+extern int ext_sync_file(struct inode *, struct file *, int);

extern int ext_lseek(struct inode *, struct file *, off_t, int);
extern int ext_read(struct inode *, struct file *, char *, int);
diff -urN linux-orig/include/linux/fs.h linux/include/linux/fs.h
--- linux-orig/include/linux/fs.h Mon Dec 23 15:52:52 1996
+++ linux/include/linux/fs.h Sat Dec 28 15:51:50 1996
@@ -472,7 +472,7 @@
int (*mmap) (struct inode *, struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
void (*release) (struct inode *, struct file *);
- int (*fsync) (struct inode *, struct file *);
+ int (*fsync) (struct inode *, struct file *, int);
int (*fasync) (struct inode *, struct file *, int);
int (*check_media_change) (kdev_t dev);
int (*revalidate) (kdev_t dev);
@@ -686,8 +686,8 @@
extern long char_write(struct inode *, struct file *, const char *, unsigned long);
extern long block_write(struct inode *, struct file *, const char *, unsigned long);

-extern int block_fsync(struct inode *, struct file *);
-extern int file_fsync(struct inode *, struct file *);
+extern int block_fsync(struct inode *, struct file *, int);
+extern int file_fsync(struct inode *, struct file *, int);

extern void dcache_add(struct inode *, const char *, int, unsigned long);
extern int dcache_lookup(struct inode *, const char *, int, unsigned long *);
diff -urN linux-orig/include/linux/minix_fs.h linux/include/linux/minix_fs.h
--- linux-orig/include/linux/minix_fs.h Wed Jul 3 10:53:06 1996
+++ linux/include/linux/minix_fs.h Sat Dec 28 14:50:16 1996
@@ -124,7 +124,7 @@
extern void minix_put_inode(struct inode *);
extern void minix_statfs(struct super_block *, struct statfs *, int);
extern int minix_sync_inode(struct inode *);
-extern int minix_sync_file(struct inode *, struct file *);
+extern int minix_sync_file(struct inode *, struct file *, int);

extern struct inode_operations minix_file_inode_operations;
extern struct inode_operations minix_dir_inode_operations;
diff -urN linux-orig/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h
--- linux-orig/include/linux/sysv_fs.h Mon Dec 23 16:00:40 1996
+++ linux/include/linux/sysv_fs.h Sat Dec 28 16:12:05 1996
@@ -398,7 +398,7 @@
extern void sysv_put_inode(struct inode *);
extern void sysv_statfs(struct super_block *, struct statfs *, int);
extern int sysv_sync_inode(struct inode *);
-extern int sysv_sync_file(struct inode *, struct file *);
+extern int sysv_sync_file(struct inode *, struct file *, int);
extern int sysv_mmap(struct inode *, struct file *, struct vm_area_struct *);

extern struct inode_operations sysv_file_inode_operations;
diff -urN linux-orig/include/linux/xia_fs.h linux/include/linux/xia_fs.h
--- linux-orig/include/linux/xia_fs.h Wed Jul 3 10:53:06 1996
+++ linux/include/linux/xia_fs.h Sat Dec 28 15:46:24 1996
@@ -102,7 +102,7 @@
extern void xiafs_put_inode(struct inode *);
extern void xiafs_statfs(struct super_block *, struct statfs *, int);
extern int xiafs_sync_inode(struct inode *);
-extern int xiafs_sync_file(struct inode *, struct file *);
+extern int xiafs_sync_file(struct inode *, struct file *, int);

extern struct inode_operations xiafs_file_inode_operations;
extern struct inode_operations xiafs_dir_inode_operations;
diff -urN linux-orig/mm/filemap.c linux/mm/filemap.c
--- linux-orig/mm/filemap.c Mon Dec 23 15:31:55 1996
+++ linux/mm/filemap.c Sat Dec 28 07:26:44 1996
@@ -1212,7 +1212,7 @@
if (error)
return error;
if (flags & MS_SYNC)
- return file_fsync(vma->vm_inode, NULL);
+ return file_fsync(vma->vm_inode, NULL, 1);
return 0;
}
return 0;