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

Commit 8764d861 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull fuse fixes from Miklos Szeredi:
 "One patch fixes an Oops introduced in 3.9 with the readdirplus
  feature.  The rest are fixes for async-dio in 3.10"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: fix alignment in short read optimization for async_dio
  fuse: return -EIOCBQUEUED from fuse_direct_IO() for all async requests
  fuse: fix readdirplus Oops in fuse_dentry_revalidate
  fuse: update inode size and invalidate attributes on fallocate
  fuse: truncate pagecache range on hole punch
  fuse: allocate for_background dio requests based on io->async state
parents 1dc735bd e5c5f05d
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -180,6 +180,8 @@ u64 fuse_get_attr_version(struct fuse_conn *fc)
static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
{
	struct inode *inode;
	struct dentry *parent;
	struct fuse_conn *fc;

	inode = ACCESS_ONCE(entry->d_inode);
	if (inode && is_bad_inode(inode))
@@ -187,10 +189,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
	else if (fuse_dentry_time(entry) < get_jiffies_64()) {
		int err;
		struct fuse_entry_out outarg;
		struct fuse_conn *fc;
		struct fuse_req *req;
		struct fuse_forget_link *forget;
		struct dentry *parent;
		u64 attr_version;

		/* For negative dentries, always do a fresh lookup */
@@ -241,8 +241,14 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
				       entry_attr_timeout(&outarg),
				       attr_version);
		fuse_change_entry_timeout(entry, &outarg);
	} else if (inode) {
		fc = get_fuse_conn(inode);
		if (fc->readdirplus_auto) {
			parent = dget_parent(entry);
			fuse_advise_use_readdirplus(parent->d_inode);
			dput(parent);
		}
	}
	fuse_advise_use_readdirplus(inode);
	return 1;
}

+49 −9
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/compat.h>
#include <linux/swap.h>
#include <linux/aio.h>
#include <linux/falloc.h>

static const struct file_operations fuse_direct_io_file_operations;

@@ -1278,6 +1279,9 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov,

	iov_iter_init(&ii, iov, nr_segs, count, 0);

	if (io->async)
		req = fuse_get_req_for_background(fc, fuse_iter_npages(&ii));
	else
		req = fuse_get_req(fc, fuse_iter_npages(&ii));
	if (IS_ERR(req))
		return PTR_ERR(req);
@@ -1314,6 +1318,10 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, const struct iovec *iov,
			break;
		if (count) {
			fuse_put_request(fc, req);
			if (io->async)
				req = fuse_get_req_for_background(fc,
					fuse_iter_npages(&ii));
			else
				req = fuse_get_req(fc, fuse_iter_npages(&ii));
			if (IS_ERR(req))
				break;
@@ -2365,6 +2373,11 @@ static void fuse_do_truncate(struct file *file)
	fuse_do_setattr(inode, &attr, file);
}

static inline loff_t fuse_round_up(loff_t off)
{
	return round_up(off, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
}

static ssize_t
fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
			loff_t offset, unsigned long nr_segs)
@@ -2372,6 +2385,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
	ssize_t ret = 0;
	struct file *file = iocb->ki_filp;
	struct fuse_file *ff = file->private_data;
	bool async_dio = ff->fc->async_dio;
	loff_t pos = 0;
	struct inode *inode;
	loff_t i_size;
@@ -2383,10 +2397,10 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
	i_size = i_size_read(inode);

	/* optimization for short read */
	if (rw != WRITE && offset + count > i_size) {
	if (async_dio && rw != WRITE && offset + count > i_size) {
		if (offset >= i_size)
			return 0;
		count = i_size - offset;
		count = min_t(loff_t, count, fuse_round_up(i_size - offset));
	}

	io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL);
@@ -2404,7 +2418,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
	 * By default, we want to optimize all I/Os with async request
	 * submission to the client filesystem if supported.
	 */
	io->async = ff->fc->async_dio;
	io->async = async_dio;
	io->iocb = iocb;

	/*
@@ -2412,7 +2426,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
	 * to wait on real async I/O requests, so we must submit this request
	 * synchronously.
	 */
	if (!is_sync_kiocb(iocb) && (offset + count > i_size))
	if (!is_sync_kiocb(iocb) && (offset + count > i_size) && rw == WRITE)
		io->async = false;

	if (rw == WRITE)
@@ -2424,7 +2438,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
		fuse_aio_complete(io, ret < 0 ? ret : 0, -1);

		/* we have a non-extending, async request, so return */
		if (ret > 0 && !is_sync_kiocb(iocb))
		if (!is_sync_kiocb(iocb))
			return -EIOCBQUEUED;

		ret = wait_on_sync_kiocb(iocb);
@@ -2446,6 +2460,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
				loff_t length)
{
	struct fuse_file *ff = file->private_data;
	struct inode *inode = file->f_inode;
	struct fuse_conn *fc = ff->fc;
	struct fuse_req *req;
	struct fuse_fallocate_in inarg = {
@@ -2459,9 +2474,16 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
	if (fc->no_fallocate)
		return -EOPNOTSUPP;

	if (mode & FALLOC_FL_PUNCH_HOLE) {
		mutex_lock(&inode->i_mutex);
		fuse_set_nowrite(inode);
	}

	req = fuse_get_req_nopages(fc);
	if (IS_ERR(req))
		return PTR_ERR(req);
	if (IS_ERR(req)) {
		err = PTR_ERR(req);
		goto out;
	}

	req->in.h.opcode = FUSE_FALLOCATE;
	req->in.h.nodeid = ff->nodeid;
@@ -2476,6 +2498,24 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
	}
	fuse_put_request(fc, req);

	if (err)
		goto out;

	/* we could have extended the file */
	if (!(mode & FALLOC_FL_KEEP_SIZE))
		fuse_write_update_size(inode, offset + length);

	if (mode & FALLOC_FL_PUNCH_HOLE)
		truncate_pagecache_range(inode, offset, offset + length - 1);

	fuse_invalidate_attr(inode);

out:
	if (mode & FALLOC_FL_PUNCH_HOLE) {
		fuse_release_nowrite(inode);
		mutex_unlock(&inode->i_mutex);
	}

	return err;
}

+4 −3
Original line number Diff line number Diff line
@@ -867,10 +867,11 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
				fc->dont_mask = 1;
			if (arg->flags & FUSE_AUTO_INVAL_DATA)
				fc->auto_inval_data = 1;
			if (arg->flags & FUSE_DO_READDIRPLUS)
			if (arg->flags & FUSE_DO_READDIRPLUS) {
				fc->do_readdirplus = 1;
				if (arg->flags & FUSE_READDIRPLUS_AUTO)
					fc->readdirplus_auto = 1;
			}
			if (arg->flags & FUSE_ASYNC_DIO)
				fc->async_dio = 1;
		} else {