Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5c89e9ea authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull fuse updates from Miklos Szeredi:
 "This adds SEEK_HOLE and SEEK_DATA support in lseek"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: add support for SEEK_HOLE and SEEK_DATA in lseek
parents d4342156 0b5da8db
Loading
Loading
Loading
Loading
+65 −8
Original line number Diff line number Diff line
@@ -2231,20 +2231,77 @@ static sector_t fuse_bmap(struct address_space *mapping, sector_t 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)
{
	loff_t retval;
	struct inode *inode = file_inode(file);

	switch (whence) {
	case SEEK_SET:
	case SEEK_CUR:
		 /* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */
	if (whence == SEEK_CUR || whence == SEEK_SET)
		return generic_file_llseek(file, offset, whence);

		retval = generic_file_llseek(file, offset, whence);
		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;
}
+3 −0
Original line number Diff line number Diff line
@@ -605,6 +605,9 @@ struct fuse_conn {
	/** Does the filesystem support asynchronous direct-IO submission? */
	unsigned async_dio:1;

	/** Is lseek not implemented by fs? */
	unsigned no_lseek:1;

	/** The number of requests waiting for completion */
	atomic_t num_waiting;

+16 −1
Original line number Diff line number Diff line
@@ -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,
@@ -758,4 +762,15 @@ struct fuse_notify_retrieve_in {
/* Device ioctls: */
#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 */