fs: push i_mutex and filemap_write_and_wait down into ->fsync() handlers

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>
This commit is contained in:
Josef Bacik 2011-07-16 20:44:56 -04:00 committed by Al Viro
parent 22735068d5
commit 02c24a8218
71 changed files with 462 additions and 164 deletions

View 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.

View 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.

View 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 *);

View File

@ -1850,9 +1850,16 @@ static int spufs_mfc_flush(struct file *file, fl_owner_t id)
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)

View 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)

View 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;
}

View 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,

View 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;
}

View 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);

View 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);

View File

@ -519,32 +519,50 @@ v9fs_file_write(struct file *filp, const char __user * data,
}
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;
}

View 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 */

View 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;
}

View 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);
/*****************************************************************************/

View 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;
}

View 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;
}

View File

@ -378,7 +378,7 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin)
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);

View 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;

View 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;
}

View File

@ -1811,7 +1811,7 @@ static void sync_write_wait(struct inode *inode)
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;
}

View 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;
}

View 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,

View 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 *);

View 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;
}

View 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);

View 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;
}

View 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;
}

View 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;
}

View 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;

View 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__,

View 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;
}

View 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 */

View 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;
}

View 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);

View 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;

View 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)

View 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,

View 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

View 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;
}

View 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;
}

View 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);

View 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;
}

View File

@ -362,9 +362,20 @@ int hostfs_file_open(struct inode *ino, struct file *file)
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 = {

View 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);
}

View 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;

View 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 = {

View 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;
}

View 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 */

View File

@ -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;
}

View 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);

View 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;
}

View 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;
}

View 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);

View 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);
}
/*

View 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 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
* 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;
}

View 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;
}

View 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;
}

View 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);

View 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;
}

View 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;
}

View 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;
}

View 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;

View 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;

View File

@ -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);

View 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;
}
/**

View 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 */

View 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:

View 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

View 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)
{

View 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);

View File

@ -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,