Commit 003386ff authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  mm: export generic_pipe_buf_*() to modules
  fuse: support splice() reading from fuse device
  fuse: allow splice to move pages
  mm: export remove_from_page_cache() to modules
  mm: export lru_cache_add_*() to modules
  fuse: support splice() writing to fuse device
  fuse: get page reference for readpages
  fuse: use get_user_pages_fast()
  fuse: remove unneeded variable
parents 092405cd 51921cb7
This diff is collapsed.
......@@ -516,17 +516,26 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
int i;
size_t count = req->misc.read.in.size;
size_t num_read = req->out.args[0].size;
struct inode *inode = req->pages[0]->mapping->host;
struct address_space *mapping = NULL;
/*
* Short read means EOF. If file size is larger, truncate it
*/
if (!req->out.h.error && num_read < count) {
loff_t pos = page_offset(req->pages[0]) + num_read;
fuse_read_update_size(inode, pos, req->misc.read.attr_ver);
}
for (i = 0; mapping == NULL && i < req->num_pages; i++)
mapping = req->pages[i]->mapping;
fuse_invalidate_attr(inode); /* atime changed */
if (mapping) {
struct inode *inode = mapping->host;
/*
* Short read means EOF. If file size is larger, truncate it
*/
if (!req->out.h.error && num_read < count) {
loff_t pos;
pos = page_offset(req->pages[0]) + num_read;
fuse_read_update_size(inode, pos,
req->misc.read.attr_ver);
}
fuse_invalidate_attr(inode); /* atime changed */
}
for (i = 0; i < req->num_pages; i++) {
struct page *page = req->pages[i];
......@@ -535,6 +544,7 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
else
SetPageError(page);
unlock_page(page);
page_cache_release(page);
}
if (req->ff)
fuse_file_put(req->ff);
......@@ -549,6 +559,7 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file)
req->out.argpages = 1;
req->out.page_zeroing = 1;
req->out.page_replace = 1;
fuse_read_fill(req, file, pos, count, FUSE_READ);
req->misc.read.attr_ver = fuse_get_attr_version(fc);
if (fc->async_read) {
......@@ -588,6 +599,7 @@ static int fuse_readpages_fill(void *_data, struct page *page)
return PTR_ERR(req);
}
}
page_cache_get(page);
req->pages[req->num_pages] = page;
req->num_pages++;
return 0;
......@@ -993,10 +1005,7 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
nbytes = min_t(size_t, nbytes, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ);
down_read(&current->mm->mmap_sem);
npages = get_user_pages(current, current->mm, user_addr, npages, !write,
0, req->pages, NULL);
up_read(&current->mm->mmap_sem);
npages = get_user_pages_fast(user_addr, npages, !write, req->pages);
if (npages < 0)
return npages;
......@@ -1579,9 +1588,9 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov,
while (iov_iter_count(&ii)) {
struct page *page = pages[page_idx++];
size_t todo = min_t(size_t, PAGE_SIZE, iov_iter_count(&ii));
void *kaddr, *map;
void *kaddr;
kaddr = map = kmap(page);
kaddr = kmap(page);
while (todo) {
char __user *uaddr = ii.iov->iov_base + ii.iov_offset;
......
......@@ -177,6 +177,9 @@ struct fuse_out {
/** Zero partially or not copied pages */
unsigned page_zeroing:1;
/** Pages may be replaced with new ones */
unsigned page_replace:1;
/** Number or arguments */
unsigned numargs;
......
......@@ -230,6 +230,7 @@ void *generic_pipe_buf_map(struct pipe_inode_info *pipe,
return kmap(buf->page);
}
EXPORT_SYMBOL(generic_pipe_buf_map);
/**
* generic_pipe_buf_unmap - unmap a previously mapped pipe buffer
......@@ -249,6 +250,7 @@ void generic_pipe_buf_unmap(struct pipe_inode_info *pipe,
} else
kunmap(buf->page);
}
EXPORT_SYMBOL(generic_pipe_buf_unmap);
/**
* generic_pipe_buf_steal - attempt to take ownership of a &pipe_buffer
......@@ -279,6 +281,7 @@ int generic_pipe_buf_steal(struct pipe_inode_info *pipe,
return 1;
}
EXPORT_SYMBOL(generic_pipe_buf_steal);
/**
* generic_pipe_buf_get - get a reference to a &struct pipe_buffer
......@@ -294,6 +297,7 @@ void generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf)
{
page_cache_get(buf->page);
}
EXPORT_SYMBOL(generic_pipe_buf_get);
/**
* generic_pipe_buf_confirm - verify contents of the pipe buffer
......@@ -309,6 +313,7 @@ int generic_pipe_buf_confirm(struct pipe_inode_info *info,
{
return 0;
}
EXPORT_SYMBOL(generic_pipe_buf_confirm);
/**
* generic_pipe_buf_release - put a reference to a &struct pipe_buffer
......@@ -323,6 +328,7 @@ void generic_pipe_buf_release(struct pipe_inode_info *pipe,
{
page_cache_release(buf->page);
}
EXPORT_SYMBOL(generic_pipe_buf_release);
static const struct pipe_buf_operations anon_pipe_buf_ops = {
.can_merge = 1,
......
......@@ -34,6 +34,9 @@
* 7.13
* - make max number of background requests and congestion threshold
* tunables
*
* 7.14
* - add splice support to fuse device
*/
#ifndef _LINUX_FUSE_H
......@@ -65,7 +68,7 @@
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 13
#define FUSE_KERNEL_MINOR_VERSION 14
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
......
......@@ -151,6 +151,7 @@ void remove_from_page_cache(struct page *page)
spin_unlock_irq(&mapping->tree_lock);
mem_cgroup_uncharge_cache_page(page);
}
EXPORT_SYMBOL(remove_from_page_cache);
static int sync_page(void *word)
{
......
......@@ -224,6 +224,7 @@ void __lru_cache_add(struct page *page, enum lru_list lru)
____pagevec_lru_add(pvec, lru);
put_cpu_var(lru_add_pvecs);
}
EXPORT_SYMBOL(__lru_cache_add);
/**
* lru_cache_add_lru - add a page to a page list
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment