fs: push i_mutex and filemap_write_and_wait down into ->fsync() handlers
authorJosef Bacik <josef@redhat.com>
Sun, 17 Jul 2011 00:44:56 +0000 (20:44 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 21 Jul 2011 00:47:59 +0000 (20:47 -0400)
Btrfs needs to be able to control how filemap_write_and_wait_range() is called
in fsync to make it less of a painful operation, so push down taking i_mutex and
the calling of filemap_write_and_wait() down into the ->fsync() handlers.  Some
file systems can drop taking the i_mutex altogether it seems, like ext3 and
ocfs2.  For correctness sake I just pushed everything down in all cases to make
sure that we keep the current behavior the same for everybody, and then each
individual fs maintainer can make up their mind about what to do from there.
Thanks,

Acked-by: Jan Kara <jack@suse.cz>
Signed-off-by: Josef Bacik <josef@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
71 files changed:
Documentation/filesystems/Locking
Documentation/filesystems/porting
Documentation/filesystems/vfs.txt
arch/powerpc/platforms/cell/spufs/file.c
drivers/char/ps3flash.c
drivers/mtd/ubi/cdev.c
drivers/staging/pohmelfs/inode.c
drivers/usb/gadget/printer.c
drivers/video/fb_defio.c
fs/9p/v9fs_vfs.h
fs/9p/vfs_file.c
fs/affs/affs.h
fs/affs/file.c
fs/afs/internal.h
fs/afs/write.c
fs/bad_inode.c
fs/block_dev.c
fs/btrfs/ctree.h
fs/btrfs/file.c
fs/ceph/caps.c
fs/ceph/dir.c
fs/ceph/super.h
fs/cifs/cifsfs.h
fs/cifs/file.c
fs/coda/coda_int.h
fs/coda/file.c
fs/ecryptfs/file.c
fs/exofs/file.c
fs/ext2/ext2.h
fs/ext2/file.c
fs/ext3/fsync.c
fs/ext4/ext4.h
fs/ext4/fsync.c
fs/fat/fat.h
fs/fat/file.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/gfs2/file.c
fs/hfs/inode.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/inode.c
fs/hostfs/hostfs_kern.c
fs/hpfs/file.c
fs/hpfs/hpfs_fn.h
fs/hppfs/hppfs.c
fs/jffs2/file.c
fs/jffs2/os-linux.h
fs/jfs/file.c
fs/jfs/jfs_inode.h
fs/libfs.c
fs/logfs/file.c
fs/logfs/logfs.h
fs/ncpfs/file.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nilfs2/file.c
fs/nilfs2/nilfs.h
fs/ntfs/dir.c
fs/ntfs/file.c
fs/ocfs2/file.c
fs/reiserfs/dir.c
fs/reiserfs/file.c
fs/sync.c
fs/ubifs/file.c
fs/ubifs/ubifs.h
fs/xfs/linux-2.6/xfs_file.c
include/linux/ext3_fs.h
include/linux/fb.h
include/linux/fs.h
ipc/shm.c

index 9b6ed7c9f34f4b5cc4424e4413e2d57c7f3f6c03..ca7e25292542a6934f4d3210846167e4343228c4 100644 (file)
@@ -412,7 +412,7 @@ prototypes:
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *);
        int (*release) (struct inode *, struct file *);
-       int (*fsync) (struct file *, int datasync);
+       int (*fsync) (struct file *, loff_t start, loff_t end, int datasync);
        int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
@@ -438,9 +438,7 @@ prototypes:
 
 locking rules:
        All may block except for ->setlease.
-       No VFS locks held on entry except for ->fsync and ->setlease.
-
-->fsync() has i_mutex on inode.
+       No VFS locks held on entry except for ->setlease.
 
 ->setlease has the file_list_lock held and must not sleep.
 
index 6b96773e27cb2ef54bd736309e46e25b04aec0db..7f8861d341ea83321092db0b94e79953c795b5e1 100644 (file)
@@ -421,3 +421,10 @@ data and there is a virtual hole at the end of the file.  So if the provided
 offset is less than i_size and SEEK_DATA is specified, return the same offset.
 If the above is true for the offset and you are given SEEK_HOLE, return the end
 of the file.  If the offset is i_size or greater return -ENXIO in either case.
+
+[mandatory]
+       If you have your own ->fsync() you must make sure to call
+filemap_write_and_wait_range() so that all dirty pages are synced out properly.
+You must also keep in mind that ->fsync() is not called with i_mutex held
+anymore, so if you require i_mutex locking you must make sure to take it and
+release it yourself.
index 6bf85b78cfea8d00c70df6c76e3bde11b88b98c7..eff6617c9a0f6fe7c3824926c8a79b26ccd5b290 100644 (file)
@@ -777,7 +777,7 @@ struct file_operations {
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *);
        int (*release) (struct inode *, struct file *);
-       int (*fsync) (struct file *, int datasync);
+       int (*fsync) (struct file *, loff_t, loff_t, int datasync);
        int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
index 3c7c3f82d8424d67e24587cd40d2ef60f0647772..fb59c46e9e9eea5946ca12aac0cfb325b1c774ca 100644 (file)
@@ -1850,9 +1850,16 @@ out:
        return ret;
 }
 
-static int spufs_mfc_fsync(struct file *file, int datasync)
+static int spufs_mfc_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
-       return spufs_mfc_flush(file, NULL);
+       struct inode *inode = file->f_path.dentry->d_inode;
+       int err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (!err) {
+               mutex_lock(&inode->i_mutex);
+               err = spufs_mfc_flush(file, NULL);
+               mutex_unlock(&inode->i_mutex);
+       }
+       return err;
 }
 
 static int spufs_mfc_fasync(int fd, struct file *file, int on)
index 5a06787e5be350cd425340c9b2fda18f07bb118f..d0c57c2e29094eb6caba946789295893d4befdbc 100644 (file)
@@ -309,9 +309,14 @@ static int ps3flash_flush(struct file *file, fl_owner_t id)
        return ps3flash_writeback(ps3flash_dev);
 }
 
-static int ps3flash_fsync(struct file *file, int datasync)
+static int ps3flash_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
-       return ps3flash_writeback(ps3flash_dev);
+       struct inode *inode = file->f_path.dentry->d_inode;
+       int err;
+       mutex_lock(&inode->i_mutex);
+       err = ps3flash_writeback(ps3flash_dev);
+       mutex_unlock(&inode->i_mutex);
+       return err;
 }
 
 static irqreturn_t ps3flash_interrupt(int irq, void *data)
index 191f3bb3c41a7440a6cf831655c6431f31ec55f6..3320a50ba4f0c81f75e48154bd4202f50ead4fad 100644 (file)
@@ -189,12 +189,16 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
        return new_offset;
 }
 
-static int vol_cdev_fsync(struct file *file, int datasync)
+static int vol_cdev_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct ubi_volume_desc *desc = file->private_data;
        struct ubi_device *ubi = desc->vol->ubi;
-
-       return ubi_sync(ubi->ubi_num);
+       struct inode *inode = file->f_path.dentry->d_inode;
+       int err;
+       mutex_lock(&inode->i_mutex);
+       err = ubi_sync(ubi->ubi_num);
+       mutex_unlock(&inode->i_mutex);
+       return err;
 }
 
 
index c0f0ac7c1cdb8f8cb6dd1aae58a8318b1ae4fb87..f3c6060c96b844d37ebdcc8caf59021081672057 100644 (file)
@@ -887,11 +887,16 @@ static struct inode *pohmelfs_alloc_inode(struct super_block *sb)
 /*
  * We want fsync() to work on POHMELFS.
  */
-static int pohmelfs_fsync(struct file *file, int datasync)
+static int pohmelfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
-
-       return sync_inode_metadata(inode, 1);
+       int err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (!err) {
+               mutex_lock(&inode->i_mutex);
+               err = sync_inode_metadata(inode, 1);
+               mutex_unlock(&inode->i_mutex);
+       }
+       return err;
 }
 
 ssize_t pohmelfs_write(struct file *file, const char __user *buf,
index 271ef94668e719867d12c00a9ce9c1681c825f23..978e6a101bf2ff45811af75acff3e6265f951734 100644 (file)
@@ -795,12 +795,14 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 }
 
 static int
-printer_fsync(struct file *fd, int datasync)
+printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync)
 {
        struct printer_dev      *dev = fd->private_data;
+       struct inode *inode = fd->f_path.dentry->d_inode;
        unsigned long           flags;
        int                     tx_list_empty;
 
+       mutex_lock(&inode->i_mutex);
        spin_lock_irqsave(&dev->lock, flags);
        tx_list_empty = (likely(list_empty(&dev->tx_reqs)));
        spin_unlock_irqrestore(&dev->lock, flags);
@@ -810,6 +812,7 @@ printer_fsync(struct file *fd, int datasync)
                wait_event_interruptible(dev->tx_flush_wait,
                                (likely(list_empty(&dev->tx_reqs_active))));
        }
