Commit 0b5da8db authored by Ravishankar N's avatar Ravishankar N Committed by Miklos Szeredi

fuse: add support for SEEK_HOLE and SEEK_DATA in lseek

A useful performance improvement for accessing virtual machine images
via FUSE mount.

See https://bugzilla.redhat.com/show_bug.cgi?id=1220173 for a use-case
for glusterFS.
Signed-off-by: default avatarRavishankar N <ravishankar@redhat.com>
Signed-off-by: default avatarMiklos Szeredi <miklos@szeredi.hu>
parent 3ca8138f
...@@ -2231,20 +2231,77 @@ static sector_t fuse_bmap(struct address_space *mapping, sector_t block) ...@@ -2231,20 +2231,77 @@ static sector_t fuse_bmap(struct address_space *mapping, sector_t block)
return err ? 0 : outarg.block; return err ? 0 : outarg.block;
} }
static loff_t fuse_lseek(struct file *file, loff_t offset, int whence)
{
struct inode *inode = file->f_mapping->host;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_file *ff = file->private_data;
FUSE_ARGS(args);
struct fuse_lseek_in inarg = {
.fh = ff->fh,
.offset = offset,
.whence = whence
};
struct fuse_lseek_out outarg;
int err;
if (fc->no_lseek)
goto fallback;
args.in.h.opcode = FUSE_LSEEK;
args.in.h.nodeid = ff->nodeid;
args.in.numargs = 1;
args.in.args[0].size = sizeof(inarg);
args.in.args[0].value = &inarg;
args.out.numargs = 1;
args.out.args[0].size = sizeof(outarg);
args.out.args[0].value = &outarg;
err = fuse_simple_request(fc, &args);
if (err) {
if (err == -ENOSYS) {
fc->no_lseek = 1;
goto fallback;
}
return err;
}
return vfs_setpos(file, outarg.offset, inode->i_sb->s_maxbytes);
fallback:
err = fuse_update_attributes(inode, NULL, file, NULL);
if (!err)
return generic_file_llseek(file, offset, whence);
else
return err;
}
static loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence) static loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence)
{ {
loff_t retval; loff_t retval;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
/* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */ switch (whence) {
if (whence == SEEK_CUR || whence == SEEK_SET) case SEEK_SET:
return generic_file_llseek(file, offset, whence); case SEEK_CUR:
/* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */
mutex_lock(&inode->i_mutex);
retval = fuse_update_attributes(inode, NULL, file, NULL);
if (!retval)
retval = generic_file_llseek(file, offset, whence); retval = generic_file_llseek(file, offset, whence);
mutex_unlock(&inode->i_mutex); break;
case SEEK_END:
mutex_lock(&inode->i_mutex);
retval = fuse_update_attributes(inode, NULL, file, NULL);
if (!retval)
retval = generic_file_llseek(file, offset, whence);
mutex_unlock(&inode->i_mutex);
break;
case SEEK_HOLE:
case SEEK_DATA:
mutex_lock(&inode->i_mutex);
retval = fuse_lseek(file, offset, whence);
mutex_unlock(&inode->i_mutex);
break;
default:
retval = -EINVAL;
}
return retval; return retval;
} }
......
...@@ -605,6 +605,9 @@ struct fuse_conn { ...@@ -605,6 +605,9 @@ struct fuse_conn {
/** Does the filesystem support asynchronous direct-IO submission? */ /** Does the filesystem support asynchronous direct-IO submission? */
unsigned async_dio:1; unsigned async_dio:1;
/** Is lseek not implemented by fs? */
unsigned no_lseek:1;
/** The number of requests waiting for completion */ /** The number of requests waiting for completion */
atomic_t num_waiting; atomic_t num_waiting;
......
...@@ -102,6 +102,9 @@ ...@@ -102,6 +102,9 @@
* - add ctime and ctimensec to fuse_setattr_in * - add ctime and ctimensec to fuse_setattr_in
* - add FUSE_RENAME2 request * - add FUSE_RENAME2 request
* - add FUSE_NO_OPEN_SUPPORT flag * - add FUSE_NO_OPEN_SUPPORT flag
*
* 7.24
* - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support
*/ */
#ifndef _LINUX_FUSE_H #ifndef _LINUX_FUSE_H
...@@ -137,7 +140,7 @@ ...@@ -137,7 +140,7 @@
#define FUSE_KERNEL_VERSION 7 #define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */ /** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 23 #define FUSE_KERNEL_MINOR_VERSION 24
/** The node ID of the root inode */ /** The node ID of the root inode */
#define FUSE_ROOT_ID 1 #define FUSE_ROOT_ID 1
...@@ -358,6 +361,7 @@ enum fuse_opcode { ...@@ -358,6 +361,7 @@ enum fuse_opcode {
FUSE_FALLOCATE = 43, FUSE_FALLOCATE = 43,
FUSE_READDIRPLUS = 44, FUSE_READDIRPLUS = 44,
FUSE_RENAME2 = 45, FUSE_RENAME2 = 45,
FUSE_LSEEK = 46,
/* CUSE specific operations */ /* CUSE specific operations */
CUSE_INIT = 4096, CUSE_INIT = 4096,
...@@ -758,4 +762,15 @@ struct fuse_notify_retrieve_in { ...@@ -758,4 +762,15 @@ struct fuse_notify_retrieve_in {
/* Device ioctls: */ /* Device ioctls: */
#define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t) #define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t)
struct fuse_lseek_in {
uint64_t fh;
uint64_t offset;
uint32_t whence;
uint32_t padding;
};
struct fuse_lseek_out {
uint64_t offset;
};
#endif /* _LINUX_FUSE_H */ #endif /* _LINUX_FUSE_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment