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) ...@@ -516,17 +516,26 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
int i; int i;
size_t count = req->misc.read.in.size; size_t count = req->misc.read.in.size;
size_t num_read = req->out.args[0].size; size_t num_read = req->out.args[0].size;
struct inode *inode = req->pages[0]->mapping->host; struct address_space *mapping = NULL;
/* for (i = 0; mapping == NULL && i < req->num_pages; i++)
* Short read means EOF. If file size is larger, truncate it mapping = req->pages[i]->mapping;
*/
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);
}
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++) { for (i = 0; i < req->num_pages; i++) {
struct page *page = req->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) ...@@ -535,6 +544,7 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
else else
SetPageError(page); SetPageError(page);
unlock_page(page); unlock_page(page);
page_cache_release(page);
} }
if (req->ff) if (req->ff)
fuse_file_put(req->ff); fuse_file_put(req->ff);
...@@ -549,6 +559,7 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file) ...@@ -549,6 +559,7 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file)
req->out.argpages = 1; req->out.argpages = 1;
req->out.page_zeroing = 1; req->out.page_zeroing = 1;
req->out.page_replace = 1;
fuse_read_fill(req, file, pos, count, FUSE_READ); fuse_read_fill(req, file, pos, count, FUSE_READ);
req->misc.read.attr_ver = fuse_get_attr_version(fc); req->misc.read.attr_ver = fuse_get_attr_version(fc);
if (fc->async_read) { if (fc->async_read) {
...@@ -588,6 +599,7 @@ static int fuse_readpages_fill(void *_data, struct page *page) ...@@ -588,6 +599,7 @@ static int fuse_readpages_fill(void *_data, struct page *page)
return PTR_ERR(req); return PTR_ERR(req);
} }
} }
page_cache_get(page);
req->pages[req->num_pages] = page; req->pages[req->num_pages] = page;
req->num_pages++; req->num_pages++;
return 0; return 0;
...@@ -993,10 +1005,7 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, ...@@ -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); nbytes = min_t(size_t, nbytes, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ); npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ);
down_read(&current->mm->mmap_sem); npages = get_user_pages_fast(user_addr, npages, !write, req->pages);
npages = get_user_pages(current, current->mm, user_addr, npages, !write,
0, req->pages, NULL);
up_read(&current->mm->mmap_sem);
if (npages < 0) if (npages < 0)
return npages; return npages;
...@@ -1579,9 +1588,9 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov, ...@@ -1579,9 +1588,9 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov,
while (iov_iter_count(&ii)) { while (iov_iter_count(&ii)) {
struct page *page = pages[page_idx++]; struct page *page = pages[page_idx++];
size_t todo = min_t(size_t, PAGE_SIZE, iov_iter_count(&ii)); 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) { while (todo) {
char __user *uaddr = ii.iov->iov_base + ii.iov_offset; char __user *uaddr = ii.iov->iov_base + ii.iov_offset;
......
...@@ -177,6 +177,9 @@ struct fuse_out { ...@@ -177,6 +177,9 @@ struct fuse_out {
/** Zero partially or not copied pages */ /** Zero partially or not copied pages */
unsigned page_zeroing:1; unsigned page_zeroing:1;
/** Pages may be replaced with new ones */
unsigned page_replace:1;
/** Number or arguments */ /** Number or arguments */
unsigned numargs; unsigned numargs;
......
...@@ -230,6 +230,7 @@ void *generic_pipe_buf_map(struct pipe_inode_info *pipe, ...@@ -230,6 +230,7 @@ void *generic_pipe_buf_map(struct pipe_inode_info *pipe,
return kmap(buf->page); return kmap(buf->page);
} }
EXPORT_SYMBOL(generic_pipe_buf_map);
/** /**
* generic_pipe_buf_unmap - unmap a previously mapped pipe buffer * generic_pipe_buf_unmap - unmap a previously mapped pipe buffer
...@@ -249,6 +250,7 @@ void generic_pipe_buf_unmap(struct pipe_inode_info *pipe, ...@@ -249,6 +250,7 @@ void generic_pipe_buf_unmap(struct pipe_inode_info *pipe,
} else } else
kunmap(buf->page); kunmap(buf->page);
} }
EXPORT_SYMBOL(generic_pipe_buf_unmap);
/** /**
* generic_pipe_buf_steal - attempt to take ownership of a &pipe_buffer * 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, ...@@ -279,6 +281,7 @@ int generic_pipe_buf_steal(struct pipe_inode_info *pipe,
return 1; return 1;
} }
EXPORT_SYMBOL(generic_pipe_buf_steal);
/** /**
* generic_pipe_buf_get - get a reference to a &struct pipe_buffer * 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) ...@@ -294,6 +297,7 @@ void generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf)
{ {
page_cache_get(buf->page); page_cache_get(buf->page);
} }
EXPORT_SYMBOL(generic_pipe_buf_get);
/** /**
* generic_pipe_buf_confirm - verify contents of the pipe buffer * generic_pipe_buf_confirm - verify contents of the pipe buffer
...@@ -309,6 +313,7 @@ int generic_pipe_buf_confirm(struct pipe_inode_info *info, ...@@ -309,6 +313,7 @@ int generic_pipe_buf_confirm(struct pipe_inode_info *info,
{ {
return 0; return 0;
} }
EXPORT_SYMBOL(generic_pipe_buf_confirm);
/** /**
* generic_pipe_buf_release - put a reference to a &struct pipe_buffer * 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, ...@@ -323,6 +328,7 @@ void generic_pipe_buf_release(struct pipe_inode_info *pipe,
{ {
page_cache_release(buf->page); page_cache_release(buf->page);
} }
EXPORT_SYMBOL(generic_pipe_buf_release);
static const struct pipe_buf_operations anon_pipe_buf_ops = { static const struct pipe_buf_operations anon_pipe_buf_ops = {
.can_merge = 1, .can_merge = 1,
......
...@@ -34,6 +34,9 @@ ...@@ -34,6 +34,9 @@
* 7.13 * 7.13
* - make max number of background requests and congestion threshold * - make max number of background requests and congestion threshold
* tunables * tunables
*
* 7.14
* - add splice support to fuse device
*/ */
#ifndef _LINUX_FUSE_H #ifndef _LINUX_FUSE_H
...@@ -65,7 +68,7 @@ ...@@ -65,7 +68,7 @@
#define FUSE_KERNEL_VERSION 7 #define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */ /** 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 */ /** The node ID of the root inode */
#define FUSE_ROOT_ID 1 #define FUSE_ROOT_ID 1
......
...@@ -151,6 +151,7 @@ void remove_from_page_cache(struct page *page) ...@@ -151,6 +151,7 @@ void remove_from_page_cache(struct page *page)
spin_unlock_irq(&mapping->tree_lock); spin_unlock_irq(&mapping->tree_lock);
mem_cgroup_uncharge_cache_page(page); mem_cgroup_uncharge_cache_page(page);
} }
EXPORT_SYMBOL(remove_from_page_cache);
static int sync_page(void *word) static int sync_page(void *word)
{ {
......
...@@ -224,6 +224,7 @@ void __lru_cache_add(struct page *page, enum lru_list lru) ...@@ -224,6 +224,7 @@ void __lru_cache_add(struct page *page, enum lru_list lru)
____pagevec_lru_add(pvec, lru); ____pagevec_lru_add(pvec, lru);
put_cpu_var(lru_add_pvecs); put_cpu_var(lru_add_pvecs);
} }
EXPORT_SYMBOL(__lru_cache_add);
/** /**
* lru_cache_add_lru - add a page to a page list * 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