X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=fs%2Fsplice.c;h=e7d7080de2f9799860a475a4df50a7742561d09f;hb=edad01e2a1c527af3baf22dc6977aeb058881150;hp=684bca3d3a107c021715f8394a1f1d23a1913aaa;hpb=00ab956f2fefd3673edc16df55beed21834b7bdd;p=~andy%2Flinux diff --git a/fs/splice.c b/fs/splice.c index 684bca3d3a1..e7d7080de2f 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -12,7 +12,7 @@ * Jens to support splicing to files, network, direct splicing, etc and * fixing lots of bugs. * - * Copyright (C) 2005-2006 Jens Axboe + * Copyright (C) 2005-2006 Jens Axboe * Copyright (C) 2005-2006 Linus Torvalds * Copyright (C) 2006 Ingo Molnar * @@ -42,7 +42,7 @@ struct splice_pipe_desc { struct partial_page *partial; /* pages[] may not be contig */ int nr_pages; /* number of pages in map */ unsigned int flags; /* splice flags */ - struct pipe_buf_operations *ops;/* ops associated with output pipe */ + const struct pipe_buf_operations *ops;/* ops associated with output pipe */ }; /* @@ -74,7 +74,7 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe, wait_on_page_writeback(page); if (PagePrivate(page)) - try_to_release_page(page, mapping_gfp_mask(mapping)); + try_to_release_page(page, GFP_KERNEL); /* * If we succeeded in removing the mapping, set LRU flag @@ -139,7 +139,7 @@ error: return err; } -static struct pipe_buf_operations page_cache_pipe_buf_ops = { +static const struct pipe_buf_operations page_cache_pipe_buf_ops = { .can_merge = 0, .map = generic_pipe_buf_map, .unmap = generic_pipe_buf_unmap, @@ -159,7 +159,7 @@ static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe, return generic_pipe_buf_steal(pipe, buf); } -static struct pipe_buf_operations user_page_pipe_buf_ops = { +static const struct pipe_buf_operations user_page_pipe_buf_ops = { .can_merge = 0, .map = generic_pipe_buf_map, .unmap = generic_pipe_buf_unmap, @@ -176,6 +176,7 @@ static struct pipe_buf_operations user_page_pipe_buf_ops = { static ssize_t splice_to_pipe(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd) { + unsigned int spd_pages = spd->nr_pages; int ret, do_wakeup, page_nr; ret = 0; @@ -244,17 +245,18 @@ static ssize_t splice_to_pipe(struct pipe_inode_info *pipe, pipe->waiting_writers--; } - if (pipe->inode) + if (pipe->inode) { mutex_unlock(&pipe->inode->i_mutex); - if (do_wakeup) { - smp_mb(); - if (waitqueue_active(&pipe->wait)) - wake_up_interruptible(&pipe->wait); - kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); + if (do_wakeup) { + smp_mb(); + if (waitqueue_active(&pipe->wait)) + wake_up_interruptible(&pipe->wait); + kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); + } } - while (page_nr < spd->nr_pages) + while (page_nr < spd_pages) page_cache_release(spd->pages[page_nr++]); return ret; @@ -272,7 +274,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, struct page *page; pgoff_t index, end_index; loff_t isize; - size_t total_len; int error, page_nr; struct splice_pipe_desc spd = { .pages = pages, @@ -289,18 +290,15 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, nr_pages = PIPE_BUFFERS; /* - * Initiate read-ahead on this page range. however, don't call into - * read-ahead if this is a non-zero offset (we are likely doing small - * chunk splice and the page is already there) for a single page. + * Don't try to 2nd guess the read-ahead logic, call into + * page_cache_readahead() like the page cache reads would do. */ - if (!loff || nr_pages > 1) - page_cache_readahead(mapping, &in->f_ra, in, index, nr_pages); + page_cache_readahead(mapping, &in->f_ra, in, index, nr_pages); /* * Now fill in the holes: */ error = 0; - total_len = 0; /* * Lookup the (hopefully) full range of pages we need. @@ -333,7 +331,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, break; error = add_to_page_cache_lru(page, mapping, index, - mapping_gfp_mask(mapping)); + GFP_KERNEL); if (unlikely(error)) { page_cache_release(page); if (error == -EEXIST) @@ -378,10 +376,11 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, * If in nonblock mode then dont block on waiting * for an in-flight io page */ - if (flags & SPLICE_F_NONBLOCK) - break; - - lock_page(page); + if (flags & SPLICE_F_NONBLOCK) { + if (TestSetPageLocked(page)) + break; + } else + lock_page(page); /* * page was truncated, stop here. if this isn't the @@ -416,43 +415,47 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, break; } + } +fill_it: + /* + * i_size must be checked after PageUptodate. + */ + isize = i_size_read(mapping->host); + end_index = (isize - 1) >> PAGE_CACHE_SHIFT; + if (unlikely(!isize || index > end_index)) + break; + + /* + * if this is the last page, see if we need to shrink + * the length and stop + */ + if (end_index == index) { + unsigned int plen; /* - * i_size must be checked after ->readpage(). + * max good bytes in this page */ - isize = i_size_read(mapping->host); - end_index = (isize - 1) >> PAGE_CACHE_SHIFT; - if (unlikely(!isize || index > end_index)) + plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1; + if (plen <= loff) break; /* - * if this is the last page, see if we need to shrink - * the length and stop + * force quit after adding this page */ - if (end_index == index) { - loff = PAGE_CACHE_SIZE - (isize & ~PAGE_CACHE_MASK); - if (total_len + loff > isize) - break; - /* - * force quit after adding this page - */ - len = this_len; - this_len = min(this_len, loff); - loff = 0; - } + this_len = min(this_len, plen - loff); + len = this_len; } -fill_it: + partial[page_nr].offset = loff; partial[page_nr].len = this_len; len -= this_len; - total_len += this_len; loff = 0; spd.nr_pages++; index++; } /* - * Release any pages at the end, if we quit early. 'i' is how far + * Release any pages at the end, if we quit early. 'page_nr' is how far * we got, 'nr_pages' is how many pages are in the map. */ while (page_nr < nr_pages) @@ -479,10 +482,18 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, { ssize_t spliced; int ret; + loff_t isize, left; + + isize = i_size_read(in->f_mapping->host); + if (unlikely(*ppos >= isize)) + return 0; + + left = isize - *ppos; + if (unlikely(left < len)) + len = left; ret = 0; spliced = 0; - while (len) { ret = __generic_file_splice_read(in, ppos, pipe, len, flags); @@ -557,7 +568,6 @@ static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, { struct file *file = sd->file; struct address_space *mapping = file->f_mapping; - gfp_t gfp_mask = mapping_gfp_mask(mapping); unsigned int offset, this_len; struct page *page; pgoff_t index; @@ -577,76 +587,21 @@ static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, if (this_len + offset > PAGE_CACHE_SIZE) this_len = PAGE_CACHE_SIZE - offset; - /* - * Reuse buf page, if SPLICE_F_MOVE is set and we are doing a full - * page. - */ - if ((sd->flags & SPLICE_F_MOVE) && this_len == PAGE_CACHE_SIZE) { - /* - * If steal succeeds, buf->page is now pruned from the - * pagecache and we can reuse it. The page will also be - * locked on successful return. - */ - if (buf->ops->steal(pipe, buf)) - goto find_page; - - page = buf->page; - if (add_to_page_cache(page, mapping, index, gfp_mask)) { - unlock_page(page); - goto find_page; - } - - page_cache_get(page); - - if (!(buf->flags & PIPE_BUF_FLAG_LRU)) - lru_cache_add(page); - } else { find_page: - page = find_lock_page(mapping, index); - if (!page) { - ret = -ENOMEM; - page = page_cache_alloc_cold(mapping); - if (unlikely(!page)) - goto out_nomem; - - /* - * This will also lock the page - */ - ret = add_to_page_cache_lru(page, mapping, index, - gfp_mask); - if (unlikely(ret)) - goto out; - } + page = find_lock_page(mapping, index); + if (!page) { + ret = -ENOMEM; + page = page_cache_alloc_cold(mapping); + if (unlikely(!page)) + goto out_ret; /* - * We get here with the page locked. If the page is also - * uptodate, we don't need to do more. If it isn't, we - * may need to bring it in if we are not going to overwrite - * the full page. + * This will also lock the page */ - if (!PageUptodate(page)) { - if (this_len < PAGE_CACHE_SIZE) { - ret = mapping->a_ops->readpage(file, page); - if (unlikely(ret)) - goto out; - - lock_page(page); - - if (!PageUptodate(page)) { - /* - * Page got invalidated, repeat. - */ - if (!page->mapping) { - unlock_page(page); - page_cache_release(page); - goto find_page; - } - ret = -EIO; - goto out; - } - } else - SetPageUptodate(page); - } + ret = add_to_page_cache_lru(page, mapping, index, + GFP_KERNEL); + if (unlikely(ret)) + goto out; } ret = mapping->a_ops->prepare_write(file, page, offset, offset+this_len); @@ -666,7 +621,7 @@ find_page: if (sd->pos + this_len > isize) vmtruncate(mapping->host, isize); - goto out; + goto out_ret; } if (buf->page != page) { @@ -683,22 +638,28 @@ find_page: } ret = mapping->a_ops->commit_write(file, page, offset, offset+this_len); - if (!ret) { + if (ret) { + if (ret == AOP_TRUNCATED_PAGE) { + page_cache_release(page); + goto find_page; + } + if (ret < 0) + goto out; /* - * Return the number of bytes written and mark page as - * accessed, we are now done! + * Partial write has happened, so 'ret' already initialized by + * number of bytes written, Where is nothing we have to do here. */ + } else ret = this_len; - mark_page_accessed(page); - balance_dirty_pages_ratelimited(mapping); - } else if (ret == AOP_TRUNCATED_PAGE) { - page_cache_release(page); - goto find_page; - } + /* + * Return the number of bytes written and mark page as + * accessed, we are now done! + */ + mark_page_accessed(page); out: page_cache_release(page); unlock_page(page); -out_nomem: +out_ret: return ret; } @@ -707,9 +668,9 @@ out_nomem: * key here is the 'actor' worker passed in that actually moves the data * to the wanted destination. See pipe_to_file/pipe_to_sendpage above. */ -ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, - loff_t *ppos, size_t len, unsigned int flags, - splice_actor *actor) +ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, + struct file *out, loff_t *ppos, size_t len, + unsigned int flags, splice_actor *actor) { int ret, do_wakeup, err; struct splice_desc sd; @@ -722,13 +683,10 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, sd.file = out; sd.pos = *ppos; - if (pipe->inode) - mutex_lock(&pipe->inode->i_mutex); - for (;;) { if (pipe->nrbufs) { struct pipe_buffer *buf = pipe->bufs + pipe->curbuf; - struct pipe_buf_operations *ops = buf->ops; + const struct pipe_buf_operations *ops = buf->ops; sd.len = buf->len; if (sd.len > sd.total_len) @@ -797,9 +755,6 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, pipe_wait(pipe); } - if (pipe->inode) - mutex_unlock(&pipe->inode->i_mutex); - if (do_wakeup) { smp_mb(); if (waitqueue_active(&pipe->wait)) @@ -809,6 +764,78 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, return ret; } +EXPORT_SYMBOL(__splice_from_pipe); + +ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags, + splice_actor *actor) +{ + ssize_t ret; + struct inode *inode = out->f_mapping->host; + + /* + * The actor worker might be calling ->prepare_write and + * ->commit_write. Most of the time, these expect i_mutex to + * be held. Since this may result in an ABBA deadlock with + * pipe->inode, we have to order lock acquiry here. + */ + inode_double_lock(inode, pipe->inode); + ret = __splice_from_pipe(pipe, out, ppos, len, flags, actor); + inode_double_unlock(inode, pipe->inode); + + return ret; +} + +/** + * generic_file_splice_write_nolock - generic_file_splice_write without mutexes + * @pipe: pipe info + * @out: file to write to + * @len: number of bytes to splice + * @flags: splice modifier flags + * + * Will either move or copy pages (determined by @flags options) from + * the given pipe inode to the given file. The caller is responsible + * for acquiring i_mutex on both inodes. + * + */ +ssize_t +generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out, + loff_t *ppos, size_t len, unsigned int flags) +{ + struct address_space *mapping = out->f_mapping; + struct inode *inode = mapping->host; + ssize_t ret; + int err; + + err = remove_suid(out->f_path.dentry); + if (unlikely(err)) + return err; + + ret = __splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file); + if (ret > 0) { + unsigned long nr_pages; + + *ppos += ret; + nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + + /* + * If file or inode is SYNC and we actually wrote some data, + * sync it. + */ + if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) { + err = generic_osync_inode(inode, mapping, + OSYNC_METADATA|OSYNC_DATA); + + if (err) + ret = err; + } + balance_dirty_pages_ratelimited_nr(mapping, nr_pages); + } + + return ret; +} + +EXPORT_SYMBOL(generic_file_splice_write_nolock); /** * generic_file_splice_write - splice data from a pipe to a file @@ -826,21 +853,31 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, loff_t *ppos, size_t len, unsigned int flags) { struct address_space *mapping = out->f_mapping; + struct inode *inode = mapping->host; ssize_t ret; + int err; + + err = should_remove_suid(out->f_path.dentry); + if (unlikely(err)) { + mutex_lock(&inode->i_mutex); + err = __remove_suid(out->f_path.dentry, err); + mutex_unlock(&inode->i_mutex); + if (err) + return err; + } ret = splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file); if (ret > 0) { - struct inode *inode = mapping->host; + unsigned long nr_pages; *ppos += ret; + nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; /* * If file or inode is SYNC and we actually wrote some data, * sync it. */ if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) { - int err; - mutex_lock(&inode->i_mutex); err = generic_osync_inode(inode, mapping, OSYNC_METADATA|OSYNC_DATA); @@ -849,6 +886,7 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, if (err) ret = err; } + balance_dirty_pages_ratelimited_nr(mapping, nr_pages); } return ret; @@ -903,7 +941,6 @@ static long do_splice_to(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) { - loff_t isize, left; int ret; if (unlikely(!in->f_op || !in->f_op->splice_read)) @@ -916,14 +953,6 @@ static long do_splice_to(struct file *in, loff_t *ppos, if (unlikely(ret < 0)) return ret; - isize = i_size_read(in->f_mapping->host); - if (unlikely(*ppos >= isize)) - return 0; - - left = isize - *ppos; - if (unlikely(left < len)) - len = left; - return in->f_op->splice_read(in, ppos, pipe, len, flags); } @@ -941,7 +970,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, * randomly drop data for eg socket -> socket splicing. Use the * piped splicing for that! */ - i_mode = in->f_dentry->d_inode->i_mode; + i_mode = in->f_path.dentry->d_inode->i_mode; if (unlikely(!S_ISREG(i_mode) && !S_ISBLK(i_mode))) return -EINVAL; @@ -1039,7 +1068,18 @@ out_release: return ret; } -EXPORT_SYMBOL(do_splice_direct); +/* + * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same + * location, so checking ->i_pipe is not enough to verify that this is a + * pipe. + */ +static inline struct pipe_inode_info *pipe_info(struct inode *inode) +{ + if (S_ISFIFO(inode->i_mode)) + return inode->i_pipe; + + return NULL; +} /* * Determine where to splice to/from. @@ -1052,7 +1092,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, loff_t offset, *off; long ret; - pipe = in->f_dentry->d_inode->i_pipe; + pipe = pipe_info(in->f_path.dentry->d_inode); if (pipe) { if (off_in) return -ESPIPE; @@ -1073,7 +1113,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, return ret; } - pipe = out->f_dentry->d_inode->i_pipe; + pipe = pipe_info(out->f_path.dentry->d_inode); if (pipe) { if (off_out) return -ESPIPE; @@ -1231,7 +1271,7 @@ static int get_iovec_page_array(const struct iovec __user *iov, static long do_vmsplice(struct file *file, const struct iovec __user *iov, unsigned long nr_segs, unsigned int flags) { - struct pipe_inode_info *pipe = file->f_dentry->d_inode->i_pipe; + struct pipe_inode_info *pipe; struct page *pages[PIPE_BUFFERS]; struct partial_page partial[PIPE_BUFFERS]; struct splice_pipe_desc spd = { @@ -1241,7 +1281,8 @@ static long do_vmsplice(struct file *file, const struct iovec __user *iov, .ops = &user_page_pipe_buf_ops, }; - if (unlikely(!pipe)) + pipe = pipe_info(file->f_path.dentry->d_inode); + if (!pipe) return -EBADF; if (unlikely(nr_segs > UIO_MAXIOV)) return -EINVAL; @@ -1400,13 +1441,7 @@ static int link_pipe(struct pipe_inode_info *ipipe, * grabbing by inode address. Otherwise two different processes * could deadlock (one doing tee from A -> B, the other from B -> A). */ - if (ipipe->inode < opipe->inode) { - mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_PARENT); - mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_CHILD); - } else { - mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_PARENT); - mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_CHILD); - } + inode_double_lock(ipipe->inode, opipe->inode); do { if (!opipe->readers) { @@ -1450,8 +1485,7 @@ static int link_pipe(struct pipe_inode_info *ipipe, i++; } while (len); - mutex_unlock(&ipipe->inode->i_mutex); - mutex_unlock(&opipe->inode->i_mutex); + inode_double_unlock(ipipe->inode, opipe->inode); /* * If we put data in the output pipe, wakeup any potential readers. @@ -1475,8 +1509,8 @@ static int link_pipe(struct pipe_inode_info *ipipe, static long do_tee(struct file *in, struct file *out, size_t len, unsigned int flags) { - struct pipe_inode_info *ipipe = in->f_dentry->d_inode->i_pipe; - struct pipe_inode_info *opipe = out->f_dentry->d_inode->i_pipe; + struct pipe_inode_info *ipipe = pipe_info(in->f_path.dentry->d_inode); + struct pipe_inode_info *opipe = pipe_info(out->f_path.dentry->d_inode); int ret = -EINVAL; /*