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

Commit 5ee7a81a authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull fuse update from Miklos Szeredi:
 "This contains a fix for a potential use-after-module-unload bug
  noticed by Al and caching improvements for read-only fuse filesystems
  by Andrew Gallagher"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: support clients that don't implement 'open'
  fuse: don't invalidate attrs when not using atime
  fuse: fix SetPageUptodate() condition in STORE
  fuse: fix pipe_buf_operations
parents 0d90d638 7678ac50
Loading
Loading
Loading
Loading
+7 −18
Original line number Diff line number Diff line
@@ -1296,22 +1296,6 @@ static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
	return fuse_dev_do_read(fc, file, &cs, iov_length(iov, nr_segs));
}

static int fuse_dev_pipe_buf_steal(struct pipe_inode_info *pipe,
				   struct pipe_buffer *buf)
{
	return 1;
}

static const struct pipe_buf_operations fuse_dev_pipe_buf_ops = {
	.can_merge = 0,
	.map = generic_pipe_buf_map,
	.unmap = generic_pipe_buf_unmap,
	.confirm = generic_pipe_buf_confirm,
	.release = generic_pipe_buf_release,
	.steal = fuse_dev_pipe_buf_steal,
	.get = generic_pipe_buf_get,
};

static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
				    struct pipe_inode_info *pipe,
				    size_t len, unsigned int flags)
@@ -1358,7 +1342,11 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
		buf->page = bufs[page_nr].page;
		buf->offset = bufs[page_nr].offset;
		buf->len = bufs[page_nr].len;
		buf->ops = &fuse_dev_pipe_buf_ops;
		/*
		 * Need to be careful about this.  Having buf->ops in module
		 * code can Oops if the buffer persists after module unload.
		 */
		buf->ops = &nosteal_pipe_buf_ops;

		pipe->nrbufs++;
		page_nr++;
@@ -1599,7 +1587,8 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,

		this_num = min_t(unsigned, num, PAGE_CACHE_SIZE - offset);
		err = fuse_copy_page(cs, &page, offset, this_num, 0);
		if (!err && offset == 0 && (num != 0 || file_size == end))
		if (!err && offset == 0 &&
		    (this_num == PAGE_CACHE_SIZE || file_size == end))
			SetPageUptodate(page);
		unlock_page(page);
		page_cache_release(page);
+12 −2
Original line number Diff line number Diff line
@@ -112,6 +112,16 @@ void fuse_invalidate_attr(struct inode *inode)
	get_fuse_inode(inode)->i_time = 0;
}

/**
 * Mark the attributes as stale due to an atime change.  Avoid the invalidate if
 * atime is not used.
 */
void fuse_invalidate_atime(struct inode *inode)
{
	if (!IS_RDONLY(inode))
		fuse_invalidate_attr(inode);
}

/*
 * Just mark the entry as stale, so that a next attempt to look it up
 * will result in a new lookup call to userspace
@@ -1371,7 +1381,7 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx)
	}

	__free_page(page);
	fuse_invalidate_attr(inode); /* atime changed */
	fuse_invalidate_atime(inode);
	return err;
}

@@ -1404,7 +1414,7 @@ static char *read_link(struct dentry *dentry)
		link[req->out.args[0].size] = '\0';
 out:
	fuse_put_request(fc, req);
	fuse_invalidate_attr(inode); /* atime changed */
	fuse_invalidate_atime(inode);
	return link;
}

+29 −12
Original line number Diff line number Diff line
@@ -127,7 +127,15 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
	if (atomic_dec_and_test(&ff->count)) {
		struct fuse_req *req = ff->reserved_req;

		if (sync) {
		if (ff->fc->no_open) {
			/*
			 * Drop the release request when client does not
			 * implement 'open'
			 */
			req->background = 0;
			path_put(&req->misc.release.path);
			fuse_put_request(ff->fc, req);
		} else if (sync) {
			req->background = 0;
			fuse_request_send(ff->fc, req);
			path_put(&req->misc.release.path);
@@ -144,27 +152,36 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
		 bool isdir)
{
	struct fuse_open_out outarg;
	struct fuse_file *ff;
	int err;
	int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;

	ff = fuse_file_alloc(fc);
	if (!ff)
		return -ENOMEM;

	ff->fh = 0;
	ff->open_flags = FOPEN_KEEP_CACHE; /* Default for no-open */
	if (!fc->no_open || isdir) {
		struct fuse_open_out outarg;
		int err;

		err = fuse_send_open(fc, nodeid, file, opcode, &outarg);
	if (err) {
		if (!err) {
			ff->fh = outarg.fh;
			ff->open_flags = outarg.open_flags;

		} else if (err != -ENOSYS || isdir) {
			fuse_file_free(ff);
			return err;
		} else {
			fc->no_open = 1;
		}
	}

	if (isdir)
		outarg.open_flags &= ~FOPEN_DIRECT_IO;
		ff->open_flags &= ~FOPEN_DIRECT_IO;

	ff->fh = outarg.fh;
	ff->nodeid = nodeid;
	ff->open_flags = outarg.open_flags;
	file->private_data = fuse_file_get(ff);

	return 0;
@@ -687,7 +704,7 @@ static int fuse_readpage(struct file *file, struct page *page)
		SetPageUptodate(page);
	}

	fuse_invalidate_attr(inode); /* atime changed */
	fuse_invalidate_atime(inode);
 out:
	unlock_page(page);
	return err;
@@ -716,7 +733,7 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
			fuse_read_update_size(inode, pos,
					      req->misc.read.attr_ver);
		}
		fuse_invalidate_attr(inode); /* atime changed */
		fuse_invalidate_atime(inode);
	}

	for (i = 0; i < req->num_pages; i++) {
+5 −0
Original line number Diff line number Diff line
@@ -485,6 +485,9 @@ struct fuse_conn {
	 * and hence races in setting them will not cause malfunction
	 */

	/** Is open/release not implemented by fs? */
	unsigned no_open:1;

	/** Is fsync not implemented by fs? */
	unsigned no_fsync:1;

@@ -788,6 +791,8 @@ void fuse_invalidate_attr(struct inode *inode);

void fuse_invalidate_entry_cache(struct dentry *entry);

void fuse_invalidate_atime(struct inode *inode);

/**
 * Acquire reference to fuse_conn
 */
+18 −0
Original line number Diff line number Diff line
@@ -555,6 +555,24 @@ static const struct pipe_buf_operations default_pipe_buf_ops = {
	.get = generic_pipe_buf_get,
};

static int generic_pipe_buf_nosteal(struct pipe_inode_info *pipe,
				    struct pipe_buffer *buf)
{
	return 1;
}

/* Pipe buffer operations for a socket and similar. */
const struct pipe_buf_operations nosteal_pipe_buf_ops = {
	.can_merge = 0,
	.map = generic_pipe_buf_map,
	.unmap = generic_pipe_buf_unmap,
	.confirm = generic_pipe_buf_confirm,
	.release = generic_pipe_buf_release,
	.steal = generic_pipe_buf_nosteal,
	.get = generic_pipe_buf_get,
};
EXPORT_SYMBOL(nosteal_pipe_buf_ops);

static ssize_t kernel_readv(struct file *file, const struct iovec *vec,
			    unsigned long vlen, loff_t offset)
{
Loading