Skip to content

Commit 0b5da8d

Browse files
itisraviszmi
authored andcommitted
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>
1 parent 3ca8138 commit 0b5da8d

File tree

3 files changed

+84
-9
lines changed

3 files changed

+84
-9
lines changed

fs/fuse/file.c

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2231,20 +2231,77 @@ static sector_t fuse_bmap(struct address_space *mapping, sector_t block)
22312231
return err ? 0 : outarg.block;
22322232
}
22332233

2234+
static 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+
2270+
fallback:
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+
22342278
static loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence)
22352279
{
22362280
loff_t retval;
22372281
struct inode *inode = file_inode(file);
22382282

2239-
/* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */
2240-
if (whence == SEEK_CUR || whence == SEEK_SET)
2241-
return generic_file_llseek(file, offset, whence);
2242-
2243-
mutex_lock(&inode->i_mutex);
2244-
retval = fuse_update_attributes(inode, NULL, file, NULL);
2245-
if (!retval)
2283+
switch (whence) {
2284+
case SEEK_SET:
2285+
case SEEK_CUR:
2286+
/* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */
22462287
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+
}
22482305

22492306
return retval;
22502307
}

fs/fuse/fuse_i.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,9 @@ struct fuse_conn {
605605
/** Does the filesystem support asynchronous direct-IO submission? */
606606
unsigned async_dio:1;
607607

608+
/** Is lseek not implemented by fs? */
609+
unsigned no_lseek:1;
610+
608611
/** The number of requests waiting for completion */
609612
atomic_t num_waiting;
610613

include/uapi/linux/fuse.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@
102102
* - add ctime and ctimensec to fuse_setattr_in
103103
* - add FUSE_RENAME2 request
104104
* - add FUSE_NO_OPEN_SUPPORT flag
105+
*
106+
* 7.24
107+
* - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support
105108
*/
106109

107110
#ifndef _LINUX_FUSE_H
@@ -137,7 +140,7 @@
137140
#define FUSE_KERNEL_VERSION 7
138141

139142
/** Minor version number of this interface */
140-
#define FUSE_KERNEL_MINOR_VERSION 23
143+
#define FUSE_KERNEL_MINOR_VERSION 24
141144

142145
/** The node ID of the root inode */
143146
#define FUSE_ROOT_ID 1
@@ -358,6 +361,7 @@ enum fuse_opcode {
358361
FUSE_FALLOCATE = 43,
359362
FUSE_READDIRPLUS = 44,
360363
FUSE_RENAME2 = 45,
364+
FUSE_LSEEK = 46,
361365

362366
/* CUSE specific operations */
363367
CUSE_INIT = 4096,
@@ -758,4 +762,15 @@ struct fuse_notify_retrieve_in {
758762
/* Device ioctls: */
759763
#define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t)
760764

765+
struct fuse_lseek_in {
766+
uint64_t fh;
767+
uint64_t offset;
768+
uint32_t whence;
769+
uint32_t padding;
770+
};
771+
772+
struct fuse_lseek_out {
773+
uint64_t offset;
774+
};
775+
761776
#endif /* _LINUX_FUSE_H */

0 commit comments

Comments
 (0)