+       mutex_unlock(&inode->i_mutex);
 
        return 0;
 }
index 804000183c5e8900e69aa6c1748efa106e312690..32814e8800e034ccb073024a0959f5764ced7d86 100644 (file)
@@ -66,19 +66,26 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma,
        return 0;
 }
 
-int fb_deferred_io_fsync(struct file *file, int datasync)
+int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct fb_info *info = file->private_data;
+       struct inode *inode = file->f_path.dentry->d_inode;
+       int err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (err)
+               return err;
 
        /* Skip if deferred io is compiled-in but disabled on this fbdev */
        if (!info->fbdefio)
                return 0;
 
+       mutex_lock(&inode->i_mutex);
        /* Kill off the delayed work */
        cancel_delayed_work_sync(&info->deferred_work);
 
        /* Run it immediately */
-       return schedule_delayed_work(&info->deferred_work, 0);
+       err = schedule_delayed_work(&info->deferred_work, 0);
+       mutex_unlock(&inode->i_mutex);
+       return err;
 }
 EXPORT_SYMBOL_GPL(fb_deferred_io_fsync);
 
index 4014160903a9bf505caabb8793fbb3ad30a73e85..46ce357ca1abd46d5bff175aa5518b9e1f7f778f 100644 (file)
@@ -70,7 +70,8 @@ ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64);
 ssize_t v9fs_fid_readn(struct p9_fid *, char *, char __user *, u32, u64);
 void v9fs_blank_wstat(struct p9_wstat *wstat);
 int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *);
-int v9fs_file_fsync_dotl(struct file *filp, int datasync);
+int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end,
+                        int datasync);
 ssize_t v9fs_file_write_internal(struct inode *, struct p9_fid *,
                                 const char __user *, size_t, loff_t *, int);
 int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode);
index ffed55817f0cd8f5cd1f6560e66805935419835a..3c173fcc2c5a0902be016dd20e6a48411f5d3a55 100644 (file)
@@ -519,32 +519,50 @@ out:
 }
 
 
-static int v9fs_file_fsync(struct file *filp, int datasync)
+static int v9fs_file_fsync(struct file *filp, loff_t start, loff_t end,
+                          int datasync)
 {
        struct p9_fid *fid;
+       struct inode *inode = filp->f_mapping->host;
        struct p9_wstat wstat;
        int retval;
 
+       retval = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (retval)
+               return retval;
+
+       mutex_lock(&inode->i_mutex);
        P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
 
        fid = filp->private_data;
        v9fs_blank_wstat(&wstat);
 
        retval = p9_client_wstat(fid, &wstat);
+       mutex_unlock(&inode->i_mutex);
+
        return retval;
 }
 
-int v9fs_file_fsync_dotl(struct file *filp, int datasync)
+int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end,
+                        int datasync)
 {
        struct p9_fid *fid;
+       struct inode *inode = filp->f_mapping->host;
        int retval;
 
+       retval = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (retval)
+               return retval;
+
+       mutex_lock(&inode->i_mutex);
        P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n",
                        filp, datasync);
 
        fid = filp->private_data;
 
        retval = p9_client_fsync(fid, datasync);
+       mutex_unlock(&inode->i_mutex);
+
        return retval;
 }
 
index 0e95f73a7023290406fad137ee92902f664a5acf..c2b9c79eb64e0ef0fa4f64332761d34fb8973602 100644 (file)
@@ -182,7 +182,7 @@ extern int                   affs_add_entry(struct inode *dir, struct inode *inode, struct dent
 
 void           affs_free_prealloc(struct inode *inode);
 extern void    affs_truncate(struct inode *);
-int            affs_file_fsync(struct file *, int);
+int            affs_file_fsync(struct file *, loff_t, loff_t, int);
 
 /* dir.c */
 
index acf321b70fcd1a8522da3658449ebcaed3a9e733..2f4c935cb3276e544b321e89bfddd4fa2525d2d5 100644 (file)
@@ -923,14 +923,20 @@ affs_truncate(struct inode *inode)
        affs_free_prealloc(inode);
 }
 
-int affs_file_fsync(struct file *filp, int datasync)
+int affs_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = filp->f_mapping->host;
        int ret, err;
 
+       err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (err)
+               return err;
+
+       mutex_lock(&inode->i_mutex);
        ret = write_inode_now(inode, 0);
        err = sync_blockdev(inode->i_sb->s_bdev);
        if (!ret)
                ret = err;
+       mutex_unlock(&inode->i_mutex);
        return ret;
 }
index f396d337b8171865fb16c5a17cad96633c0e71bc..d2b0888126d40f745cd5ff04a60d0f9cc9a9c395 100644 (file)
@@ -750,7 +750,7 @@ extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *);
 extern ssize_t afs_file_write(struct kiocb *, const struct iovec *,
                              unsigned long, loff_t);
 extern int afs_writeback_all(struct afs_vnode *);
-extern int afs_fsync(struct file *, int);
+extern int afs_fsync(struct file *, loff_t, loff_t, int);
 
 
 /*****************************************************************************/
index b806285ff85304bf71032c4b64cc3fb3cf49dda0..9aa52d93c73c4860b285be7d0c685512f511f576 100644 (file)
@@ -681,9 +681,10 @@ int afs_writeback_all(struct afs_vnode *vnode)
  * - the return status from this call provides a reliable indication of
  *   whether any write errors occurred for this process.
  */
-int afs_fsync(struct file *file, int datasync)
+int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct dentry *dentry = file->f_path.dentry;
+       struct inode *inode = file->f_mapping->host;
        struct afs_writeback *wb, *xwb;
        struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
        int ret;
@@ -692,12 +693,19 @@ int afs_fsync(struct file *file, int datasync)
               vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
               datasync);
 
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (ret)
+               return ret;
+       mutex_lock(&inode->i_mutex);
+
        /* use a writeback record as a marker in the queue - when this reaches
         * the front of the queue, all the outstanding writes are either
         * completed or rejected */
        wb = kzalloc(sizeof(*wb), GFP_KERNEL);
-       if (!wb)
-               return -ENOMEM;
+       if (!wb) {
+               ret = -ENOMEM;
+               goto out;
+       }
        wb->vnode = vnode;
        wb->first = 0;
        wb->last = -1;
@@ -720,7 +728,7 @@ int afs_fsync(struct file *file, int datasync)
        if (ret < 0) {
                afs_put_writeback(wb);
                _leave(" = %d [wb]", ret);
-               return ret;
+               goto out;
        }
 
        /* wait for the preceding writes to actually complete */
@@ -729,6 +737,8 @@ int afs_fsync(struct file *file, int datasync)
                                       vnode->writebacks.next == &wb->link);
        afs_put_writeback(wb);
        _leave(" = %d", ret);
+out:
+       mutex_unlock(&inode->i_mutex);
        return ret;
 }
 
index f024d8aaddefff929ec7d557fdfc6449ab7825b8..9205cf25f1c6c4ea9b769ab3cd41add695f14ae0 100644 (file)
@@ -87,7 +87,8 @@ static int bad_file_release(struct inode *inode, struct file *filp)
        return -EIO;
 }
 
-static int bad_file_fsync(struct file *file, int datasync)
+static int bad_file_fsync(struct file *file, loff_t start, loff_t end,
+                         int datasync)
 {
        return -EIO;
 }
index 966617a422d98bd905699c0d34d44c6e4f29bddb..9fb0b15331d3f1b941d7de553b544e437d42210d 100644 (file)
@@ -378,7 +378,7 @@ out:
        return retval;
 }
        
-int blkdev_fsync(struct file *filp, int datasync)
+int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
 {
        struct inode *bd_inode = filp->f_mapping->host;
        struct block_device *bdev = I_BDEV(bd_inode);
@@ -389,14 +389,10 @@ int blkdev_fsync(struct file *filp, int datasync)
         * i_mutex and doing so causes performance issues with concurrent
         * O_SYNC writers to a block device.
         */
-       mutex_unlock(&bd_inode->i_mutex);
-
        error = blkdev_issue_flush(bdev, GFP_KERNEL, NULL);
        if (error == -EOPNOTSUPP)
                error = 0;
 
-       mutex_lock(&bd_inode->i_mutex);
-
        return error;
 }
 EXPORT_SYMBOL(blkdev_fsync);
index f1ff62bff1b3998f82661aedad3544f2649a674b..82be74efbb26dd833a8a0b32bbf108ecfc63baca 100644 (file)
@@ -2605,7 +2605,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
 int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
                           struct inode *inode);
 int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info);
-int btrfs_sync_file(struct file *file, int datasync);
+int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync);
 int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                            int skip_pinned);
 extern const struct file_operations btrfs_file_operations;
