Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4c728ef5 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Al Viro
Browse files

add a vfs_fsync helper



Fsync currently has a fdatawrite/fdatawait pair around the method call,
and a mutex_lock/unlock of the inode mutex.  All callers of fsync have
to duplicate this, but we have a few and most of them don't quite get
it right.  This patch adds a new vfs_fsync that takes care of this.
It's a little more complicated as usual as ->fsync might get a NULL file
pointer and just a dentry from nfsd, but otherwise gets afile and we
want to take the mapping and file operations from it when it is there.

Notes on the fsync callers:

 - ecryptfs wasn't calling filemap_fdatawrite / filemap_fdatawait on the
   	lower file
 - coda wasn't calling filemap_fdatawrite / filemap_fdatawait on the host
	file, and returning 0 when ->fsync was missing
 - shm wasn't calling either filemap_fdatawrite / filemap_fdatawait nor
   taking i_mutex.  Now given that shared memory doesn't have disk
   backing not doing anything in fsync seems fine and I left it out of
   the vfs_fsync conversion for now, but in that case we might just
   not pass it through to the lower file at all but just call the no-op
   simple_sync_file directly.

[and now actually export vfs_fsync]

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 6110e3ab
Loading
Loading
Loading
Loading
+1 −17
Original line number Diff line number Diff line
@@ -1863,26 +1863,10 @@ static int do_write(struct fsg_dev *fsg)
static int fsync_sub(struct lun *curlun)
{
	struct file	*filp = curlun->filp;
	struct inode	*inode;
	int		rc, err;

	if (curlun->ro || !filp)
		return 0;
	if (!filp->f_op->fsync)
		return -EINVAL;

	inode = filp->f_path.dentry->d_inode;
	mutex_lock(&inode->i_mutex);
	rc = filemap_fdatawrite(inode->i_mapping);
	err = filp->f_op->fsync(filp, filp->f_path.dentry, 1);
	if (!rc)
		rc = err;
	err = filemap_fdatawait(inode->i_mapping);
	if (!rc)
		rc = err;
	mutex_unlock(&inode->i_mutex);
	VLDBG(curlun, "fdatasync -> %d\n", rc);
	return rc;
	return vfs_fsync(filp, filp->f_path.dentry, 1);
}

static void fsync_all(struct fsg_dev *fsg)
+2 −10
Original line number Diff line number Diff line
@@ -201,8 +201,7 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
{
	struct file *host_file;
	struct dentry *host_dentry;
	struct inode *host_inode, *coda_inode = coda_dentry->d_inode;
	struct inode *coda_inode = coda_dentry->d_inode;
	struct coda_file_info *cfi;
	int err = 0;

@@ -214,14 +213,7 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
	host_file = cfi->cfi_container;

	if (host_file->f_op && host_file->f_op->fsync) {
		host_dentry = host_file->f_path.dentry;
		host_inode = host_dentry->d_inode;
		mutex_lock(&host_inode->i_mutex);
		err = host_file->f_op->fsync(host_file, host_dentry, datasync);
		mutex_unlock(&host_inode->i_mutex);
	}

	err = vfs_fsync(host_file, host_file->f_path.dentry, datasync);
	if ( !err && !datasync ) {
		lock_kernel();
		err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
+3 −12
Original line number Diff line number Diff line
@@ -275,18 +275,9 @@ static int ecryptfs_release(struct inode *inode, struct file *file)
static int
ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync)
{
	struct file *lower_file = ecryptfs_file_to_lower(file);
	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
	struct inode *lower_inode = lower_dentry->d_inode;
	int rc = -EINVAL;

	if (lower_inode->i_fop->fsync) {
		mutex_lock(&lower_inode->i_mutex);
		rc = lower_inode->i_fop->fsync(lower_file, lower_dentry,
	return vfs_fsync(ecryptfs_file_to_lower(file),
			 ecryptfs_dentry_to_lower(dentry),
			 datasync);
		mutex_unlock(&lower_inode->i_mutex);
	}
	return rc;
}

static int ecryptfs_fasync(int fd, struct file *file, int flag)
+3 −32
Original line number Diff line number Diff line
@@ -744,45 +744,16 @@ nfsd_close(struct file *filp)
	fput(filp);
}

/*
 * Sync a file
 * As this calls fsync (not fdatasync) there is no need for a write_inode
 * after it.
 */
static inline int nfsd_dosync(struct file *filp, struct dentry *dp,
			      const struct file_operations *fop)
{
	struct inode *inode = dp->d_inode;
	int (*fsync) (struct file *, struct dentry *, int);
	int err;

	err = filemap_fdatawrite(inode->i_mapping);
	if (err == 0 && fop && (fsync = fop->fsync))
		err = fsync(filp, dp, 0);
	if (err == 0)
		err = filemap_fdatawait(inode->i_mapping);

	return err;
}
	

static int
nfsd_sync(struct file *filp)
{
        int err;
	struct inode *inode = filp->f_path.dentry->d_inode;
	dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name);
	mutex_lock(&inode->i_mutex);
	err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op);
	mutex_unlock(&inode->i_mutex);

	return err;
	return vfs_fsync(filp, filp->f_path.dentry, 0);
}

