fuse: add support for SEEK_HOLE and SEEK_DATA through lseek()

The Linux FUSE kernel module has gained support for passing SEEK_HOLE
and SEEK_DATA on through lseek(). This can greatly improve performance
when working with sparse files.

Linux FUSE introduced support for lseek() with version 4.5. The commit
in mainline Linux is 0b5da8db145bfd44266ac964a2636a0cf8d7c286.

URL: http://thread.gmane.org/gmane.comp.file-systems.fuse.devel/14752
Change-Id: I12496d788e59461a3023ddd30e0ea3179007f77e
BUG: 1220173
Signed-off-by: Ravishankar N <ravishankar@redhat.com>
Signed-off-by: Niels de Vos <ndevos@redhat.com>
Reviewed-on: http://review.gluster.org/11474
Smoke: Gluster Build System <jenkins@build.gluster.com>
CentOS-regression: Gluster Build System <jenkins@build.gluster.com>
NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
Reviewed-by: Raghavendra G <rgowdapp@redhat.com>
This commit is contained in:
Niels de Vos 2015-07-06 00:01:44 +02:00 committed by Raghavendra G
parent b8bd9a6e6e
commit e501a7da4c
3 changed files with 83 additions and 2 deletions

View File

@ -102,6 +102,9 @@
* - add ctime and ctimensec to fuse_setattr_in
* - add FUSE_RENAME2 request
* - add FUSE_NO_OPEN_SUPPORT flag
*
* 7.24
* - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support
*/
#ifndef _LINUX_FUSE_H
@ -137,7 +140,7 @@
#define FUSE_KERNEL_VERSION 7
/** 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 */
#define FUSE_ROOT_ID 1
@ -358,6 +361,7 @@ enum fuse_opcode {
FUSE_FALLOCATE = 43,
FUSE_READDIRPLUS = 44,
FUSE_RENAME2 = 45,
FUSE_LSEEK = 46,
/* CUSE specific operations */
CUSE_INIT = 4096,
@ -755,4 +759,15 @@ struct fuse_notify_retrieve_in {
uint64_t dummy4;
};
struct fuse_lseek_in {
uint64_t fh;
uint64_t offset;
int32_t whence;
uint32_t padding;
};
struct fuse_lseek_out {
uint64_t offset;
};
#endif /* _LINUX_FUSE_H */

View File

@ -2393,6 +2393,66 @@ fuse_write (xlator_t *this, fuse_in_header_t *finh, void *msg)
return;
}
#if FUSE_KERNEL_MINOR_VERSION >= 24 && HAVE_SEEK_HOLE
static int
fuse_lseek_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
int32_t op_ret, int32_t op_errno, off_t offset, dict_t *xdata)
{
fuse_state_t *state = frame->root->state;
fuse_in_header_t *finh = state->finh;
struct fuse_lseek_out flo = {0, };
fuse_log_eh_fop (this, state, frame, op_ret, op_errno);
if (op_ret >= 0) {
flo.offset = offset;
send_fuse_obj (this, finh, &flo);
} else {
send_fuse_err (this, finh, op_errno);
}
free_fuse_state (state);
STACK_DESTROY (frame->root);
return 0;
}
static void
fuse_lseek_resume (fuse_state_t *state)
{
FUSE_FOP (state, fuse_lseek_cbk, GF_FOP_SEEK, seek, state->fd,
state->off, state->whence, state->xdata);
}
static void
fuse_lseek (xlator_t *this, fuse_in_header_t *finh, void *msg)
{
struct fuse_lseek_in *ffi = msg;
fuse_state_t *state = NULL;
GET_STATE (this, finh, state);
state->fd = FH_TO_FD (ffi->fh);
state->off = ffi->offset;
switch (ffi->whence) {
case SEEK_DATA:
state->whence = GF_SEEK_DATA;
break;
case SEEK_HOLE:
state->whence = GF_SEEK_HOLE;
break;
default:
/* fuse should handle other whence internally */
send_fuse_err (this, finh, EINVAL);
free_fuse_state (state);
return;
}
fuse_resolve_fd_init (state, &state->resolve, state->fd);
fuse_resolve_and_resume (state, fuse_lseek_resume);
}
#endif /* FUSE_KERNEL_MINOR_VERSION >= 24 && HAVE_SEEK_HOLE */
void
fuse_flush_resume (fuse_state_t *state)
{
@ -5327,6 +5387,10 @@ static fuse_handler_t *fuse_std_ops[FUSE_OP_HIGH] = {
#if FUSE_KERNEL_MINOR_VERSION >= 21
[FUSE_READDIRPLUS] = fuse_readdirp,
#endif
#if FUSE_KERNEL_MINOR_VERSION >= 24 && HAVE_SEEK_HOLE
[FUSE_LSEEK] = fuse_lseek,
#endif
};

View File

@ -41,7 +41,7 @@
#include "gidcache.h"
#if defined(GF_LINUX_HOST_OS) || defined(__FreeBSD__) || defined(__NetBSD__)
#define FUSE_OP_HIGH (FUSE_READDIRPLUS + 1)
#define FUSE_OP_HIGH (FUSE_LSEEK + 1)
#endif
#ifdef GF_DARWIN_HOST_OS
#define FUSE_OP_HIGH (FUSE_DESTROY + 1)
@ -380,6 +380,8 @@ typedef struct {
uuid_t gfid;
uint32_t io_flags;
int32_t fd_no;
gf_seek_what_t whence;
} fuse_state_t;
typedef struct {