Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757611Ab1F2T0V (ORCPT ); Wed, 29 Jun 2011 15:26:21 -0400 Received: from cantor2.suse.de ([195.135.220.15]:55141 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757471Ab1F2T0S (ORCPT ); Wed, 29 Jun 2011 15:26:18 -0400 Date: Wed, 29 Jun 2011 21:26:10 +0200 From: Jan Kara To: Josef Bacik Cc: linux-fsdevel@vger.kernel.org, hch@infradead.org, viro@zeniv.linux.org.uk, jack@suse.cz, linux-kernel@vger.kernel.org Subject: Re: [PATCH] fs: push i_mutex and filemap_write_and_wait down into ->fsync() handlers Message-ID: <20110629192610.GB23196@quack.suse.cz> References: <1309370716-12235-1-git-send-email-josef@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1309370716-12235-1-git-send-email-josef@redhat.com> User-Agent: Mutt/1.5.20 (2009-06-14) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 66287 Lines: 1903 On Wed 29-06-11 14:05:16, Josef Bacik wrote: > 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, The patch looks OK now AFAICT (I've checked ext2, ext3, ext4, reiserfs, ocfs2, and the generic code). You can add: Acked-by: Jan Kara Honza > Signed-off-by: Josef Bacik > --- > Documentation/filesystems/vfs.txt | 2 +- > fs/9p/v9fs_vfs.h | 3 +- > fs/9p/vfs_file.c | 22 +++++++++++++++++++- > fs/affs/affs.h | 2 +- > fs/affs/file.c | 8 ++++++- > fs/afs/internal.h | 2 +- > fs/afs/write.c | 18 +++++++++++++--- > fs/bad_inode.c | 3 +- > fs/block_dev.c | 6 +---- > fs/btrfs/ctree.h | 2 +- > fs/btrfs/file.c | 21 ++++++++++++++----- > fs/ceph/caps.c | 6 +++- > fs/ceph/dir.c | 10 ++++++++- > fs/ceph/super.h | 3 +- > fs/cifs/cifsfs.h | 4 +- > fs/cifs/file.c | 18 +++++++++++++++- > fs/coda/coda_int.h | 2 +- > fs/coda/file.c | 8 ++++++- > fs/ecryptfs/file.c | 7 +++-- > fs/exofs/file.c | 10 ++++++++- > fs/ext2/ext2.h | 3 +- > fs/ext2/file.c | 4 +- > fs/ext3/fsync.c | 18 +++++++++++++++- > fs/ext4/ext4.h | 2 +- > fs/ext4/fsync.c | 38 ++++++++++++++++++++++++++++++++++-- > fs/fat/fat.h | 3 +- > fs/fat/file.c | 4 +- > fs/fuse/dir.c | 5 ++- > fs/fuse/file.c | 24 +++++++++++++++++----- > fs/fuse/fuse_i.h | 3 +- > fs/gfs2/file.c | 17 +++++++++++++-- > fs/hfs/inode.c | 9 +++++++- > fs/hfsplus/hfsplus_fs.h | 3 +- > fs/hfsplus/inode.c | 10 ++++++++- > fs/hostfs/hostfs_kern.c | 15 ++++++++++++- > fs/hpfs/file.c | 7 +++++- > fs/hpfs/hpfs_fn.h | 2 +- > fs/hppfs/hppfs.c | 5 ++- > fs/jffs2/file.c | 9 +++++++- > fs/jffs2/os-linux.h | 2 +- > fs/jfs/file.c | 9 +++++++- > fs/jfs/jfs_inode.h | 2 +- > fs/libfs.c | 16 +++++++++++--- > fs/logfs/file.c | 11 +++++++++- > fs/logfs/logfs.h | 2 +- > fs/ncpfs/file.c | 4 +- > fs/nfs/dir.c | 8 +++++- > fs/nfs/file.c | 11 +++++++-- > fs/nilfs2/file.c | 12 +++++++++- > fs/nilfs2/nilfs.h | 2 +- > fs/ntfs/dir.c | 10 ++++++++- > fs/ntfs/file.c | 10 ++++++++- > fs/ocfs2/file.c | 14 ++++++++++++- > fs/reiserfs/dir.c | 13 ++++++++++- > fs/reiserfs/file.c | 9 +++++++- > fs/sync.c | 25 ++--------------------- > fs/ubifs/file.c | 21 ++++++++++--------- > fs/ubifs/ubifs.h | 2 +- > fs/xfs/linux-2.6/xfs_file.c | 16 +++++++++++++- > include/linux/ext3_fs.h | 2 +- > include/linux/fs.h | 9 ++++--- > ipc/shm.c | 4 +- > 62 files changed, 413 insertions(+), 139 deletions(-) > > diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt > index 88b9f55..cdb7315 100644 > --- a/Documentation/filesystems/vfs.txt > +++ b/Documentation/filesystems/vfs.txt > @@ -755,7 +755,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 *); > diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h > index 4014160..46ce357 100644 > --- a/fs/9p/v9fs_vfs.h > +++ b/fs/9p/v9fs_vfs.h > @@ -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); > diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c > index ffed558..3c173fc 100644 > --- a/fs/9p/vfs_file.c > +++ b/fs/9p/vfs_file.c > @@ -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; > } > > diff --git a/fs/affs/affs.h b/fs/affs/affs.h > index 0e95f73..c2b9c79 100644 > --- a/fs/affs/affs.h > +++ b/fs/affs/affs.h > @@ -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 */ > > diff --git a/fs/affs/file.c b/fs/affs/file.c > index acf321b..2f4c935 100644 > --- a/fs/affs/file.c > +++ b/fs/affs/file.c > @@ -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; > } > diff --git a/fs/afs/internal.h b/fs/afs/internal.h > index 5a9b684..fe85208 100644 > --- a/fs/afs/internal.h > +++ b/fs/afs/internal.h > @@ -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); > > > /*****************************************************************************/ > diff --git a/fs/afs/write.c b/fs/afs/write.c > index b806285..9aa52d9 100644 > --- a/fs/afs/write.c > +++ b/fs/afs/write.c > @@ -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; > } > > diff --git a/fs/bad_inode.c b/fs/bad_inode.c > index bfcb18f..b00e563 100644 > --- a/fs/bad_inode.c > +++ b/fs/bad_inode.c > @@ -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; > } > diff --git a/fs/block_dev.c b/fs/block_dev.c > index 966617a..9fb0b15 100644 > --- a/fs/block_dev.c > +++ b/fs/block_dev.c > @@ -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); > diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h > index eeae8f0..ae9560a 100644 > --- a/fs/btrfs/ctree.h > +++ b/fs/btrfs/ctree.h > @@ -2600,7 +2600,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; > diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c > index bd4d061..59cbdb1 100644 > --- a/fs/btrfs/file.c > +++ b/fs/btrfs/file.c > @@ -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; > } > diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c > index f605753..8d74ad7 100644 > --- a/fs/ceph/caps.c > +++ b/fs/ceph/caps.c > @@ -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; > } > > diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c > index 79cd77c..9f8dd05 100644 > --- a/fs/ceph/dir.c > +++ b/fs/ceph/dir.c > @@ -1119,7 +1119,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); > @@ -1129,6 +1130,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; > @@ -1162,6 +1168,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; > } > > diff --git a/fs/ceph/super.h b/fs/ceph/super.h > index f5cabef..b95cf3d 100644 > --- a/fs/ceph/super.h > +++ b/fs/ceph/super.h > @@ -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, > diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h > index 0900e16..1686b0a 100644 > --- a/fs/cifs/cifsfs.h > +++ b/fs/cifs/cifsfs.h > @@ -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 *); > diff --git a/fs/cifs/file.c b/fs/cifs/file.c > index bb71471..cef58445 100644 > --- a/fs/cifs/file.c > +++ b/fs/cifs/file.c > @@ -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; > } > > diff --git a/fs/coda/coda_int.h b/fs/coda/coda_int.h > index 6b443ff..b7143cf 100644 > --- a/fs/coda/coda_int.h > +++ b/fs/coda/coda_int.h > @@ -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); > > diff --git a/fs/coda/file.c b/fs/coda/file.c > index 0433057..8edd404 100644 > --- a/fs/coda/file.c > +++ b/fs/coda/file.c > @@ -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; > } > diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c > index 4ec9eb0..c6ac98c 100644 > --- a/fs/ecryptfs/file.c > +++ b/fs/ecryptfs/file.c > @@ -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; > } > diff --git a/fs/exofs/file.c b/fs/exofs/file.c > index 45ca323..491c6c0 100644 > --- a/fs/exofs/file.c > +++ b/fs/exofs/file.c > @@ -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; > } > > diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h > index 645be9e..af9fc89 100644 > --- a/fs/ext2/ext2.h > +++ b/fs/ext2/ext2.h > @@ -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; > diff --git a/fs/ext2/file.c b/fs/ext2/file.c > index 49eec94..82e0632 100644 > --- a/fs/ext2/file.c > +++ b/fs/ext2/file.c > @@ -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__, > diff --git a/fs/ext3/fsync.c b/fs/ext3/fsync.c > index 09b13bb..0bcf63a 100644 > --- a/fs/ext3/fsync.c > +++ b/fs/ext3/fsync.c > @@ -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; > } > diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h > index 1921392..fa44df8 100644 > --- a/fs/ext4/ext4.h > +++ b/fs/ext4/ext4.h > @@ -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 */ > diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c > index ce66d2f..da3bed3 100644 > --- a/fs/ext4/fsync.c > +++ b/fs/ext4/fsync.c > @@ -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; > } > diff --git a/fs/fat/fat.h b/fs/fat/fat.h > index 8276cc2..8b7d322 100644 > --- a/fs/fat/fat.h > +++ b/fs/fat/fat.h > @@ -309,7 +309,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); > diff --git a/fs/fat/file.c b/fs/fat/file.c > index 7018e1d..24bc5df 100644 > --- a/fs/fat/file.c > +++ b/fs/fat/file.c > @@ -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; > diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c > index d5016071..709b9a1 100644 > --- a/fs/fuse/dir.c > +++ b/fs/fuse/dir.c > @@ -1177,9 +1177,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) > diff --git a/fs/fuse/file.c b/fs/fuse/file.c > index 73b89df..7bb685c 100644 > --- a/fs/fuse/file.c > +++ b/fs/fuse/file.c > @@ -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, > diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h > index b788bec..c6aa2d4 100644 > --- a/fs/fuse/fuse_i.h > +++ b/fs/fuse/fuse_i.h > @@ -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 > diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c > index a9f5cbe..83cdb24 100644 > --- a/fs/gfs2/file.c > +++ b/fs/gfs2/file.c > @@ -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; > } > > diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c > index fff16c9..ce3f575 100644 > --- a/fs/hfs/inode.c > +++ b/fs/hfs/inode.c > @@ -625,12 +625,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); > > @@ -647,6 +653,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; > } > > diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h > index d685752..38184e3 100644 > --- a/fs/hfsplus/hfsplus_fs.h > +++ b/fs/hfsplus/hfsplus_fs.h > @@ -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); > diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c > index b248a6c..43e846b 100644 > --- a/fs/hfsplus/inode.c > +++ b/fs/hfsplus/inode.c > @@ -306,13 +306,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. > */ > @@ -340,6 +346,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; > } > > diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c > index 2638c834e..1efb31c 100644 > --- a/fs/hostfs/hostfs_kern.c > +++ b/fs/hostfs/hostfs_kern.c > @@ -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 = { > diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c > index 89c500e..89d2a58 100644 > --- a/fs/hpfs/file.c > +++ b/fs/hpfs/file.c > @@ -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); > } > > diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h > index dd552f8..331b5e2 100644 > --- a/fs/hpfs/hpfs_fn.h > +++ b/fs/hpfs/hpfs_fn.h > @@ -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; > diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c > index 87ed48e..44a3ebc 100644 > --- a/fs/hppfs/hppfs.c > +++ b/fs/hppfs/hppfs.c > @@ -588,9 +588,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 = { > diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c > index 1c0a08d..3989f7e 100644 > --- a/fs/jffs2/file.c > +++ b/fs/jffs2/file.c > @@ -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; > } > diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h > index 65c6c43..9c25283 100644 > --- a/fs/jffs2/os-linux.h > +++ b/fs/jffs2/os-linux.h > @@ -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 */ > diff --git a/fs/jfs/file.c b/fs/jfs/file.c > index 2f3f531..a6b0c2c 100644 > --- a/fs/jfs/file.c > +++ b/fs/jfs/file.c > @@ -28,19 +28,26 @@ > #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; > } > diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h > index ec2fb8b..9271cfe 100644 > --- a/fs/jfs/jfs_inode.h > +++ b/fs/jfs/jfs_inode.h > @@ -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); > diff --git a/fs/libfs.c b/fs/libfs.c > index c88eab5..02c94e7 100644 > --- a/fs/libfs.c > +++ b/fs/libfs.c > @@ -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; > } > diff --git a/fs/logfs/file.c b/fs/logfs/file.c > index c2ad702..b548c87 100644 > --- a/fs/logfs/file.c > +++ b/fs/logfs/file.c > @@ -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; > } > > diff --git a/fs/logfs/logfs.h b/fs/logfs/logfs.h > index 57afd4a..f22d108 100644 > --- a/fs/logfs/logfs.h > +++ b/fs/logfs/logfs.h > @@ -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); > diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c > index 0ed65e0..64a3264 100644 > --- a/fs/ncpfs/file.c > +++ b/fs/ncpfs/file.c > @@ -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); > } > > /* > diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c > index ededdbd..645c2e2 100644 > --- a/fs/nfs/dir.c > +++ b/fs/nfs/dir.c > @@ -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; > } > > diff --git a/fs/nfs/file.c b/fs/nfs/file.c > index 2c1705b..28b8c3f 100644 > --- a/fs/nfs/file.c > +++ b/fs/nfs/file.c > @@ -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; > } > > diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c > index d7eeca6..2660152 100644 > --- a/fs/nilfs2/file.c > +++ b/fs/nilfs2/file.c > @@ -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; > } > > diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h > index f02b9ad..eeaff83 100644 > --- a/fs/nilfs2/nilfs.h > +++ b/fs/nilfs2/nilfs.h > @@ -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); > diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c > index 0f48e7c..99e3610 100644 > --- a/fs/ntfs/dir.c > +++ b/fs/ntfs/dir.c > @@ -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; > } > > diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c > index f4b1057..c404ad0 100644 > --- a/fs/ntfs/file.c > +++ b/fs/ntfs/file.c > @@ -2153,12 +2153,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); > @@ -2176,6 +2183,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; > } > > diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c > index b1e35a3..b1c3c57 100644 > --- a/fs/ocfs2/file.c > +++ b/fs/ocfs2/file.c > @@ -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; > } > diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c > index 198dabf..133e935 100644 > --- a/fs/reiserfs/dir.c > +++ b/fs/reiserfs/dir.c > @@ -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; > diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c > index 91f080c..1a23e1e 100644 > --- a/fs/reiserfs/file.c > +++ b/fs/reiserfs/file.c > @@ -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; > diff --git a/fs/sync.c b/fs/sync.c > index c38ec16..c98a747 100644 > --- 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); > > diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c > index 5e7fccf..89ef9a2 100644 > --- a/fs/ubifs/file.c > +++ b/fs/ubifs/file.c > @@ -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; > } > > /** > diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h > index f79983d..4cd6485 100644 > --- a/fs/ubifs/ubifs.h > +++ b/fs/ubifs/ubifs.h > @@ -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 */ > diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c > index 7f782af..9183f75 100644 > --- a/fs/xfs/linux-2.6/xfs_file.c > +++ b/fs/xfs/linux-2.6/xfs_file.c > @@ -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,8 +140,16 @@ xfs_file_fsync( > > trace_xfs_file_fsync(ip); > > - if (XFS_FORCED_SHUTDOWN(mp)) > + error = filemap_write_and_wait_range(inode->i_mapping, start, end); > + if (error) > + return error; > + > + mutex_lock(&inode->i_mutex); > + > + if (XFS_FORCED_SHUTDOWN(mp)) { > + mutex_unlock(&inode->i_mutex); > return -XFS_ERROR(EIO); > + } > > xfs_iflags_clear(ip, XFS_ITRUNCATED); > > @@ -195,6 +205,7 @@ xfs_file_fsync( > XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0); > if (error) { > xfs_trans_cancel(tp, 0); > + mutex_unlock(&inode->i_mutex); > return -error; > } > xfs_ilock(ip, XFS_ILOCK_EXCL); > @@ -244,6 +255,7 @@ xfs_file_fsync( > !log_flushed) > xfs_blkdev_issue_flush(mp->m_ddev_targp); > > + mutex_unlock(&inode->i_mutex); > return -error; > } > > @@ -881,7 +893,7 @@ xfs_file_aio_write( > error = filemap_write_and_wait_range(mapping, pos, end); > xfs_rw_ilock(ip, iolock); > > - error2 = -xfs_file_fsync(file, > + error2 = -xfs_file_fsync(file, pos, end, > (file->f_flags & __O_SYNC) ? 0 : 1); > if (error) > ret = error; > diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h > index 5e06acf..0c473fd 100644 > --- a/include/linux/ext3_fs.h > +++ b/include/linux/ext3_fs.h > @@ -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 > diff --git a/include/linux/fs.h b/include/linux/fs.h > index c9156f3..8d3e50e 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -1560,7 +1560,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 *); > @@ -2319,7 +2319,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 *, > @@ -2446,7 +2447,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, > @@ -2471,7 +2472,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); > > diff --git a/ipc/shm.c b/ipc/shm.c > index ab3385a..27884ad 100644 > --- 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, > -- > 1.7.5.2 > -- Jan Kara SUSE Labs, CR -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/