int
nfsd_sync_dir(struct dentry *dp)
nfsd_sync_dir(struct dentry *dentry)
{
	return nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
	return vfs_fsync(NULL, dentry, 0);
}

/*
+37 −11
Original line number Diff line number Diff line
@@ -75,14 +75,39 @@ int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
	return ret;
}

long do_fsync(struct file *file, int datasync)
/**
 * vfs_fsync - perform a fsync or fdatasync on a file
 * @file:		file to sync
 * @dentry:		dentry of @file
 * @data:		only perform a fdatasync operation
 *
 * Write back data and metadata for @file to disk.  If @datasync is
 * set only metadata needed to access modified file data is written.
 *
 * In case this function is called from nfsd @file may be %NULL and
 * only @dentry is set.  This can only happen when the filesystem
 * implements the export_operations API.
 */
int vfs_fsync(struct file *file, struct dentry *dentry, int datasync)
{
	int ret;
	int err;
	struct address_space *mapping = file->f_mapping;
	const struct file_operations *fop;
	struct address_space *mapping;
	int err, ret;

	/*
	 * Get mapping and operations from the file in case we have
	 * as file, or get the default values for them in case we
	 * don't have a struct file available.  Damn nfsd..
	 */
	if (file) {
		mapping = file->f_mapping;
		fop = file->f_op;
	} else {
		mapping = dentry->d_inode->i_mapping;
		fop = dentry->d_inode->i_fop;
	}

	if (!file->f_op || !file->f_op->fsync) {
		/* Why?  We can still call filemap_fdatawrite */
	if (!fop || !fop->fsync) {
		ret = -EINVAL;
		goto out;
	}
@@ -94,7 +119,7 @@ long do_fsync(struct file *file, int datasync)
	 * livelocks in fsync_buffers_list().
	 */
	mutex_lock(&mapping->host->i_mutex);
	err = file->f_op->fsync(file, file->f_path.dentry, datasync);
	err = fop->fsync(file, dentry, datasync);
	if (!ret)
		ret = err;
	mutex_unlock(&mapping->host->i_mutex);
@@ -104,15 +129,16 @@ long do_fsync(struct file *file, int datasync)
out:
	return ret;
}
EXPORT_SYMBOL(vfs_fsync);

static long __do_fsync(unsigned int fd, int datasync)
static int do_fsync(unsigned int fd, int datasync)
{
	struct file *file;
	int ret = -EBADF;

	file = fget(fd);
	if (file) {
		ret = do_fsync(file, datasync);
		ret = vfs_fsync(file, file->f_path.dentry, datasync);
		fput(file);
	}
	return ret;
@@ -120,12 +146,12 @@ static long __do_fsync(unsigned int fd, int datasync)

asmlinkage long sys_fsync(unsigned int fd)
{
	return __do_fsync(fd, 0);
	return do_fsync(fd, 0);
}

asmlinkage long sys_fdatasync(unsigned int fd)
{
	return __do_fsync(fd, 1);
	return do_fsync(fd, 1);
}

/*
Loading