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

Commit 9b5cf826 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull fuse updates from Miklos Szeredi:
 "As well as the usual bug fixes, this adds the following new features:

   - cached readdir and readlink

   - max I/O size increased from 128k to 1M

   - improved performance and scalability of request queues

   - copy_file_range support

  The only non-fuse bits are trivial cleanups of macros in
  <linux/bitops.h>"

* tag 'fuse-update-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: (31 commits)
  fuse: enable caching of symlinks
  fuse: only invalidate atime in direct read
  fuse: don't need GETATTR after every READ
  fuse: allow fine grained attr cache invaldation
  bitops: protect variables in bit_clear_unless() macro
  bitops: protect variables in set_mask_bits() macro
  fuse: realloc page array
  fuse: add max_pages to init_out
  fuse: allocate page array more efficiently
  fuse: reduce size of struct fuse_inode
  fuse: use iversion for readdir cache verification
  fuse: use mtime for readdir cache verification
  fuse: add readdir cache version
  fuse: allow using readdir cache
  fuse: allow caching readdir
  fuse: extract fuse_emit() helper
  fuse: add FOPEN_CACHE_DIR
  fuse: split out readdir.c
  fuse: Use hash table to link processing request
  fuse: kill req->intr_unique
  ...
parents 31990f0f 5571f1e6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -5,4 +5,4 @@
obj-$(CONFIG_FUSE_FS) += fuse.o
obj-$(CONFIG_CUSE) += cuse.o

fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o acl.o
fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o
+26 −8
Original line number Diff line number Diff line
@@ -107,7 +107,7 @@ static ssize_t fuse_conn_max_background_read(struct file *file,
	if (!fc)
		return 0;

	val = fc->max_background;
	val = READ_ONCE(fc->max_background);
	fuse_conn_put(fc);

	return fuse_conn_limit_read(file, buf, len, ppos, val);
@@ -125,7 +125,12 @@ static ssize_t fuse_conn_max_background_write(struct file *file,
	if (ret > 0) {
		struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
		if (fc) {
			spin_lock(&fc->bg_lock);
			fc->max_background = val;
			fc->blocked = fc->num_background >= fc->max_background;
			if (!fc->blocked)
				wake_up(&fc->blocked_waitq);
			spin_unlock(&fc->bg_lock);
			fuse_conn_put(fc);
		}
	}
@@ -144,7 +149,7 @@ static ssize_t fuse_conn_congestion_threshold_read(struct file *file,
	if (!fc)
		return 0;

	val = fc->congestion_threshold;
	val = READ_ONCE(fc->congestion_threshold);
	fuse_conn_put(fc);

	return fuse_conn_limit_read(file, buf, len, ppos, val);
@@ -155,18 +160,31 @@ static ssize_t fuse_conn_congestion_threshold_write(struct file *file,
						    size_t count, loff_t *ppos)
{
	unsigned uninitialized_var(val);
	struct fuse_conn *fc;
	ssize_t ret;

	ret = fuse_conn_limit_write(file, buf, count, ppos, &val,
				    max_user_congthresh);
	if (ret > 0) {
		struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
		if (fc) {
	if (ret <= 0)
		goto out;
	fc = fuse_ctl_file_conn_get(file);
	if (!fc)
		goto out;

	spin_lock(&fc->bg_lock);
	fc->congestion_threshold = val;
			fuse_conn_put(fc);
	if (fc->sb) {
		if (fc->num_background < fc->congestion_threshold) {
			clear_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC);
			clear_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC);
		} else {
			set_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC);
			set_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC);
		}
	}

	spin_unlock(&fc->bg_lock);
	fuse_conn_put(fc);
out:
	return ret;
}

+145 −76
Original line number Diff line number Diff line
@@ -25,6 +25,10 @@
MODULE_ALIAS_MISCDEV(FUSE_MINOR);
MODULE_ALIAS("devname:fuse");

/* Ordinary requests have even IDs, while interrupts IDs are odd */
#define FUSE_INT_REQ_BIT (1ULL << 0)
#define FUSE_REQ_ID_STEP (1ULL << 1)

static struct kmem_cache *fuse_req_cachep;

static struct fuse_dev *fuse_get_dev(struct file *file)
@@ -40,9 +44,6 @@ static void fuse_request_init(struct fuse_req *req, struct page **pages,
			      struct fuse_page_desc *page_descs,
			      unsigned npages)
{
	memset(req, 0, sizeof(*req));
	memset(pages, 0, sizeof(*pages) * npages);
	memset(page_descs, 0, sizeof(*page_descs) * npages);
	INIT_LIST_HEAD(&req->list);
	INIT_LIST_HEAD(&req->intr_entry);
	init_waitqueue_head(&req->waitq);
@@ -53,31 +54,37 @@ static void fuse_request_init(struct fuse_req *req, struct page **pages,
	__set_bit(FR_PENDING, &req->flags);
}

static struct fuse_req *__fuse_request_alloc(unsigned npages, gfp_t flags)
static struct page **fuse_req_pages_alloc(unsigned int npages, gfp_t flags,
					  struct fuse_page_desc **desc)
{
	struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, flags);
	if (req) {
	struct page **pages;
		struct fuse_page_desc *page_descs;

		if (npages <= FUSE_REQ_INLINE_PAGES) {
			pages = req->inline_pages;
			page_descs = req->inline_page_descs;
		} else {
			pages = kmalloc_array(npages, sizeof(struct page *),
					      flags);
			page_descs =
				kmalloc_array(npages,
					      sizeof(struct fuse_page_desc),
					      flags);
	pages = kzalloc(npages * (sizeof(struct page *) +
				  sizeof(struct fuse_page_desc)), flags);
	*desc = (void *) pages + npages * sizeof(struct page *);

	return pages;
}

		if (!pages || !page_descs) {
			kfree(pages);
			kfree(page_descs);
static struct fuse_req *__fuse_request_alloc(unsigned npages, gfp_t flags)
{
	struct fuse_req *req = kmem_cache_zalloc(fuse_req_cachep, flags);
	if (req) {
		struct page **pages = NULL;
		struct fuse_page_desc *page_descs = NULL;

		WARN_ON(npages > FUSE_MAX_MAX_PAGES);
		if (npages > FUSE_REQ_INLINE_PAGES) {
			pages = fuse_req_pages_alloc(npages, flags,
						     &page_descs);
			if (!pages) {
				kmem_cache_free(fuse_req_cachep, req);
				return NULL;
			}
		} else if (npages) {
			pages = req->inline_pages;
			page_descs = req->inline_page_descs;
		}

		fuse_request_init(req, pages, page_descs, npages);
	}
@@ -95,12 +102,41 @@ struct fuse_req *fuse_request_alloc_nofs(unsigned npages)
	return __fuse_request_alloc(npages, GFP_NOFS);
}

void fuse_request_free(struct fuse_req *req)
static void fuse_req_pages_free(struct fuse_req *req)
{
	if (req->pages != req->inline_pages) {
	if (req->pages != req->inline_pages)
		kfree(req->pages);
		kfree(req->page_descs);
}

bool fuse_req_realloc_pages(struct fuse_conn *fc, struct fuse_req *req,
			    gfp_t flags)
{
	struct page **pages;
	struct fuse_page_desc *page_descs;
	unsigned int npages = min_t(unsigned int,
				    max_t(unsigned int, req->max_pages * 2,
					  FUSE_DEFAULT_MAX_PAGES_PER_REQ),
				    fc->max_pages);
	WARN_ON(npages <= req->max_pages);

	pages = fuse_req_pages_alloc(npages, flags, &page_descs);
	if (!pages)
		return false;

	memcpy(pages, req->pages, sizeof(struct page *) * req->max_pages);
	memcpy(page_descs, req->page_descs,
	       sizeof(struct fuse_page_desc) * req->max_pages);
	fuse_req_pages_free(req);
	req->pages = pages;
	req->page_descs = page_descs;
	req->max_pages = npages;

	return true;
}

void fuse_request_free(struct fuse_req *req)
{
	fuse_req_pages_free(req);
	kmem_cache_free(fuse_req_cachep, req);
}

@@ -235,8 +271,10 @@ static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req)
	struct file *file = req->stolen_file;
	struct fuse_file *ff = file->private_data;

	WARN_ON(req->max_pages);
	spin_lock(&fc->lock);
	fuse_request_init(req, req->pages, req->page_descs, req->max_pages);
	memset(req, 0, sizeof(*req));
	fuse_request_init(req, NULL, NULL, 0);
	BUG_ON(ff->reserved_req);
	ff->reserved_req = req;
	wake_up_all(&fc->reserved_req_waitq);
@@ -287,10 +325,10 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
			 * We get here in the unlikely case that a background
			 * request was allocated but not sent
			 */
			spin_lock(&fc->lock);
			spin_lock(&fc->bg_lock);
			if (!fc->blocked)
				wake_up(&fc->blocked_waitq);
			spin_unlock(&fc->lock);
			spin_unlock(&fc->bg_lock);
		}

		if (test_bit(FR_WAITING, &req->flags)) {
@@ -319,7 +357,13 @@ static unsigned len_args(unsigned numargs, struct fuse_arg *args)

static u64 fuse_get_unique(struct fuse_iqueue *fiq)
{
	return ++fiq->reqctr;
	fiq->reqctr += FUSE_REQ_ID_STEP;
	return fiq->reqctr;
}

static unsigned int fuse_req_hash(u64 unique)
{
	return hash_long(unique & ~FUSE_INT_REQ_BIT, FUSE_PQ_HASH_BITS);
}

static void queue_request(struct fuse_iqueue *fiq, struct fuse_req *req)
@@ -353,12 +397,13 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget,

static void flush_bg_queue(struct fuse_conn *fc)
{
	struct fuse_iqueue *fiq = &fc->iq;

	while (fc->active_background < fc->max_background &&
	       !list_empty(&fc->bg_queue)) {
		struct fuse_req *req;
		struct fuse_iqueue *fiq = &fc->iq;

		req = list_entry(fc->bg_queue.next, struct fuse_req, list);
		req = list_first_entry(&fc->bg_queue, struct fuse_req, list);
		list_del(&req->list);
		fc->active_background++;
		spin_lock(&fiq->waitq.lock);
@@ -389,14 +434,21 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
	WARN_ON(test_bit(FR_PENDING, &req->flags));
	WARN_ON(test_bit(FR_SENT, &req->flags));
	if (test_bit(FR_BACKGROUND, &req->flags)) {
		spin_lock(&fc->lock);
		spin_lock(&fc->bg_lock);
		clear_bit(FR_BACKGROUND, &req->flags);
		if (fc->num_background == fc->max_background)
		if (fc->num_background == fc->max_background) {
			fc->blocked = 0;

		/* Wake up next waiter, if any */
		if (!fc->blocked && waitqueue_active(&fc->blocked_waitq))
			wake_up(&fc->blocked_waitq);
		} else if (!fc->blocked) {
			/*
			 * Wake up next waiter, if any.  It's okay to use
			 * waitqueue_active(), as we've already synced up
			 * fc->blocked with waiters with the wake_up() call
			 * above.
			 */
			if (waitqueue_active(&fc->blocked_waitq))
				wake_up(&fc->blocked_waitq);
		}

		if (fc->num_background == fc->congestion_threshold && fc->sb) {
			clear_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC);
@@ -405,7 +457,7 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
		fc->num_background--;
		fc->active_background--;
		flush_bg_queue(fc);
		spin_unlock(&fc->lock);
		spin_unlock(&fc->bg_lock);
	}
	wake_up(&req->waitq);
	if (req->end)
@@ -573,20 +625,18 @@ ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args)
	return ret;
}

/*
 * Called under fc->lock
 *
 * fc->connected must have been checked previously
 */
void fuse_request_send_background_locked(struct fuse_conn *fc,
					 struct fuse_req *req)
bool fuse_request_queue_background(struct fuse_conn *fc, struct fuse_req *req)
{
	BUG_ON(!test_bit(FR_BACKGROUND, &req->flags));
	bool queued = false;

	WARN_ON(!test_bit(FR_BACKGROUND, &req->flags));
	if (!test_bit(FR_WAITING, &req->flags)) {
		__set_bit(FR_WAITING, &req->flags);
		atomic_inc(&fc->num_waiting);
	}
	__set_bit(FR_ISREPLY, &req->flags);
	spin_lock(&fc->bg_lock);
	if (likely(fc->connected)) {
		fc->num_background++;
		if (fc->num_background == fc->max_background)
			fc->blocked = 1;
@@ -596,17 +646,17 @@ void fuse_request_send_background_locked(struct fuse_conn *fc,
		}
		list_add_tail(&req->list, &fc->bg_queue);
		flush_bg_queue(fc);
		queued = true;
	}
	spin_unlock(&fc->bg_lock);

	return queued;
}

void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req)
{
	BUG_ON(!req->end);
	spin_lock(&fc->lock);
	if (fc->connected) {
		fuse_request_send_background_locked(fc, req);
		spin_unlock(&fc->lock);
	} else {
		spin_unlock(&fc->lock);
	WARN_ON(!req->end);
	if (!fuse_request_queue_background(fc, req)) {
		req->out.h.error = -ENOTCONN;
		req->end(fc, req);
		fuse_put_request(fc, req);
@@ -1084,12 +1134,11 @@ __releases(fiq->waitq.lock)
	int err;

	list_del_init(&req->intr_entry);
	req->intr_unique = fuse_get_unique(fiq);
	memset(&ih, 0, sizeof(ih));
	memset(&arg, 0, sizeof(arg));
	ih.len = reqsize;
	ih.opcode = FUSE_INTERRUPT;
	ih.unique = req->intr_unique;
	ih.unique = (req->in.h.unique | FUSE_INT_REQ_BIT);
	arg.unique = req->in.h.unique;

	spin_unlock(&fiq->waitq.lock);
@@ -1238,6 +1287,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
	struct fuse_req *req;
	struct fuse_in *in;
	unsigned reqsize;
	unsigned int hash;

 restart:
	spin_lock(&fiq->waitq.lock);
@@ -1310,13 +1360,16 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
		err = reqsize;
		goto out_end;
	}
	list_move_tail(&req->list, &fpq->processing);
	spin_unlock(&fpq->lock);
	hash = fuse_req_hash(req->in.h.unique);
	list_move_tail(&req->list, &fpq->processing[hash]);
	__fuse_get_request(req);
	set_bit(FR_SENT, &req->flags);
	spin_unlock(&fpq->lock);
	/* matches barrier in request_wait_answer() */
	smp_mb__after_atomic();
	if (test_bit(FR_INTERRUPTED, &req->flags))
		queue_interrupt(fiq, req);
	fuse_put_request(fc, req);

	return reqsize;

@@ -1663,7 +1716,7 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode,
	unsigned int num;
	unsigned int offset;
	size_t total_len = 0;
	int num_pages;
	unsigned int num_pages;

	offset = outarg->offset & ~PAGE_MASK;
	file_size = i_size_read(inode);
@@ -1675,7 +1728,7 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode,
		num = file_size - outarg->offset;

	num_pages = (num + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
	num_pages = min(num_pages, FUSE_MAX_PAGES_PER_REQ);
	num_pages = min(num_pages, fc->max_pages);

	req = fuse_get_req(fc, num_pages);
	if (IS_ERR(req))
@@ -1792,10 +1845,11 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
/* Look up request on processing list by unique ID */
static struct fuse_req *request_find(struct fuse_pqueue *fpq, u64 unique)
{
	unsigned int hash = fuse_req_hash(unique);
	struct fuse_req *req;

	list_for_each_entry(req, &fpq->processing, list) {
		if (req->in.h.unique == unique || req->intr_unique == unique)
	list_for_each_entry(req, &fpq->processing[hash], list) {
		if (req->in.h.unique == unique)
			return req;
	}
	return NULL;
@@ -1869,22 +1923,26 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
	if (!fpq->connected)
		goto err_unlock_pq;

	req = request_find(fpq, oh.unique);
	req = request_find(fpq, oh.unique & ~FUSE_INT_REQ_BIT);
	if (!req)
		goto err_unlock_pq;

	/* Is it an interrupt reply? */
	if (req->intr_unique == oh.unique) {
	/* Is it an interrupt reply ID? */
	if (oh.unique & FUSE_INT_REQ_BIT) {
		__fuse_get_request(req);
		spin_unlock(&fpq->lock);

		err = -EINVAL;
		if (nbytes != sizeof(struct fuse_out_header))
		if (nbytes != sizeof(struct fuse_out_header)) {
			fuse_put_request(fc, req);
			goto err_finish;
		}

		if (oh.error == -ENOSYS)
			fc->no_interrupt = 1;
		else if (oh.error == -EAGAIN)
			queue_interrupt(&fc->iq, req);
		fuse_put_request(fc, req);

		fuse_copy_finish(cs);
		return nbytes;
@@ -2102,9 +2160,13 @@ void fuse_abort_conn(struct fuse_conn *fc, bool is_abort)
		struct fuse_dev *fud;
		struct fuse_req *req, *next;
		LIST_HEAD(to_end);
		unsigned int i;

		/* Background queuing checks fc->connected under bg_lock */
		spin_lock(&fc->bg_lock);
		fc->connected = 0;
		fc->blocked = 0;
		spin_unlock(&fc->bg_lock);

		fc->aborted = is_abort;
		fuse_set_initialized(fc);
		list_for_each_entry(fud, &fc->devices, entry) {
@@ -2123,11 +2185,16 @@ void fuse_abort_conn(struct fuse_conn *fc, bool is_abort)
				}
				spin_unlock(&req->waitq.lock);
			}
			list_splice_tail_init(&fpq->processing, &to_end);
			for (i = 0; i < FUSE_PQ_HASH_SIZE; i++)
				list_splice_tail_init(&fpq->processing[i],
						      &to_end);
			spin_unlock(&fpq->lock);
		}
		spin_lock(&fc->bg_lock);
		fc->blocked = 0;
		fc->max_background = UINT_MAX;
		flush_bg_queue(fc);
		spin_unlock(&fc->bg_lock);

		spin_lock(&fiq->waitq.lock);
		fiq->connected = 0;
@@ -2163,10 +2230,12 @@ int fuse_dev_release(struct inode *inode, struct file *file)
		struct fuse_conn *fc = fud->fc;
		struct fuse_pqueue *fpq = &fud->pq;
		LIST_HEAD(to_end);
		unsigned int i;

		spin_lock(&fpq->lock);
		WARN_ON(!list_empty(&fpq->io));
		list_splice_init(&fpq->processing, &to_end);
		for (i = 0; i < FUSE_PQ_HASH_SIZE; i++)
			list_splice_init(&fpq->processing[i], &to_end);
		spin_unlock(&fpq->lock);

		end_requests(fc, &to_end);
+106 −275

File changed.

Preview size limit exceeded, changes collapsed.

+127 −31
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
	}

	INIT_LIST_HEAD(&ff->write_entry);
	mutex_init(&ff->readdir.lock);
	refcount_set(&ff->count, 1);
	RB_CLEAR_NODE(&ff->polled_node);
	init_waitqueue_head(&ff->poll_wait);
@@ -73,6 +74,7 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc)
void fuse_file_free(struct fuse_file *ff)
{
	fuse_request_free(ff->reserved_req);
	mutex_destroy(&ff->readdir.lock);
	kfree(ff);
}

@@ -848,11 +850,11 @@ static int fuse_readpages_fill(void *_data, struct page *page)
	fuse_wait_on_page_writeback(inode, page->index);

	if (req->num_pages &&
	    (req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
	    (req->num_pages == fc->max_pages ||
	     (req->num_pages + 1) * PAGE_SIZE > fc->max_read ||
	     req->pages[req->num_pages - 1]->index + 1 != page->index)) {
		int nr_alloc = min_t(unsigned, data->nr_pages,
				     FUSE_MAX_PAGES_PER_REQ);
		unsigned int nr_alloc = min_t(unsigned int, data->nr_pages,
					      fc->max_pages);
		fuse_send_readpages(req, data->file);
		if (fc->async_read)
			req = fuse_get_req_for_background(fc, nr_alloc);
@@ -887,7 +889,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping,
	struct fuse_conn *fc = get_fuse_conn(inode);
	struct fuse_fill_data data;
	int err;
	int nr_alloc = min_t(unsigned, nr_pages, FUSE_MAX_PAGES_PER_REQ);
	unsigned int nr_alloc = min_t(unsigned int, nr_pages, fc->max_pages);

	err = -EIO;
	if (is_bad_inode(inode))
@@ -1102,12 +1104,13 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req,
	return count > 0 ? count : err;
}

static inline unsigned fuse_wr_pages(loff_t pos, size_t len)
static inline unsigned int fuse_wr_pages(loff_t pos, size_t len,
				     unsigned int max_pages)
{
	return min_t(unsigned,
	return min_t(unsigned int,
		     ((pos + len - 1) >> PAGE_SHIFT) -
		     (pos >> PAGE_SHIFT) + 1,
		     FUSE_MAX_PAGES_PER_REQ);
		     max_pages);
}

static ssize_t fuse_perform_write(struct kiocb *iocb,
@@ -1129,7 +1132,8 @@ static ssize_t fuse_perform_write(struct kiocb *iocb,
	do {
		struct fuse_req *req;
		ssize_t count;
		unsigned nr_pages = fuse_wr_pages(pos, iov_iter_count(ii));
		unsigned int nr_pages = fuse_wr_pages(pos, iov_iter_count(ii),
						      fc->max_pages);

		req = fuse_get_req(fc, nr_pages);
		if (IS_ERR(req)) {
@@ -1319,11 +1323,6 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii,
	return ret < 0 ? ret : 0;
}

static inline int fuse_iter_npages(const struct iov_iter *ii_p)
{
	return iov_iter_npages(ii_p, FUSE_MAX_PAGES_PER_REQ);
}

ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
		       loff_t *ppos, int flags)
{
@@ -1343,9 +1342,10 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
	int err = 0;

	if (io->async)
		req = fuse_get_req_for_background(fc, fuse_iter_npages(iter));
		req = fuse_get_req_for_background(fc, iov_iter_npages(iter,
								fc->max_pages));
	else
		req = fuse_get_req(fc, fuse_iter_npages(iter));
		req = fuse_get_req(fc, iov_iter_npages(iter, fc->max_pages));
	if (IS_ERR(req))
		return PTR_ERR(req);

@@ -1390,9 +1390,10 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
			fuse_put_request(fc, req);
			if (io->async)
				req = fuse_get_req_for_background(fc,
					fuse_iter_npages(iter));
					iov_iter_npages(iter, fc->max_pages));
			else
				req = fuse_get_req(fc, fuse_iter_npages(iter));
				req = fuse_get_req(fc, iov_iter_npages(iter,
								fc->max_pages));
			if (IS_ERR(req))
				break;
		}
@@ -1418,7 +1419,7 @@ static ssize_t __fuse_direct_read(struct fuse_io_priv *io,

	res = fuse_direct_io(io, iter, ppos, 0);

	fuse_invalidate_attr(inode);
	fuse_invalidate_atime(inode);

	return res;
}
@@ -1487,6 +1488,7 @@ __acquires(fc->lock)
	struct fuse_inode *fi = get_fuse_inode(req->inode);
	struct fuse_write_in *inarg = &req->misc.write.in;
	__u64 data_size = req->num_pages * PAGE_SIZE;
	bool queued;

	if (!fc->connected)
		goto out_free;
@@ -1502,7 +1504,8 @@ __acquires(fc->lock)

	req->in.args[1].size = inarg->size;
	fi->writectr++;
	fuse_request_send_background_locked(fc, req);
	queued = fuse_request_queue_background(fc, req);
	WARN_ON(!queued);
	return;

 out_free:
@@ -1819,12 +1822,18 @@ static int fuse_writepages_fill(struct page *page,
	is_writeback = fuse_page_is_writeback(inode, page->index);

	if (req && req->num_pages &&
	    (is_writeback || req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
	    (is_writeback || req->num_pages == fc->max_pages ||
	     (req->num_pages + 1) * PAGE_SIZE > fc->max_write ||
	     data->orig_pages[req->num_pages - 1]->index + 1 != page->index)) {
		fuse_writepages_send(data);
		data->req = NULL;
	} else if (req && req->num_pages == req->max_pages) {
		if (!fuse_req_realloc_pages(fc, req, GFP_NOFS)) {
			fuse_writepages_send(data);
			req = data->req = NULL;
		}
	}

	err = -ENOMEM;
	tmp_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
	if (!tmp_page)
@@ -1847,7 +1856,7 @@ static int fuse_writepages_fill(struct page *page,
		struct fuse_inode *fi = get_fuse_inode(inode);

		err = -ENOMEM;
		req = fuse_request_alloc_nofs(FUSE_MAX_PAGES_PER_REQ);
		req = fuse_request_alloc_nofs(FUSE_REQ_INLINE_PAGES);
		if (!req) {
			__free_page(tmp_page);
			goto out_unlock;
@@ -1904,6 +1913,7 @@ static int fuse_writepages(struct address_space *mapping,
			   struct writeback_control *wbc)
{
	struct inode *inode = mapping->host;
	struct fuse_conn *fc = get_fuse_conn(inode);
	struct fuse_fill_wb_data data;
	int err;

@@ -1916,7 +1926,7 @@ static int fuse_writepages(struct address_space *mapping,
	data.ff = NULL;

	err = -ENOMEM;
	data.orig_pages = kcalloc(FUSE_MAX_PAGES_PER_REQ,
	data.orig_pages = kcalloc(fc->max_pages,
				  sizeof(struct page *),
				  GFP_NOFS);
	if (!data.orig_pages)
@@ -2387,10 +2397,11 @@ static int fuse_copy_ioctl_iovec_old(struct iovec *dst, void *src,
}

/* Make sure iov_length() won't overflow */
static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count)
static int fuse_verify_ioctl_iov(struct fuse_conn *fc, struct iovec *iov,
				 size_t count)
{
	size_t n;
	u32 max = FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT;
	u32 max = fc->max_pages << PAGE_SHIFT;

	for (n = 0; n < count; n++, iov++) {
		if (iov->iov_len > (size_t) max)
@@ -2514,7 +2525,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
	BUILD_BUG_ON(sizeof(struct fuse_ioctl_iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE);

	err = -ENOMEM;
	pages = kcalloc(FUSE_MAX_PAGES_PER_REQ, sizeof(pages[0]), GFP_KERNEL);
	pages = kcalloc(fc->max_pages, sizeof(pages[0]), GFP_KERNEL);
	iov_page = (struct iovec *) __get_free_page(GFP_KERNEL);
	if (!pages || !iov_page)
		goto out;
@@ -2553,7 +2564,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,

	/* make sure there are enough buffer pages and init request with them */
	err = -ENOMEM;
	if (max_pages > FUSE_MAX_PAGES_PER_REQ)
	if (max_pages > fc->max_pages)
		goto out;
	while (num_pages < max_pages) {
		pages[num_pages] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
@@ -2640,11 +2651,11 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
		in_iov = iov_page;
		out_iov = in_iov + in_iovs;

		err = fuse_verify_ioctl_iov(in_iov, in_iovs);
		err = fuse_verify_ioctl_iov(fc, in_iov, in_iovs);
		if (err)
			goto out;

		err = fuse_verify_ioctl_iov(out_iov, out_iovs);
		err = fuse_verify_ioctl_iov(fc, out_iov, out_iovs);
		if (err)
			goto out;

@@ -2835,9 +2846,9 @@ static void fuse_do_truncate(struct file *file)
	fuse_do_setattr(file_dentry(file), &attr, file);
}

static inline loff_t fuse_round_up(loff_t off)
static inline loff_t fuse_round_up(struct fuse_conn *fc, loff_t off)
{
	return round_up(off, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
	return round_up(off, fc->max_pages << PAGE_SHIFT);
}

static ssize_t
@@ -2866,7 +2877,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
	if (async_dio && iov_iter_rw(iter) != WRITE && offset + count > i_size) {
		if (offset >= i_size)
			return 0;
		iov_iter_truncate(iter, fuse_round_up(i_size - offset));
		iov_iter_truncate(iter, fuse_round_up(ff->fc, i_size - offset));
		count = iov_iter_count(iter);
	}

@@ -3011,6 +3022,82 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
	return err;
}

static ssize_t fuse_copy_file_range(struct file *file_in, loff_t pos_in,
				    struct file *file_out, loff_t pos_out,
				    size_t len, unsigned int flags)
{
	struct fuse_file *ff_in = file_in->private_data;
	struct fuse_file *ff_out = file_out->private_data;
	struct inode *inode_out = file_inode(file_out);
	struct fuse_inode *fi_out = get_fuse_inode(inode_out);
	struct fuse_conn *fc = ff_in->fc;
	FUSE_ARGS(args);
	struct fuse_copy_file_range_in inarg = {
		.fh_in = ff_in->fh,
		.off_in = pos_in,
		.nodeid_out = ff_out->nodeid,
		.fh_out = ff_out->fh,
		.off_out = pos_out,
		.len = len,
		.flags = flags
	};
	struct fuse_write_out outarg;
	ssize_t err;
	/* mark unstable when write-back is not used, and file_out gets
	 * extended */
	bool is_unstable = (!fc->writeback_cache) &&
			   ((pos_out + len) > inode_out->i_size);

	if (fc->no_copy_file_range)
		return -EOPNOTSUPP;

	inode_lock(inode_out);

	if (fc->writeback_cache) {
		err = filemap_write_and_wait_range(inode_out->i_mapping,
						   pos_out, pos_out + len);
		if (err)
			goto out;

		fuse_sync_writes(inode_out);
	}

	if (is_unstable)
		set_bit(FUSE_I_SIZE_UNSTABLE, &fi_out->state);

	args.in.h.opcode = FUSE_COPY_FILE_RANGE;
	args.in.h.nodeid = ff_in->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 == -ENOSYS) {
		fc->no_copy_file_range = 1;
		err = -EOPNOTSUPP;
	}
	if (err)
		goto out;

	if (fc->writeback_cache) {
		fuse_write_update_size(inode_out, pos_out + outarg.size);
		file_update_time(file_out);
	}

	fuse_invalidate_attr(inode_out);

	err = outarg.size;
out:
	if (is_unstable)
		clear_bit(FUSE_I_SIZE_UNSTABLE, &fi_out->state);

	inode_unlock(inode_out);

	return err;
}

static const struct file_operations fuse_file_operations = {
	.llseek		= fuse_file_llseek,
	.read_iter	= fuse_file_read_iter,
@@ -3027,6 +3114,7 @@ static const struct file_operations fuse_file_operations = {
	.compat_ioctl	= fuse_file_compat_ioctl,
	.poll		= fuse_file_poll,
	.fallocate	= fuse_file_fallocate,
	.copy_file_range = fuse_copy_file_range,
};

static const struct file_operations fuse_direct_io_file_operations = {
@@ -3062,6 +3150,14 @@ static const struct address_space_operations fuse_file_aops = {

void fuse_init_file_inode(struct inode *inode)
{
	struct fuse_inode *fi = get_fuse_inode(inode);

	inode->i_fop = &fuse_file_operations;
	inode->i_data.a_ops = &fuse_file_aops;

	INIT_LIST_HEAD(&fi->write_files);
	INIT_LIST_HEAD(&fi->queued_writes);
	fi->writectr = 0;
	init_waitqueue_head(&fi->page_waitq);
	INIT_LIST_HEAD(&fi->writepages);
}
Loading