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: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:

committed by
Al Viro

parent
6110e3abbf
commit
4c728ef583
48
fs/sync.c
48
fs/sync.c
@@ -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;
|
||||
|
||||
if (!file->f_op || !file->f_op->fsync) {
|
||||
/* Why? We can still call filemap_fdatawrite */
|
||||
/*
|
||||
* 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 (!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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user