2045 lines · 46.3 KB · C
RawDownload
/* * "splice": joining two ropes together by interweaving their strands. * * This is the "extended pipe" functionality, where a pipe is used as * an arbitrary in-memory buffer. Think of a pipe as a small kernel * buffer that you can use to transfer data from one end to the other. * * The traditional unix read/write is extended with a "splice()" operation * that transfers data buffers to or from a pipe buffer. * * Named by Larry McVoy, original implementation from Linus, extended by * Jens to support splicing to files, network, direct splicing, etc and * fixing lots of bugs. * * Copyright (C) 2005-2006 Jens Axboe <axboe@kernel.dk> * Copyright (C) 2005-2006 Linus Torvalds <torvalds@osdl.org> * Copyright (C) 2006 Ingo Molnar <mingo@elte.hu> * */#include <linux/fs.h>#include <linux/file.h>#include <linux/pagemap.h>#include <linux/splice.h>#include <linux/memcontrol.h>#include <linux/mm_inline.h>#include <linux/swap.h>#include <linux/writeback.h>#include <linux/export.h>#include <linux/syscalls.h>#include <linux/uio.h>#include <linux/security.h>#include <linux/gfp.h>#include <linux/socket.h> /* * Attempt to steal a page from a pipe buffer. This should perhaps go into * a vm helper function, it's already simplified quite a bit by the * addition of remove_mapping(). If success is returned, the caller may * attempt to reuse this page for another destination. */static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe,				     struct pipe_buffer *buf){	struct page *page = buf->page;	struct address_space *mapping; 	lock_page(page); 	mapping = page_mapping(page);	if (mapping) {		WARN_ON(!PageUptodate(page)); 		/*		 * At least for ext2 with nobh option, we need to wait on		 * writeback completing on this page, since we'll remove it		 * from the pagecache.  Otherwise truncate wont wait on the		 * page, allowing the disk blocks to be reused by someone else		 * before we actually wrote our data to them. fs corruption		 * ensues.		 */		wait_on_page_writeback(page); 		if (page_has_private(page) &&		    !try_to_release_page(page, GFP_KERNEL))			goto out_unlock; 		/*		 * If we succeeded in removing the mapping, set LRU flag		 * and return good.		 */		if (remove_mapping(mapping, page)) {			buf->flags |= PIPE_BUF_FLAG_LRU;			return 0;		}	} 	/*	 * Raced with truncate or failed to remove page from current	 * address space, unlock and return failure.	 */out_unlock:	unlock_page(page);	return 1;} static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe,					struct pipe_buffer *buf){	page_cache_release(buf->page);	buf->flags &= ~PIPE_BUF_FLAG_LRU;} /* * Check whether the contents of buf is OK to access. Since the content * is a page cache page, IO may be in flight. */static int page_cache_pipe_buf_confirm(struct pipe_inode_info *pipe,				       struct pipe_buffer *buf){	struct page *page = buf->page;	int err; 	if (!PageUptodate(page)) {		lock_page(page); 		/*		 * Page got truncated/unhashed. This will cause a 0-byte		 * splice, if this is the first page.		 */		if (!page->mapping) {			err = -ENODATA;			goto error;		} 		/*		 * Uh oh, read-error from disk.		 */		if (!PageUptodate(page)) {			err = -EIO;			goto error;		} 		/*		 * Page is ok afterall, we are done.		 */		unlock_page(page);	} 	return 0;error:	unlock_page(page);	return err;} const struct pipe_buf_operations page_cache_pipe_buf_ops = {	.can_merge = 0,	.map = generic_pipe_buf_map,	.unmap = generic_pipe_buf_unmap,	.confirm = page_cache_pipe_buf_confirm,	.release = page_cache_pipe_buf_release,	.steal = page_cache_pipe_buf_steal,	.get = generic_pipe_buf_get,}; static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe,				    struct pipe_buffer *buf){	if (!(buf->flags & PIPE_BUF_FLAG_GIFT))		return 1; 	buf->flags |= PIPE_BUF_FLAG_LRU;	return generic_pipe_buf_steal(pipe, buf);} static const struct pipe_buf_operations user_page_pipe_buf_ops = {	.can_merge = 0,	.map = generic_pipe_buf_map,	.unmap = generic_pipe_buf_unmap,	.confirm = generic_pipe_buf_confirm,	.release = page_cache_pipe_buf_release,	.steal = user_page_pipe_buf_steal,	.get = generic_pipe_buf_get,}; static void wakeup_pipe_readers(struct pipe_inode_info *pipe){	smp_mb();	if (waitqueue_active(&pipe->wait))		wake_up_interruptible(&pipe->wait);	kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);} /** * splice_to_pipe - fill passed data into a pipe * @pipe:	pipe to fill * @spd:	data to fill * * Description: *    @spd contains a map of pages and len/offset tuples, along with *    the struct pipe_buf_operations associated with these pages. This *    function will link that data to the pipe. * */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;	do_wakeup = 0;	page_nr = 0; 	pipe_lock(pipe); 	for (;;) {		if (!pipe->readers) {			send_sig(SIGPIPE, current, 0);			if (!ret)				ret = -EPIPE;			break;		} 		if (pipe->nrbufs < pipe->buffers) {			int newbuf = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);			struct pipe_buffer *buf = pipe->bufs + newbuf; 			buf->page = spd->pages[page_nr];			buf->offset = spd->partial[page_nr].offset;			buf->len = spd->partial[page_nr].len;			buf->private = spd->partial[page_nr].private;			buf->ops = spd->ops;			if (spd->flags & SPLICE_F_GIFT)				buf->flags |= PIPE_BUF_FLAG_GIFT; 			pipe->nrbufs++;			page_nr++;			ret += buf->len; 			if (pipe->inode)				do_wakeup = 1; 			if (!--spd->nr_pages)				break;			if (pipe->nrbufs < pipe->buffers)				continue; 			break;		} 		if (spd->flags & SPLICE_F_NONBLOCK) {			if (!ret)				ret = -EAGAIN;			break;		} 		if (signal_pending(current)) {			if (!ret)				ret = -ERESTARTSYS;			break;		} 		if (do_wakeup) {			smp_mb();			if (waitqueue_active(&pipe->wait))				wake_up_interruptible_sync(&pipe->wait);			kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);			do_wakeup = 0;		} 		pipe->waiting_writers++;		pipe_wait(pipe);		pipe->waiting_writers--;	} 	pipe_unlock(pipe); 	if (do_wakeup)		wakeup_pipe_readers(pipe); 	while (page_nr < spd_pages)		spd->spd_release(spd, page_nr++); 	return ret;} void spd_release_page(struct splice_pipe_desc *spd, unsigned int i){	page_cache_release(spd->pages[i]);} /* * Check if we need to grow the arrays holding pages and partial page * descriptions. */int splice_grow_spd(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd){	if (pipe->buffers <= PIPE_DEF_BUFFERS)		return 0; 	spd->pages = kmalloc(pipe->buffers * sizeof(struct page *), GFP_KERNEL);	spd->partial = kmalloc(pipe->buffers * sizeof(struct partial_page), GFP_KERNEL); 	if (spd->pages && spd->partial)		return 0; 	kfree(spd->pages);	kfree(spd->partial);	return -ENOMEM;} void splice_shrink_spd(struct pipe_inode_info *pipe,		       struct splice_pipe_desc *spd){	if (pipe->buffers <= PIPE_DEF_BUFFERS)		return; 	kfree(spd->pages);	kfree(spd->partial);} static int__generic_file_splice_read(struct file *in, loff_t *ppos,			   struct pipe_inode_info *pipe, size_t len,			   unsigned int flags){	struct address_space *mapping = in->f_mapping;	unsigned int loff, nr_pages, req_pages;	struct page *pages[PIPE_DEF_BUFFERS];	struct partial_page partial[PIPE_DEF_BUFFERS];	struct page *page;	pgoff_t index, end_index;	loff_t isize;	int error, page_nr;	struct splice_pipe_desc spd = {		.pages = pages,		.partial = partial,		.flags = flags,		.ops = &page_cache_pipe_buf_ops,		.spd_release = spd_release_page,	}; 	if (splice_grow_spd(pipe, &spd))		return -ENOMEM; 	index = *ppos >> PAGE_CACHE_SHIFT;	loff = *ppos & ~PAGE_CACHE_MASK;	req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;	nr_pages = min(req_pages, pipe->buffers); 	/*	 * Lookup the (hopefully) full range of pages we need.	 */	spd.nr_pages = find_get_pages_contig(mapping, index, nr_pages, spd.pages);	index += spd.nr_pages; 	/*	 * If find_get_pages_contig() returned fewer pages than we needed,	 * readahead/allocate the rest and fill in the holes.	 */	if (spd.nr_pages < nr_pages)		page_cache_sync_readahead(mapping, &in->f_ra, in,				index, req_pages - spd.nr_pages); 	error = 0;	while (spd.nr_pages < nr_pages) {		/*		 * Page could be there, find_get_pages_contig() breaks on		 * the first hole.		 */		page = find_get_page(mapping, index);		if (!page) {			/*			 * page didn't exist, allocate one.			 */			page = page_cache_alloc_cold(mapping);			if (!page)				break; 			error = add_to_page_cache_lru(page, mapping, index,						GFP_KERNEL);			if (unlikely(error)) {				page_cache_release(page);				if (error == -EEXIST)					continue;				break;			}			/*			 * add_to_page_cache() locks the page, unlock it			 * to avoid convoluting the logic below even more.			 */			unlock_page(page);		} 		spd.pages[spd.nr_pages++] = page;		index++;	} 	/*	 * Now loop over the map and see if we need to start IO on any	 * pages, fill in the partial map, etc.	 */	index = *ppos >> PAGE_CACHE_SHIFT;	nr_pages = spd.nr_pages;	spd.nr_pages = 0;	for (page_nr = 0; page_nr < nr_pages; page_nr++) {		unsigned int this_len; 		if (!len)			break; 		/*		 * this_len is the max we'll use from this page		 */		this_len = min_t(unsigned long, len, PAGE_CACHE_SIZE - loff);		page = spd.pages[page_nr]; 		if (PageReadahead(page))			page_cache_async_readahead(mapping, &in->f_ra, in,					page, index, req_pages - page_nr); 		/*		 * If the page isn't uptodate, we may need to start io on it		 */		if (!PageUptodate(page)) {			lock_page(page); 			/*			 * Page was truncated, or invalidated by the			 * filesystem.  Redo the find/create, but this time the			 * page is kept locked, so there's no chance of another			 * race with truncate/invalidate.			 */			if (!page->mapping) {				unlock_page(page);				page = find_or_create_page(mapping, index,						mapping_gfp_mask(mapping)); 				if (!page) {					error = -ENOMEM;					break;				}				page_cache_release(spd.pages[page_nr]);				spd.pages[page_nr] = page;			}			/*			 * page was already under io and is now done, great			 */			if (PageUptodate(page)) {				unlock_page(page);				goto fill_it;			} 			/*			 * need to read in the page			 */			error = mapping->a_ops->readpage(in, page);			if (unlikely(error)) {				/*				 * We really should re-lookup the page here,				 * but it complicates things a lot. Instead				 * lets just do what we already stored, and				 * we'll get it the next time we are called.				 */				if (error == AOP_TRUNCATED_PAGE)					error = 0; 				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; 			/*			 * max good bytes in this page			 */			plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;			if (plen <= loff)				break; 			/*			 * force quit after adding this page			 */			this_len = min(this_len, plen - loff);			len = this_len;		} 		spd.partial[page_nr].offset = loff;		spd.partial[page_nr].len = this_len;		len -= this_len;		loff = 0;		spd.nr_pages++;		index++;	} 	/*	 * 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)		page_cache_release(spd.pages[page_nr++]);	in->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT; 	if (spd.nr_pages)		error = splice_to_pipe(pipe, &spd); 	splice_shrink_spd(pipe, &spd);

Lines 1–500 of 2045.