aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRavishankar N <ravishankar@redhat.com>2015-06-30 14:10:22 -0400
committerMiklos Szeredi <miklos@szeredi.hu>2015-11-10 04:32:37 -0500
commit0b5da8db145bfd44266ac964a2636a0cf8d7c286 (patch)
tree23e46abfcb58f4b744aeab42a8c3a62e141b399b
parent3ca8138f014a913f98e6ef40e939868e1e9ea876 (diff)
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: Ravishankar N <ravishankar@redhat.com> Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
-rw-r--r--fs/fuse/file.c73
-rw-r--r--fs/fuse/fuse_i.h3
-rw-r--r--include/uapi/linux/fuse.h17
3 files changed, 84 insertions, 9 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 195476a24148..47f181191060 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -2231,20 +2231,77 @@ static sector_t fuse_bmap(struct address_space *mapping, sector_t block)
2231 return err ? 0 : outarg.block; 2231 return err ? 0 : outarg.block;
2232} 2232}
2233 2233
2234static loff_t fuse_lseek(struct file *file, loff_t offset, int whence)
2235{
2236 struct inode *inode = file->f_mapping->host;
2237 struct fuse_conn *fc = get_fuse_conn(inode);
2238 struct fuse_file *ff = file->private_data;
2239 FUSE_ARGS(args);
2240 struct fuse_lseek_in inarg = {
2241 .fh = ff->fh,
2242 .offset = offset,
2243 .whence = whence
2244 };
2245 struct fuse_lseek_out outarg;
2246 int err;
2247
2248 if (fc->no_lseek)
2249 goto fallback;
2250
2251 args.in.h.opcode = FUSE_LSEEK;
2252 args.in.h.nodeid = ff->nodeid;
2253 args.in.numargs = 1;
2254 args.in.args[0].size = sizeof(inarg);
2255 args.in.args[0].value = &inarg;
2256 args.out.numargs = 1;
2257 args.out.args[0].size = sizeof(outarg);
2258 args.out.args[0].value = &outarg;
2259 err = fuse_simple_request(fc, &args);
2260 if (err) {
2261 if (err == -ENOSYS) {
2262 fc->no_lseek = 1;
2263 goto fallback;
2264 }
2265 return err;
2266 }
2267
2268 return vfs_setpos(file, outarg.offset, inode->i_sb->s_maxbytes);
2269
2270fallback:
2271 err = fuse_update_attributes(inode, NULL, file, NULL);
2272 if (!err)
2273 return generic_file_llseek(file, offset, whence);
2274 else
2275 return err;
2276}
2277
2234static loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence) 2278static loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence)
2235{ 2279{
2236 loff_t retval; 2280 loff_t retval;
2237 struct inode *inode = file_inode(file); 2281 struct inode *inode = file_inode(file);
2238 2282
2239 /* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */ 2283 switch (whence) {
2240 if (whence == SEEK_CUR || whence == SEEK_SET) 2284 case SEEK_SET:
2241 return generic_file_llseek(file, offset, whence); 2285 case SEEK_CUR:
2242 2286 /* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */
2243 mutex_lock(&inode->i_mutex);
2244 retval = fuse_update_attributes(inode, NULL, file, NULL);
2245 if (!retval)
2246 retval = generic_file_llseek(file, offset, whence); 2287 retval = generic_file_llseek(file, offset, whence);
2247 mutex_unlock(&inode->i_mutex); 2288 break;
2289 case SEEK_END:
2290 mutex_lock(&inode->i_mutex);
2291 retval = fuse_update_attributes(inode, NULL, file, NULL);
2292 if (!retval)
2293 retval = generic_file_llseek(file, offset, whence);
2294 mutex_unlock(&inode->i_mutex);
2295 break;
2296 case SEEK_HOLE:
2297 case SEEK_DATA:
2298 mutex_lock(&inode->i_mutex);
2299 retval = fuse_lseek(file, offset, whence);
2300 mutex_unlock(&inode->i_mutex);
2301 break;
2302 default:
2303 retval = -EINVAL;
2304 }
2248 2305
2249 return retval; 2306 return retval;
2250} 2307}
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 405113101db8..ce394b5fe6b4 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -605,6 +605,9 @@ struct fuse_conn {
605 /** Does the filesystem support asynchronous direct-IO submission? */ 605 /** Does the filesystem support asynchronous direct-IO submission? */
606 unsigned async_dio:1; 606 unsigned async_dio:1;
607 607
608 /** Is lseek not implemented by fs? */
609 unsigned no_lseek:1;
610
608 /** The number of requests waiting for completion */ 611 /** The number of requests waiting for completion */
609 atomic_t num_waiting; 612 atomic_t num_waiting;
610 613
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index c9aca042e61d..5974fae54e12 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -102,6 +102,9 @@
102 * - add ctime and ctimensec to fuse_setattr_in 102 * - add ctime and ctimensec to fuse_setattr_in
103 * - add FUSE_RENAME2 request 103 * - add FUSE_RENAME2 request
104 * - add FUSE_NO_OPEN_SUPPORT flag 104 * - add FUSE_NO_OPEN_SUPPORT flag
105 *
106 * 7.24
107 * - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support
105 */ 108 */
106 109
107#ifndef _LINUX_FUSE_H 110#ifndef _LINUX_FUSE_H
@@ -137,7 +140,7 @@
137#define FUSE_KERNEL_VERSION 7 140#define FUSE_KERNEL_VERSION 7
138 141
139/** Minor version number of this interface */ 142/** Minor version number of this interface */
140#define FUSE_KERNEL_MINOR_VERSION 23 143#define FUSE_KERNEL_MINOR_VERSION 24
141 144
142/** The node ID of the root inode */ 145/** The node ID of the root inode */
143#define FUSE_ROOT_ID 1 146#define FUSE_ROOT_ID 1
@@ -358,6 +361,7 @@ enum fuse_opcode {
358 FUSE_FALLOCATE = 43, 361 FUSE_FALLOCATE = 43,
359 FUSE_READDIRPLUS = 44, 362 FUSE_READDIRPLUS = 44,
360 FUSE_RENAME2 = 45, 363 FUSE_RENAME2 = 45,
364 FUSE_LSEEK = 46,
361 365
362 /* CUSE specific operations */ 366 /* CUSE specific operations */
363 CUSE_INIT = 4096, 367 CUSE_INIT = 4096,
@@ -758,4 +762,15 @@ struct fuse_notify_retrieve_in {
758/* Device ioctls: */ 762/* Device ioctls: */
759#define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t) 763#define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t)
760 764
765struct fuse_lseek_in {
766 uint64_t fh;
767 uint64_t offset;
768 uint32_t whence;
769 uint32_t padding;
770};
771
772struct fuse_lseek_out {
773 uint64_t offset;
774};
775
761#endif /* _LINUX_FUSE_H */ 776#endif /* _LINUX_FUSE_H */