index bd4d061c6e4dbc37a0feeddf3e47ec487e565d28..59cbdb120ad0917a001dd9c97d5a17999e6ce59e 100644 (file)
@@ -1452,7 +1452,7 @@ int btrfs_release_file(struct inode *inode, struct file *filp)
  * important optimization for directories because holding the mutex prevents
  * new operations on the dir while we write to disk.
  */
-int btrfs_sync_file(struct file *file, int datasync)
+int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct dentry *dentry = file->f_path.dentry;
        struct inode *inode = dentry->d_inode;
@@ -1462,9 +1462,13 @@ int btrfs_sync_file(struct file *file, int datasync)
 
        trace_btrfs_sync_file(file, datasync);
 
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (ret)
+               return ret;
+       mutex_lock(&inode->i_mutex);
+
        /* we wait first, since the writeback may change the inode */
        root->log_batch++;
-       /* the VFS called filemap_fdatawrite for us */
        btrfs_wait_ordered_range(inode, 0, (u64)-1);
        root->log_batch++;
 
@@ -1472,8 +1476,10 @@ int btrfs_sync_file(struct file *file, int datasync)
         * check the transaction that last modified this inode
         * and see if its already been committed
         */
-       if (!BTRFS_I(inode)->last_trans)
+       if (!BTRFS_I(inode)->last_trans) {
+               mutex_unlock(&inode->i_mutex);
                goto out;
+       }
 
        /*
         * if the last transaction that changed this file was before
@@ -1484,6 +1490,7 @@ int btrfs_sync_file(struct file *file, int datasync)
        if (BTRFS_I(inode)->last_trans <=
            root->fs_info->last_trans_committed) {
                BTRFS_I(inode)->last_trans = 0;
+               mutex_unlock(&inode->i_mutex);
                goto out;
        }
 
@@ -1496,12 +1503,15 @@ int btrfs_sync_file(struct file *file, int datasync)
        trans = btrfs_start_transaction(root, 0);
        if (IS_ERR(trans)) {
                ret = PTR_ERR(trans);
+               mutex_unlock(&inode->i_mutex);
                goto out;
        }
 
        ret = btrfs_log_dentry_safe(trans, root, dentry);
-       if (ret < 0)
+       if (ret < 0) {
+               mutex_unlock(&inode->i_mutex);
                goto out;
+       }
 
        /* we've logged all the items and now have a consistent
         * version of the file in the log.  It is possible that
@@ -1513,7 +1523,7 @@ int btrfs_sync_file(struct file *file, int datasync)
         * file again, but that will end up using the synchronization
         * inside btrfs_sync_log to keep things safe.
         */
-       mutex_unlock(&dentry->d_inode->i_mutex);
+       mutex_unlock(&inode->i_mutex);
 
        if (ret != BTRFS_NO_LOG_SYNC) {
                if (ret > 0) {
@@ -1528,7 +1538,6 @@ int btrfs_sync_file(struct file *file, int datasync)
        } else {
                ret = btrfs_end_transaction(trans, root);
        }
-       mutex_lock(&dentry->d_inode->i_mutex);
 out:
        return ret > 0 ? -EIO : ret;
 }
index f605753c8fe9b20aa4d2f165b57534d1d9b3fe78..8d74ad7ba556624c4eb80e1f598ac908e5356d04 100644 (file)
@@ -1811,7 +1811,7 @@ out:
        spin_unlock(&ci->i_unsafe_lock);
 }
 
-int ceph_fsync(struct file *file, int datasync)
+int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
        struct ceph_inode_info *ci = ceph_inode(inode);
@@ -1822,9 +1822,10 @@ int ceph_fsync(struct file *file, int datasync)
        dout("fsync %p%s\n", inode, datasync ? " datasync" : "");
        sync_write_wait(inode);
 
-       ret = filemap_write_and_wait(inode->i_mapping);
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
        if (ret < 0)
                return ret;
+       mutex_lock(&inode->i_mutex);
 
        dirty = try_flush_caps(inode, NULL, &flush_tid);
        dout("fsync dirty caps are %s\n", ceph_cap_string(dirty));
@@ -1841,6 +1842,7 @@ int ceph_fsync(struct file *file, int datasync)
        }
 
        dout("fsync %p%s done\n", inode, datasync ? " datasync" : "");
+       mutex_unlock(&inode->i_mutex);
        return ret;
 }
 
index 0972b457a03f33dd9f61ee9fec66e851fdd44316..1065ac779840ac4bb4c7f740c47c1ec33ef79787 100644 (file)
@@ -1118,7 +1118,8 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
  * an fsync() on a dir will wait for any uncommitted directory
  * operations to commit.
  */
-static int ceph_dir_fsync(struct file *file, int datasync)
+static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end,
+                         int datasync)
 {
        struct inode *inode = file->f_path.dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
@@ -1128,6 +1129,11 @@ static int ceph_dir_fsync(struct file *file, int datasync)
        int ret = 0;
 
        dout("dir_fsync %p\n", inode);
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (ret)
+               return ret;
+       mutex_lock(&inode->i_mutex);
+
        spin_lock(&ci->i_unsafe_lock);
        if (list_empty(head))
                goto out;
@@ -1161,6 +1167,8 @@ static int ceph_dir_fsync(struct file *file, int datasync)
        } while (req->r_tid < last_tid);
 out:
        spin_unlock(&ci->i_unsafe_lock);
+       mutex_unlock(&inode->i_mutex);
+
        return ret;
 }
 
index 56c41ef47cad207cad60db5b1aa82030356f3cf1..30446b144e3d2106c3beb65bd8802f956a849516 100644 (file)
@@ -728,7 +728,8 @@ extern void ceph_put_cap(struct ceph_mds_client *mdsc,
 
 extern void ceph_queue_caps_release(struct inode *inode);
 extern int ceph_write_inode(struct inode *inode, struct writeback_control *wbc);
-extern int ceph_fsync(struct file *file, int datasync);
+extern int ceph_fsync(struct file *file, loff_t start, loff_t end,
+                     int datasync);
 extern void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
                                    struct ceph_mds_session *session);
 extern struct ceph_cap *ceph_get_cap_for_mds(struct ceph_inode_info *ci,
index 036ca83e5f461c2ff3e807ded5b7b797e5b6f836..fbd050c8d52a53063319ff266568300788faf02f 100644 (file)
@@ -91,8 +91,8 @@ extern ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov,
 extern ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
                                  unsigned long nr_segs, loff_t pos);
 extern int cifs_lock(struct file *, int, struct file_lock *);
-extern int cifs_fsync(struct file *, int);
-extern int cifs_strict_fsync(struct file *, int);
+extern int cifs_fsync(struct file *, loff_t, loff_t, int);
+extern int cifs_strict_fsync(struct file *, loff_t, loff_t, int);
 extern int cifs_flush(struct file *, fl_owner_t id);
 extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
 extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *);
index bb71471a4d9d68516269550d6b5eeb5603d5a46b..cef5844511132a8b6d445cbcbb5658e29db874e7 100644 (file)
@@ -1401,7 +1401,8 @@ static int cifs_write_end(struct file *file, struct address_space *mapping,
        return rc;
 }
 
-int cifs_strict_fsync(struct file *file, int datasync)
+int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
+                     int datasync)
 {
        int xid;
        int rc = 0;
@@ -1410,6 +1411,11 @@ int cifs_strict_fsync(struct file *file, int datasync)
        struct inode *inode = file->f_path.dentry->d_inode;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 
+       rc = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (rc)
+               return rc;
+       mutex_lock(&inode->i_mutex);
+
        xid = GetXid();
 
        cFYI(1, "Sync file - name: %s datasync: 0x%x",
@@ -1428,16 +1434,23 @@ int cifs_strict_fsync(struct file *file, int datasync)
                rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
 
        FreeXid(xid);
+       mutex_unlock(&inode->i_mutex);
        return rc;
 }
 
-int cifs_fsync(struct file *file, int datasync)
+int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        int xid;
        int rc = 0;
        struct cifs_tcon *tcon;
        struct cifsFileInfo *smbfile = file->private_data;
        struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+       struct inode *inode = file->f_mapping->host;
+
+       rc = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (rc)
+               return rc;
+       mutex_lock(&inode->i_mutex);
 
        xid = GetXid();
 
@@ -1449,6 +1462,7 @@ int cifs_fsync(struct file *file, int datasync)
                rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
 
        FreeXid(xid);
+       mutex_unlock(&inode->i_mutex);
        return rc;
 }
 
index 6b443ff43a19dd829b1d35877d144e37b2fce918..b7143cf783ace6a6231fa1acb6f7467c2992fd3f 100644 (file)
@@ -11,7 +11,7 @@ extern int coda_fake_statfs;
 
 void coda_destroy_inodecache(void);
 int coda_init_inodecache(void);
-int coda_fsync(struct file *coda_file, int datasync);
+int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync);
 void coda_sysctl_init(void);
 void coda_sysctl_clean(void);
 
index 0433057be3305c083fc4a705dfd5fcfbd857e2c0..8edd404e64192c2961b6a3d972df027b4ee56f14 100644 (file)
@@ -199,7 +199,7 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
        return 0;
 }
 
-int coda_fsync(struct file *coda_file, int datasync)
+int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync)
 {
        struct file *host_file;
        struct inode *coda_inode = coda_file->f_path.dentry->d_inode;
@@ -210,6 +210,11 @@ int coda_fsync(struct file *coda_file, int datasync)
              S_ISLNK(coda_inode->i_mode)))
                return -EINVAL;
 
+       err = filemap_write_and_wait_range(coda_inode->i_mapping, start, end);
+       if (err)
+               return err;
+       mutex_lock(&coda_inode->i_mutex);
+
        cfi = CODA_FTOC(coda_file);
        BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
        host_file = cfi->cfi_container;
@@ -217,6 +222,7 @@ int coda_fsync(struct file *coda_file, int datasync)
        err = vfs_fsync(host_file, datasync);
        if (!err && !datasync)
                err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
+       mutex_unlock(&coda_inode->i_mutex);
 
        return err;
 }
index 4ec9eb00a241fb56adcec03587d8b3c8ae506d40..c6ac98cf9baaeca5d898cce216aa0dc08df2716c 100644 (file)
@@ -270,14 +270,15 @@ static int ecryptfs_release(struct inode *inode, struct file *file)
 }
 
 static int
-ecryptfs_fsync(struct file *file, int datasync)
+ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        int rc = 0;
 
-       rc = generic_file_fsync(file, datasync);
+       rc = generic_file_fsync(file, start, end, datasync);
        if (rc)
                goto out;
-       rc = vfs_fsync(ecryptfs_file_to_lower(file), datasync);
+       rc = vfs_fsync_range(ecryptfs_file_to_lower(file), start, end,
+                            datasync);
 out:
        return rc;
 }
index 45ca323d8363440b1c0641c6b29302911677eb9d..491c6c078e7f5e0ac420646288452d93cca86ce2 100644 (file)
@@ -42,11 +42,19 @@ static int exofs_release_file(struct inode *inode, struct file *filp)
  *   Note, in exofs all metadata is written as part of inode, regardless.
  *   The writeout is synchronous
  */
-static int exofs_file_fsync(struct file *filp, int datasync)
+static int exofs_file_fsync(struct file *filp, loff_t start, loff_t end,
+                           int datasync)
 {
+       struct inode *inode = filp->f_mapping->host;
        int ret;
 
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (ret)
+               return ret;
+
+       mutex_lock(&inode->i_mutex);
        ret = sync_inode_metadata(filp->f_mapping->host, 1);
+       mutex_unlock(&inode->i_mutex);
        return ret;
 }
 
index 645be9e7ee4713b9bfc6fc7c11095ce57addcd09..af9fc89b1b2d3e92994e63db97023f2ebf32ecac 100644 (file)
@@ -150,7 +150,8 @@ extern void ext2_write_super (struct super_block *);
 extern const struct file_operations ext2_dir_operations;
 
 /* file.c */
-extern int ext2_fsync(struct file *file, int datasync);
+extern int ext2_fsync(struct file *file, loff_t start, loff_t end,
+                     int datasync);
 extern const struct inode_operations ext2_file_inode_operations;
 extern const struct file_operations ext2_file_operations;
 extern const struct file_operations ext2_xip_file_operations;
index 49eec9456c5b3dc47dbf4fa102e0c81c656beda5..82e06321de359176c20c9603ba1a9dee2b15b638 100644 (file)
@@ -40,13 +40,13 @@ static int ext2_release_file (struct inode * inode, struct file * filp)
        return 0;
 }
 
-int ext2_fsync(struct file *file, int datasync)
+int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        int ret;
        struct super_block *sb = file->f_mapping->host->i_sb;
        struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
 
-       ret = generic_file_fsync(file, datasync);
+       ret = generic_file_fsync(file, start, end, datasync);
        if (ret == -EIO || test_and_clear_bit(AS_EIO, &mapping->flags)) {
                /* We don't really know where the IO error happened... */
                ext2_error(sb, __func__,
index 09b13bb34c94e9c6e2561b4b7dcab93ae334359f..0bcf63adb80a9290866c42153bfe6af37777b885 100644 (file)
@@ -43,7 +43,7 @@
  * inode to disk.
  */
 
-int ext3_sync_file(struct file *file, int datasync)
+int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
        struct ext3_inode_info *ei = EXT3_I(inode);
@@ -54,6 +54,17 @@ int ext3_sync_file(struct file *file, int datasync)
        if (inode->i_sb->s_flags & MS_RDONLY)
                return 0;
 
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (ret)
+               return ret;
+
+       /*
+        * Taking the mutex here just to keep consistent with how fsync was
+        * called previously, however it looks like we don't need to take
+        * i_mutex at all.
+        */
+       mutex_lock(&inode->i_mutex);
+
        J_ASSERT(ext3_journal_current_handle() == NULL);
 
        /*
@@ -70,8 +81,10 @@ int ext3_sync_file(struct file *file, int datasync)
         *  (they were dirtied by commit).  But that's OK - the blocks are
         *  safe in-journal, which is all fsync() needs to ensure.
         */
-       if (ext3_should_journal_data(inode))
+       if (ext3_should_journal_data(inode)) {
+               mutex_unlock(&inode->i_mutex);
                return ext3_force_commit(inode->i_sb);
+       }
 
        if (datasync)
                commit_tid = atomic_read(&ei->i_datasync_tid);
@@ -91,5 +104,6 @@ int ext3_sync_file(struct file *file, int datasync)
         */
        if (needs_barrier)
                blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
+       mutex_unlock(&inode->i_mutex);
        return ret;
 }
index 1921392cd7085d4b2679ea398979ec78d17d2099..fa44df8797115f97f3e098b512ba8b7c7a2a2de5 100644 (file)
@@ -1758,7 +1758,7 @@ extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
 extern void ext4_htree_free_dir_info(struct dir_private_info *p);
 
 /* fsync.c */
-extern int ext4_sync_file(struct file *, int);
+extern int ext4_sync_file(struct file *, loff_t, loff_t, int);
 extern int ext4_flush_completed_IO(struct inode *);
 
 /* hash.c */
index ce66d2fe826cbdf99389dea50aa3f72240e911d9..da3bed3e0c29d1159f2169f4b94be97ce485d966 100644 (file)
@@ -151,6 +151,32 @@ static int ext4_sync_parent(struct inode *inode)
        return ret;
 }
 
+/**
+ * __sync_file - generic_file_fsync without the locking and filemap_write
+ * @inode:     inode to sync
+ * @datasync:  only sync essential metadata if true
+ *
+ * This is just generic_file_fsync without the locking.  This is needed for
+ * nojournal mode to make sure this inodes data/metadata makes it to disk
+ * properly.  The i_mutex should be held already.
+ */
+static int __sync_inode(struct inode *inode, int datasync)
+{
+       int err;
+       int ret;
+
+       ret = sync_mapping_buffers(inode->i_mapping);
+       if (!(inode->i_state & I_DIRTY))
+               return ret;
+       if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+               return ret;
+
+       err = sync_inode_metadata(inode, 1);
+       if (ret == 0)
+               ret = err;
+       return ret;
+}
+
 /*
  * akpm: A new design for ext4_sync_file().
  *
@@ -165,7 +191,7 @@ static int ext4_sync_parent(struct inode *inode)
  * i_mutex lock is held when entering and exiting this function
  */
 
-int ext4_sync_file(struct file *file, int datasync)
+int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
        struct ext4_inode_info *ei = EXT4_I(inode);
@@ -178,15 +204,20 @@ int ext4_sync_file(struct file *file, int datasync)
 
        trace_ext4_sync_file_enter(file, datasync);
 
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (ret)
+               return ret;
+       mutex_lock(&inode->i_mutex);
+
        if (inode->i_sb->s_flags & MS_RDONLY)
-               return 0;
+               goto out;
 
        ret = ext4_flush_completed_IO(inode);
        if (ret < 0)
                goto out;
 
        if (!journal) {
-               ret = generic_file_fsync(file, datasync);
+               ret = __sync_inode(inode, datasync);
                if (!ret && !list_empty(&inode->i_dentry))
                        ret = ext4_sync_parent(inode);
                goto out;
@@ -220,6 +251,7 @@ int ext4_sync_file(struct file *file, int datasync)
        if (needs_barrier)
                blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
  out:
+       mutex_unlock(&inode->i_mutex);
        trace_ext4_sync_file_exit(inode, ret);
        return ret;
 }
index a975b4147e9179fe6bf3bd1917b48ec8a031110b..a5d3853822e07b68f5434007725ddf4acec0330f 100644 (file)
@@ -310,7 +310,8 @@ extern int fat_setattr(struct dentry * dentry, struct iattr * attr);
 extern void fat_truncate_blocks(struct inode *inode, loff_t offset);
 extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry,
                       struct kstat *stat);
-extern int fat_file_fsync(struct file *file, int datasync);
+extern int fat_file_fsync(struct file *file, loff_t start, loff_t end,
+                         int datasync);
 
 /* fat/inode.c */
 extern void fat_attach(struct inode *inode, loff_t i_pos);
index e1587c54d3c1398373a027c01fc81dd4083e2146..c118acf16e4310530e39abf115fd003813cdea03 100644 (file)
@@ -149,12 +149,12 @@ static int fat_file_release(struct inode *inode, struct file *filp)
        return 0;
 }
 
-int fat_file_fsync(struct file *filp, int datasync)
+int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = filp->f_mapping->host;
        int res, err;
 
-       res = generic_file_fsync(filp, datasync);
+       res = generic_file_fsync(filp, start, end, datasync);
        err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping);
 
        return res ? res : err;
index 02063dde2728cafdc3cf549d35fb81ab3a7e00c2..9f63e493a9b6f79b1d4c3b667074742c2c29821a 100644 (file)
@@ -1176,9 +1176,10 @@ static int fuse_dir_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int fuse_dir_fsync(struct file *file, int datasync)
+static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end,
+                         int datasync)
 {
-       return fuse_fsync_common(file, datasync, 1);
+       return fuse_fsync_common(file, start, end, datasync, 1);
 }
 
 static bool update_mtime(unsigned ivalid)
index 73b89df20851e220308c9db63929f18f01d6e66f..7bb685cdd00cfcf855ee90fa947fc3871ef7f787 100644 (file)
@@ -400,7 +400,8 @@ static void fuse_sync_writes(struct inode *inode)
        fuse_release_nowrite(inode);
 }
 
-int fuse_fsync_common(struct file *file, int datasync, int isdir)
+int fuse_fsync_common(struct file *file, loff_t start, loff_t end,
+                     int datasync, int isdir)
 {
        struct inode *inode = file->f_mapping->host;
        struct fuse_conn *fc = get_fuse_conn(inode);
@@ -412,9 +413,15 @@ int fuse_fsync_common(struct file *file, int datasync, int isdir)
        if (is_bad_inode(inode))
                return -EIO;
 
+       err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (err)
+               return err;
+
        if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir))
                return 0;
 
+       mutex_lock(&inode->i_mutex);
+
        /*
         * Start writeback against all dirty pages of the inode, then
         * wait for all outstanding writes, before sending the FSYNC
@@ -422,13 +429,15 @@ int fuse_fsync_common(struct file *file, int datasync, int isdir)
         */
        err = write_inode_now(inode, 0);
        if (err)
-               return err;
+               goto out;
 
        fuse_sync_writes(inode);
 
        req = fuse_get_req(fc);
-       if (IS_ERR(req))
-               return PTR_ERR(req);
+       if (IS_ERR(req)) {
+               err = PTR_ERR(req);
+               goto out;
+       }
 
        memset(&inarg, 0, sizeof(inarg));
        inarg.fh = ff->fh;
@@ -448,12 +457,15 @@ int fuse_fsync_common(struct file *file, int datasync, int isdir)
                        fc->no_fsync = 1;
                err = 0;
        }
+out:
+       mutex_unlock(&inode->i_mutex);
        return err;
 }
 
-static int fuse_fsync(struct file *file, int datasync)
+static int fuse_fsync(struct file *file, loff_t start, loff_t end,
+                     int datasync)
 {
-       return fuse_fsync_common(file, datasync, 0);
+       return fuse_fsync_common(file, start, end, datasync, 0);
 }
 
 void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos,
index b788becada76bf8616512fb766525fc89950eeec..c6aa2d4b851733a250205734215c785be6944507 100644 (file)
@@ -589,7 +589,8 @@ void fuse_release_common(struct file *file, int opcode);
 /**
  * Send FSYNC or FSYNCDIR request
  */
-int fuse_fsync_common(struct file *file, int datasync, int isdir);
+int fuse_fsync_common(struct file *file, loff_t start, loff_t end,
+                     int datasync, int isdir);
 
 /**
  * Notify poll wakeup
index 89c39e53760d660d8e90b38e9b5ee1f2f3b07317..f82cb5e1cb6b548b69a08787e1d1d3ce3a4330c5 100644 (file)
@@ -544,7 +544,9 @@ static int gfs2_close(struct inode *inode, struct file *file)
 
 /**
  * gfs2_fsync - sync the dirty data for a file (across the cluster)
- * @file: the file that points to the dentry (we ignore this)
+ * @file: the file that points to the dentry
+ * @start: the start position in the file to sync
+ * @end: the end position in the file to sync
  * @datasync: set if we can ignore timestamp changes
  *
  * The VFS will flush data for us. We only need to worry
@@ -553,23 +555,32 @@ static int gfs2_close(struct inode *inode, struct file *file)
  * Returns: errno
  */
 
-static int gfs2_fsync(struct file *file, int datasync)
+static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
+                     int datasync)
 {
        struct inode *inode = file->f_mapping->host;
        int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
        struct gfs2_inode *ip = GFS2_I(inode);
        int ret;
 
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (ret)
+               return ret;
+       mutex_lock(&inode->i_mutex);
+
        if (datasync)
                sync_state &= ~I_DIRTY_SYNC;
 
        if (sync_state) {
                ret = sync_inode_metadata(inode, 1);
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&inode->i_mutex);
                        return ret;
+               }
                gfs2_ail_flush(ip->i_gl);
        }
 
+       mutex_unlock(&inode->i_mutex);
        return 0;
 }
 
index 5e7c3f3096170c97f0c8d648fc139c9867dae445..96a1b625fc74de04cd79ef2ba8fc2a2dba0301a1 100644 (file)
@@ -627,12 +627,18 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)
        return 0;
 }
 
-static int hfs_file_fsync(struct file *filp, int datasync)
+static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end,
+                         int datasync)
 {
        struct inode *inode = filp->f_mapping->host;
        struct super_block * sb;
        int ret, err;
 
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (ret)
+               return ret;
+       mutex_lock(&inode->i_mutex);
+
        /* sync the inode to buffers */
        ret = write_inode_now(inode, 0);
 
@@ -649,6 +655,7 @@ static int hfs_file_fsync(struct file *filp, int datasync)
        err = sync_blockdev(sb->s_bdev);
        if (!ret)
                ret = err;
+       mutex_unlock(&inode->i_mutex);
        return ret;
 }
 
index d6857523336d21412ec50bb0a8c8039526ab6adb..38184e3609327c57373a07685d4ab8a75d78efad 100644 (file)
@@ -392,7 +392,8 @@ int hfsplus_cat_read_inode(struct inode *, struct hfs_find_data *);
 int hfsplus_cat_write_inode(struct inode *);
 struct inode *hfsplus_new_inode(struct super_block *, int);
 void hfsplus_delete_inode(struct inode *);
-int hfsplus_file_fsync(struct file *file, int datasync);
+int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end,
+                      int datasync);
 
 /* ioctl.c */
 long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
index 5b1cb98741cc5e7d6e003ca1db989300d5cc8fd3..30486e01d003f2a18a5fe6b61e5fef19faf727dc 100644 (file)
@@ -308,13 +308,19 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
        return 0;
 }
 
-int hfsplus_file_fsync(struct file *file, int datasync)
+int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end,
+                      int datasync)
 {
        struct inode *inode = file->f_mapping->host;
        struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
        int error = 0, error2;
 
+       error = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (error)
+               return error;
+       mutex_lock(&inode->i_mutex);
+
        /*
         * Sync inode metadata into the catalog and extent trees.
         */
@@ -342,6 +348,8 @@ int hfsplus_file_fsync(struct file *file, int datasync)
        if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
                blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
 
+       mutex_unlock(&inode->i_mutex);
+
        return error;
 }
 
index 6e449c599b9dbf357e630e9fba8e02a826d880e5..0d22afdd4611d53383957b86bc8688cba62ef3d4 100644 (file)
@@ -362,9 +362,20 @@ retry:
        return 0;
 }
 
-int hostfs_fsync(struct file *file, int datasync)
+int hostfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
-       return fsync_file(HOSTFS_I(file->f_mapping->host)->fd, datasync);
+       struct inode *inode = file->f_mapping->host;
+       int ret;
+
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (ret)
+               return ret;
+
+       mutex_lock(&inode->i_mutex);
+       ret = fsync_file(HOSTFS_I(inode)->fd, datasync);
+       mutex_unlock(&inode->i_mutex);
+
+       return ret;
 }
 
 static const struct file_operations hostfs_file_fops = {
index 89c500ee521382c2250c0a818a3c18c773025ac8..89d2a5803ae35b6644507352124f512048f0513e 100644 (file)
@@ -18,9 +18,14 @@ static int hpfs_file_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-int hpfs_file_fsync(struct file *file, int datasync)
+int hpfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
+       int ret;
+
+       ret = filemap_write_and_wait_range(file->f_mapping, start, end);
+       if (ret)
+               return ret;
        return sync_blockdev(inode->i_sb->s_bdev);
 }
 
index dd552f862c8f1c562a34768f970b6ddcb68b2336..331b5e234ef3aca66c93c27f7f90fd357b14f8d3 100644 (file)
@@ -258,7 +258,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, const char *,
 
 /* file.c */
 
-int hpfs_file_fsync(struct file *, int);
+int hpfs_file_fsync(struct file *, loff_t, loff_t, int);
 extern const struct file_operations hpfs_file_ops;
 extern const struct inode_operations hpfs_file_iops;
 extern const struct address_space_operations hpfs_aops;
index 85c098a499f33ce858bdfaf85f76f053bd1b9376..8635be5ffd97e90f443efeb09acdc6efa4d4cf39 100644 (file)
@@ -573,9 +573,10 @@ static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
        return err;
 }
 
-static int hppfs_fsync(struct file *file, int datasync)
+static int hppfs_fsync(struct file *file, loff_t start, loff_t end,
+                      int datasync)
 {
-       return 0;
+       return filemap_write_and_wait_range(file->f_mapping, start, end);
 }
 
 static const struct file_operations hppfs_dir_fops = {
index 1c0a08d711aa431a72770f33840cd5c1b9d997ad..3989f7e09f7f649c96ad9e5737de886697c018b4 100644 (file)
@@ -27,13 +27,20 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
                        struct page **pagep, void **fsdata);
 static int jffs2_readpage (struct file *filp, struct page *pg);
 
-int jffs2_fsync(struct file *filp, int datasync)
+int jffs2_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = filp->f_mapping->host;
        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+       int ret;
+
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (ret)
+               return ret;
 
+       mutex_lock(&inode->i_mutex);
        /* Trigger GC to flush any pending writes for this inode */
        jffs2_flush_wbuf_gc(c, inode->i_ino);
+       mutex_unlock(&inode->i_mutex);
 
        return 0;
 }
index 65c6c43ca482b4359e675be6c21a0f6d5d97ac69..9c252835e8e59507c8d9b56ddd985c5ed3e9ed84 100644 (file)
@@ -158,7 +158,7 @@ extern const struct inode_operations jffs2_dir_inode_operations;
 extern const struct file_operations jffs2_file_operations;
 extern const struct inode_operations jffs2_file_inode_operations;
 extern const struct address_space_operations jffs2_file_address_operations;
-int jffs2_fsync(struct file *, int);
+int jffs2_fsync(struct file *, loff_t, loff_t, int);
 int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
 
 /* ioctl.c */
index 9f32315acef1584877e40d9bbbf59645dcbba6ac..7527855b5cc6fc71ec5b613fbf022bd725843f20 100644 (file)
 #include "jfs_acl.h"
 #include "jfs_debug.h"
 
-int jfs_fsync(struct file *file, int datasync)
+int jfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
        int rc = 0;
 
+       rc = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (rc)
+               return rc;
+
+       mutex_lock(&inode->i_mutex);
        if (!(inode->i_state & I_DIRTY) ||
            (datasync && !(inode->i_state & I_DIRTY_DATASYNC))) {
                /* Make sure committed changes hit the disk */
                jfs_flush_journal(JFS_SBI(inode->i_sb)->log, 1);
+               mutex_unlock(&inode->i_mutex);
                return rc;
        }
 
        rc |= jfs_commit_inode(inode, 1);
+       mutex_unlock(&inode->i_mutex);
 
        return rc ? -EIO : 0;
 }
index ec2fb8b945fc9d0ac102028bbfc6a5c184521683..9271cfe4a1490ca88785a7973ecd22fd88000e73 100644 (file)
@@ -21,7 +21,7 @@
 struct fid;
 
 extern struct inode *ialloc(struct inode *, umode_t);
-extern int jfs_fsync(struct file *, int);
+extern int jfs_fsync(struct file *, loff_t, loff_t, int);
 extern long jfs_ioctl(struct file *, unsigned int, unsigned long);
 extern long jfs_compat_ioctl(struct file *, unsigned int, unsigned long);
 extern struct inode *jfs_iget(struct super_block *, unsigned long);
index bd50b11f92da754cd3b2f3c7532ea3fb2c02cf5d..8f2271a5df53c119eb05b86fa9834652ede9c57b 100644 (file)
@@ -905,21 +905,29 @@ EXPORT_SYMBOL_GPL(generic_fh_to_parent);
  * filesystems which track all non-inode metadata in the buffers list
  * hanging off the address_space structure.
  */
-int generic_file_fsync(struct file *file, int datasync)
+int generic_file_fsync(struct file *file, loff_t start, loff_t end,
+                      int datasync)
 {
        struct inode *inode = file->f_mapping->host;
        int err;
        int ret;
 
+       err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (err)
+               return err;
+
+       mutex_lock(&inode->i_mutex);
        ret = sync_mapping_buffers(inode->i_mapping);
        if (!(inode->i_state & I_DIRTY))
-               return ret;
+               goto out;
        if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
-               return ret;
+               goto out;
 
        err = sync_inode_metadata(inode, 1);
        if (ret == 0)
                ret = err;
+out:
+       mutex_unlock(&inode->i_mutex);
        return ret;
 }
 EXPORT_SYMBOL(generic_file_fsync);
@@ -956,7 +964,7 @@ EXPORT_SYMBOL(generic_check_addressable);
 /*
  * No-op implementation of ->fsync for in-memory filesystems.
  */
-int noop_fsync(struct file *file, int datasync)
+int noop_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        return 0;
 }
index c2ad7028def4ebf78295a418ab8d49b1bb7ff765..b548c87a86f1dbe6ff3b15b185fa432697ea0096 100644 (file)
@@ -219,11 +219,20 @@ long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        }
 }
 
-int logfs_fsync(struct file *file, int datasync)
+int logfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct super_block *sb = file->f_mapping->host->i_sb;
+       struct inode *inode = file->f_mapping->host;
+       int ret;
+
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (ret)
+               return ret;
 
+       mutex_lock(&inode->i_mutex);
        logfs_write_anchor(sb);
+       mutex_unlock(&inode->i_mutex);
+
        return 0;
 }
 
index 57afd4a6fabbb992b0b08ea9bb5399071ea576c2..f22d108bfa5dd54d4ea81129561f093076559a9f 100644 (file)
@@ -506,7 +506,7 @@ extern const struct file_operations logfs_reg_fops;
 extern const struct address_space_operations logfs_reg_aops;
 int logfs_readpage(struct file *file, struct page *page);
 long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-int logfs_fsync(struct file *file, int datasync);
+int logfs_fsync(struct file *file, loff_t start, loff_t end, int datasync);
 
 /* gc.c */
 u32 get_best_cand(struct super_block *sb, struct candidate_list *list, u32 *ec);
index 0ed65e0c3dfe29bddae78c9dcf171968c6e998dc..64a326418aa272dbda0211e892ddb32b7217eb81 100644 (file)
@@ -20,9 +20,9 @@
 
 #include "ncp_fs.h"
 
-static int ncp_fsync(struct file *file, int datasync)
+static int ncp_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
-       return 0;
+       return filemap_write_and_wait_range(file->f_mapping, start, end);
 }
 
 /*
index 8a45e6d1f6a477cfdb18fe29698c59c8d3f70a3b..57f578e2560a0be44a6e29978627f315f57db01d 100644 (file)
@@ -56,7 +56,7 @@ static int nfs_link(struct dentry *, struct inode *, struct dentry *);
 static int nfs_mknod(struct inode *, struct dentry *, int, dev_t);
 static int nfs_rename(struct inode *, struct dentry *,
                      struct inode *, struct dentry *);
-static int nfs_fsync_dir(struct file *, int);
+static int nfs_fsync_dir(struct file *, loff_t, loff_t, int);
 static loff_t nfs_llseek_dir(struct file *, loff_t, int);
 static void nfs_readdir_clear_array(struct page*);
 
@@ -945,15 +945,19 @@ out:
  * All directory operations under NFS are synchronous, so fsync()
  * is a dummy operation.
  */
-static int nfs_fsync_dir(struct file *filp, int datasync)
+static int nfs_fsync_dir(struct file *filp, loff_t start, loff_t end,
+                        int datasync)
 {
        struct dentry *dentry = filp->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
 
        dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n",
                        dentry->d_parent->d_name.name, dentry->d_name.name,
                        datasync);
 
+       mutex_lock(&inode->i_mutex);
        nfs_inc_stats(dentry->d_inode, NFSIOS_VFSFSYNC);
+       mutex_unlock(&inode->i_mutex);
        return 0;
 }
 
index 2c1705b6acd7c6bb92d397a43a6d37d98825702d..28b8c3f3cda3af002e99044fee907f119ac78afb 100644 (file)
@@ -55,7 +55,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
 static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov,
                                unsigned long nr_segs, loff_t pos);
 static int  nfs_file_flush(struct file *, fl_owner_t id);
-static int  nfs_file_fsync(struct file *, int datasync);
+static int  nfs_file_fsync(struct file *, loff_t, loff_t, int datasync);
 static int nfs_check_flags(int flags);
 static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
 static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
@@ -308,7 +308,7 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
  * fall back to doing a synchronous write.
  */
 static int
-nfs_file_fsync(struct file *file, int datasync)
+nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct dentry *dentry = file->f_path.dentry;
        struct nfs_open_context *ctx = nfs_file_open_context(file);
@@ -316,11 +316,15 @@ nfs_file_fsync(struct file *file, int datasync)
        int have_error, status;
        int ret = 0;
 
-
        dprintk("NFS: fsync file(%s/%s) datasync %d\n",
                        dentry->d_parent->d_name.name, dentry->d_name.name,
                        datasync);
 
+       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (ret)
+               return ret;
+       mutex_lock(&inode->i_mutex);
+
        nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
        have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
        status = nfs_commit_inode(inode, FLUSH_SYNC);
@@ -332,6 +336,7 @@ nfs_file_fsync(struct file *file, int datasync)
        if (!ret && !datasync)
                /* application has asked for meta-data sync */
                ret = pnfs_layoutcommit_inode(inode, true);
+       mutex_unlock(&inode->i_mutex);
        return ret;
 }
 
index d7eeca62febd960e9a78604021526364158d0382..26601529dc17c7ff9f5bc7d4c249a59371cd14c4 100644 (file)
@@ -27,7 +27,7 @@
 #include "nilfs.h"
 #include "segment.h"
 
-int nilfs_sync_file(struct file *file, int datasync)
+int nilfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 {
        /*
         * Called from fsync() system call
@@ -40,8 +40,15 @@ int nilfs_sync_file(struct file *file, int datasync)
        struct inode *inode = file->f_mapping->host;
        int err;
 
-       if (!nilfs_inode_dirty(inode))
+       err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (err)
+               return err;
+       mutex_lock(&inode->i_mutex);
+
+       if (!nilfs_inode_dirty(inode)) {
+               mutex_unlock(&inode->i_mutex);
                return 0;
+       }
 
        if (datasync)
                err = nilfs_construct_dsync_segment(inode->i_sb, inode, 0,
@@ -49,6 +56,7 @@ int nilfs_sync_file(struct file *file, int datasync)
        else
                err = nilfs_construct_segment(inode->i_sb);
 
+       mutex_unlock(&inode->i_mutex);
        return err;
 }
 
index 6fb7511c0328586def5821cb21ee07804e549d99..255d5e1c03b74197046877181fb1c205c094aafd 100644 (file)
@@ -235,7 +235,7 @@ extern void nilfs_set_link(struct inode *, struct nilfs_dir_entry *,
                           struct page *, struct inode *);
 
 /* file.c */
-extern int nilfs_sync_file(struct file *, int);
+extern int nilfs_sync_file(struct file *, loff_t, loff_t, int);
 
 /* ioctl.c */
 long nilfs_ioctl(struct file *, unsigned int, unsigned long);
index 0f48e7c5d9e1a7d35fad15b6231107ee5bf7100b..99e36107ff604c2164fa7f154b91629f9bf826e3 100644 (file)
@@ -1527,13 +1527,20 @@ static int ntfs_dir_open(struct inode *vi, struct file *filp)
  * this problem for now.  We do write the $BITMAP attribute if it is present
  * which is the important one for a directory so things are not too bad.
  */
-static int ntfs_dir_fsync(struct file *filp, int datasync)
+static int ntfs_dir_fsync(struct file *filp, loff_t start, loff_t end,
+                         int datasync)
 {
        struct inode *bmp_vi, *vi = filp->f_mapping->host;
        int err, ret;
        ntfs_attr na;
 
        ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
+
+       err = filemap_write_and_wait_range(vi->i_mapping, start, end);
+       if (err)
+               return err;
+       mutex_lock(&vi->i_mutex);
+
        BUG_ON(!S_ISDIR(vi->i_mode));
        /* If the bitmap attribute inode is in memory sync it, too. */
        na.mft_no = vi->i_ino;
@@ -1555,6 +1562,7 @@ static int ntfs_dir_fsync(struct file *filp, int datasync)
        else
                ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx.  Error "
                                "%u.", datasync ? "data" : "", vi->i_ino, -ret);
+       mutex_unlock(&vi->i_mutex);
        return ret;
 }
 
index b59f5ac26bef85c080b95368c3dfe317921165d1..c587e2d271830bc01dd861a6f95926365c664c58 100644 (file)
@@ -2152,12 +2152,19 @@ static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
  * with this inode but since we have no simple way of getting to them we ignore
  * this problem for now.
  */
-static int ntfs_file_fsync(struct file *filp, int datasync)
+static int ntfs_file_fsync(struct file *filp, loff_t start, loff_t end,
+                          int datasync)
 {
        struct inode *vi = filp->f_mapping->host;
        int err, ret = 0;
 
        ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
+
+       err = filemap_write_and_wait_range(vi->i_mapping, start, end);
+       if (err)
+               return err;
+       mutex_lock(&vi->i_mutex);
+
        BUG_ON(S_ISDIR(vi->i_mode));
        if (!datasync || !NInoNonResident(NTFS_I(vi)))
                ret = __ntfs_write_inode(vi, 1);
@@ -2175,6 +2182,7 @@ static int ntfs_file_fsync(struct file *filp, int datasync)
        else
                ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx.  Error "
                                "%u.", datasync ? "data" : "", vi->i_ino, -ret);
+       mutex_unlock(&vi->i_mutex);
        return ret;
 }
 
index 22d60460195754e8fba94e55e05e97670fb7d0fd..0fc2bd34039dafd8d05e4bbe89885afbe11167af 100644 (file)
@@ -171,7 +171,8 @@ static int ocfs2_dir_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int ocfs2_sync_file(struct file *file, int datasync)
+static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end,
+                          int datasync)
 {
        int err = 0;
        journal_t *journal;
@@ -184,6 +185,16 @@ static int ocfs2_sync_file(struct file *file, int datasync)
                              file->f_path.dentry->d_name.name,
                              (unsigned long long)datasync);
 
+       err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (err)
+               return err;
+
+       /*
+        * Probably don't need the i_mutex at all in here, just putting it here
+        * to be consistent with how fsync used to be called, someone more
+        * familiar with the fs could possibly remove it.
+        */
+       mutex_lock(&inode->i_mutex);
        if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) {
                /*
                 * We still have to flush drive's caches to get data to the
@@ -200,6 +211,7 @@ static int ocfs2_sync_file(struct file *file, int datasync)
 bail:
        if (err)
                mlog_errno(err);
+       mutex_unlock(&inode->i_mutex);
 
        return (err < 0) ? -EIO : 0;
 }
index 198dabf1b2bbd7c8964194fe4340d5a12161bb4b..133e9355dc6f3c07227f95400de82c4821d4a4ae 100644 (file)
@@ -14,7 +14,8 @@
 extern const struct reiserfs_key MIN_KEY;
 
 static int reiserfs_readdir(struct file *, void *, filldir_t);
-static int reiserfs_dir_fsync(struct file *filp, int datasync);
+static int reiserfs_dir_fsync(struct file *filp, loff_t start, loff_t end,
+                             int datasync);
 
 const struct file_operations reiserfs_dir_operations = {
        .llseek = generic_file_llseek,
@@ -27,13 +28,21 @@ const struct file_operations reiserfs_dir_operations = {
 #endif
 };
 
-static int reiserfs_dir_fsync(struct file *filp, int datasync)
+static int reiserfs_dir_fsync(struct file *filp, loff_t start, loff_t end,
+                             int datasync)
 {
        struct inode *inode = filp->f_mapping->host;
        int err;
+
+       err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (err)
+               return err;
+
+       mutex_lock(&inode->i_mutex);
        reiserfs_write_lock(inode->i_sb);
        err = reiserfs_commit_for_inode(inode);
        reiserfs_write_unlock(inode->i_sb);
+       mutex_unlock(&inode->i_mutex);
        if (err < 0)
                return err;
        return 0;
index bbf31003d308824791c206951e86539ffe5301d7..c7156dc39ce7946b806e210dd0c4382cb1313185 100644 (file)
@@ -140,12 +140,18 @@ static void reiserfs_vfs_truncate_file(struct inode *inode)
  * be removed...
  */
 
-static int reiserfs_sync_file(struct file *filp, int datasync)
+static int reiserfs_sync_file(struct file *filp, loff_t start, loff_t end,
+                             int datasync)
 {
        struct inode *inode = filp->f_mapping->host;
        int err;
        int barrier_done;
 
+       err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (err)
+               return err;
+
+       mutex_lock(&inode->i_mutex);
        BUG_ON(!S_ISREG(inode->i_mode));
        err = sync_mapping_buffers(inode->i_mapping);
        reiserfs_write_lock(inode->i_sb);
@@ -153,6 +159,7 @@ static int reiserfs_sync_file(struct file *filp, int datasync)
        reiserfs_write_unlock(inode->i_sb);
        if (barrier_done != 1 && reiserfs_barrier_flush(inode->i_sb))
                blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
+       mutex_unlock(&inode->i_mutex);
        if (barrier_done < 0)
                return barrier_done;
        return (err < 0) ? -EIO : 0;
index c38ec163da6ccba00a0146c75606c1b548b31343..c98a7477edfdc91eec85602fe1a68d6dade4c9c6 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -165,28 +165,9 @@ SYSCALL_DEFINE1(syncfs, int, fd)
  */
 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);
 
index 5e7fccfc4b29d0c7eab7481ff1c89a5213c548df..89ef9a2f783727fa96dba511f2f68cb968e1ae78 100644 (file)
@@ -1304,7 +1304,7 @@ static void *ubifs_follow_link(struct dentry *dentry, struct nameidata *nd)
        return NULL;
 }
 
-int ubifs_fsync(struct file *file, int datasync)
+int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
        struct ubifs_info *c = inode->i_sb->s_fs_info;
@@ -1319,14 +1319,16 @@ int ubifs_fsync(struct file *file, int datasync)
                 */
                return 0;
 
-       /*
-        * VFS has already synchronized dirty pages for this inode. Synchronize
-        * the inode unless this is a 'datasync()' call.
-        */
+       err = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (err)
+               return err;
+       mutex_lock(&inode->i_mutex);
+
+       /* Synchronize the inode unless this is a 'datasync()' call. */
        if (!datasync || (inode->i_state & I_DIRTY_DATASYNC)) {
                err = inode->i_sb->s_op->write_inode(inode, NULL);
                if (err)
-                       return err;
+                       goto out;
        }
 
        /*
@@ -1334,10 +1336,9 @@ int ubifs_fsync(struct file *file, int datasync)
         * them.
         */
        err = ubifs_sync_wbufs_by_inode(c, inode);
-       if (err)
-               return err;
-
-       return 0;
+out:
+       mutex_unlock(&inode->i_mutex);
+       return err;
 }
 
 /**
index f79983d6f860eb43ec766dab9b6b044f1e23dd7b..4cd648501fa41848a1de95b3d95d622b5a07f3d2 100644 (file)
@@ -1720,7 +1720,7 @@ const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c);
 int ubifs_calc_dark(const struct ubifs_info *c, int spc);
 
 /* file.c */
-int ubifs_fsync(struct file *file, int datasync);
+int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync);
 int ubifs_setattr(struct dentry *dentry, struct iattr *attr);
 
 /* dir.c */
index 7f782af286bfa0edd73a125cdcb892339025913a..fbbf657df0cd581f0979dba3744295ecfe087813 100644 (file)
@@ -127,6 +127,8 @@ xfs_iozero(
 STATIC int
 xfs_file_fsync(
        struct file             *file,
+       loff_t                  start,
+       loff_t                  end,
        int                     datasync)
 {
        struct inode            *inode = file->f_mapping->host;
@@ -138,6 +140,10 @@ xfs_file_fsync(
 
        trace_xfs_file_fsync(ip);
 
+       error = filemap_write_and_wait_range(inode->i_mapping, start, end);
+       if (error)
+               return error;
+
        if (XFS_FORCED_SHUTDOWN(mp))
                return -XFS_ERROR(EIO);
 
@@ -875,18 +881,11 @@ xfs_file_aio_write(
        /* Handle various SYNC-type writes */
        if ((file->f_flags & O_DSYNC) || IS_SYNC(inode)) {
                loff_t end = pos + ret - 1;
-               int error, error2;
 
                xfs_rw_iunlock(ip, iolock);
-               error = filemap_write_and_wait_range(mapping, pos, end);
+               ret = -xfs_file_fsync(file, pos, end,
+                                     (file->f_flags & __O_SYNC) ? 0 : 1);
                xfs_rw_ilock(ip, iolock);
-
-               error2 = -xfs_file_fsync(file,
-                                        (file->f_flags & __O_SYNC) ? 0 : 1);
-               if (error)
-                       ret = error;
-               else if (error2)
-                       ret = error2;
        }
 
 out_unlock:
index 5e06acf95d0f84271b637f41711749c6968a32b4..0c473fd79acb4f0ae9ca4b41637fc1e8133b21de 100644 (file)
@@ -877,7 +877,7 @@ extern int ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
 extern void ext3_htree_free_dir_info(struct dir_private_info *p);
 
 /* fsync.c */
-extern int ext3_sync_file(struct file *, int);
+extern int ext3_sync_file(struct file *, loff_t, loff_t, int);
 
 /* hash.c */
 extern int ext3fs_dirhash(const char *name, int len, struct
index 6a8274877171aa7959cb95e5370ccc49a626d665..1d6836c498ddc626dab613da7099aed0244a1e17 100644 (file)
@@ -1043,7 +1043,8 @@ extern void fb_deferred_io_open(struct fb_info *info,
                                struct inode *inode,
                                struct file *file);
 extern void fb_deferred_io_cleanup(struct fb_info *info);
-extern int fb_deferred_io_fsync(struct file *file, int datasync);
+extern int fb_deferred_io_fsync(struct file *file, loff_t start,
+                               loff_t end, int datasync);
 
 static inline bool fb_be_math(struct fb_info *info)
 {
index 4a61f98823a6edb581c61d10f015b33aeb1d0599..9cd2075c4a3924a23573ae200dbc639ce17fffe9 100644 (file)
@@ -1572,7 +1572,7 @@ struct file_operations {
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *, fl_owner_t id);
        int (*release) (struct inode *, struct file *);
-       int (*fsync) (struct file *, int datasync);
+       int (*fsync) (struct file *, loff_t, loff_t, int datasync);
        int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
@@ -2360,7 +2360,8 @@ extern int generic_segment_checks(const struct iovec *iov,
 /* fs/block_dev.c */
 extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
                                unsigned long nr_segs, loff_t pos);
-extern int blkdev_fsync(struct file *filp, int datasync);
+extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end,
+                       int datasync);
 
 /* fs/splice.c */
 extern ssize_t generic_file_splice_read(struct file *, loff_t *,
@@ -2490,7 +2491,7 @@ extern int simple_link(struct dentry *, struct inode *, struct dentry *);
 extern int simple_unlink(struct inode *, struct dentry *);
 extern int simple_rmdir(struct inode *, struct dentry *);
 extern int simple_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
-extern int noop_fsync(struct file *, int);
+extern int noop_fsync(struct file *, loff_t, loff_t, int);
 extern int simple_empty(struct dentry *);
 extern int simple_readpage(struct file *file, struct page *page);
 extern int simple_write_begin(struct file *file, struct address_space *mapping,
@@ -2515,7 +2516,7 @@ extern ssize_t simple_read_from_buffer(void __user *to, size_t count,
 extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
                const void __user *from, size_t count);
 
-extern int generic_file_fsync(struct file *, int);
+extern int generic_file_fsync(struct file *, loff_t, loff_t, int);
 
 extern int generic_check_addressable(unsigned, u64);
 
index ab3385a21b27ac9b528ea270f2d4567522d2c966..27884adb1a9072b6bea5caabdee25cf5b14a8465 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -277,13 +277,13 @@ static int shm_release(struct inode *ino, struct file *file)
        return 0;
 }
 
-static int shm_fsync(struct file *file, int datasync)
+static int shm_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct shm_file_data *sfd = shm_file_data(file);
 
        if (!sfd->file->f_op->fsync)
                return -EINVAL;
-       return sfd->file->f_op->fsync(sfd->file, datasync);
+       return sfd->file->f_op->fsync(sfd->file, start, end, datasync);
 }
 
 static unsigned long shm_get_unmapped_area(struct file *file,