Commit 5212c555 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'splice-2.6.22' of git://git.kernel.dk/data/git/linux-2.6-block

* 'splice-2.6.22' of git://git.kernel.dk/data/git/linux-2.6-block:
  splice: __generic_file_splice_read: fix read/truncate race
  splice: __generic_file_splice_read: fix i_size_read() length checks
  splice: move balance_dirty_pages_ratelimited() outside of splice actor
  pipe: move pipe_inode_info structure decleration up before it's used
  splice: remove do_splice_direct() symbol export
  splice: move inode size check into generic_file_splice_read()
parents 845a2fdc 620a324b
...@@ -272,7 +272,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, ...@@ -272,7 +272,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
struct page *page; struct page *page;
pgoff_t index, end_index; pgoff_t index, end_index;
loff_t isize; loff_t isize;
size_t total_len;
int error, page_nr; int error, page_nr;
struct splice_pipe_desc spd = { struct splice_pipe_desc spd = {
.pages = pages, .pages = pages,
...@@ -298,7 +297,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, ...@@ -298,7 +297,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
* Now fill in the holes: * Now fill in the holes:
*/ */
error = 0; error = 0;
total_len = 0;
/* /*
* Lookup the (hopefully) full range of pages we need. * Lookup the (hopefully) full range of pages we need.
...@@ -415,43 +413,47 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, ...@@ -415,43 +413,47 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
break; 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); plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
end_index = (isize - 1) >> PAGE_CACHE_SHIFT; if (plen <= loff)
if (unlikely(!isize || index > end_index))
break; break;
/* /*
* if this is the last page, see if we need to shrink * force quit after adding this page
* the length and stop
*/ */
if (end_index == index) { this_len = min(this_len, plen - loff);
loff = PAGE_CACHE_SIZE - (isize & ~PAGE_CACHE_MASK); len = this_len;
if (total_len + loff > isize)
break;
/*
* force quit after adding this page
*/
len = this_len;
this_len = min(this_len, loff);
loff = 0;
}
} }
fill_it:
partial[page_nr].offset = loff; partial[page_nr].offset = loff;
partial[page_nr].len = this_len; partial[page_nr].len = this_len;
len -= this_len; len -= this_len;
total_len += this_len;
loff = 0; loff = 0;
spd.nr_pages++; spd.nr_pages++;
index++; 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. * we got, 'nr_pages' is how many pages are in the map.
*/ */
while (page_nr < nr_pages) while (page_nr < nr_pages)
...@@ -478,10 +480,18 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, ...@@ -478,10 +480,18 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
{ {
ssize_t spliced; ssize_t spliced;
int ret; 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; ret = 0;
spliced = 0; spliced = 0;
while (len) { while (len) {
ret = __generic_file_splice_read(in, ppos, pipe, len, flags); ret = __generic_file_splice_read(in, ppos, pipe, len, flags);
...@@ -644,7 +654,6 @@ static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, ...@@ -644,7 +654,6 @@ static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
* accessed, we are now done! * accessed, we are now done!
*/ */
mark_page_accessed(page); mark_page_accessed(page);
balance_dirty_pages_ratelimited(mapping);
out: out:
page_cache_release(page); page_cache_release(page);
unlock_page(page); unlock_page(page);
...@@ -815,6 +824,7 @@ generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out, ...@@ -815,6 +824,7 @@ generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out,
if (err) if (err)
ret = err; ret = err;
} }
balance_dirty_pages_ratelimited(mapping);
} }
return ret; return ret;
...@@ -868,6 +878,7 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, ...@@ -868,6 +878,7 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
if (err) if (err)
ret = err; ret = err;
} }
balance_dirty_pages_ratelimited(mapping);
} }
return ret; return ret;
...@@ -922,7 +933,6 @@ static long do_splice_to(struct file *in, loff_t *ppos, ...@@ -922,7 +933,6 @@ static long do_splice_to(struct file *in, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len, struct pipe_inode_info *pipe, size_t len,
unsigned int flags) unsigned int flags)
{ {
loff_t isize, left;
int ret; int ret;
if (unlikely(!in->f_op || !in->f_op->splice_read)) if (unlikely(!in->f_op || !in->f_op->splice_read))
...@@ -935,14 +945,6 @@ static long do_splice_to(struct file *in, loff_t *ppos, ...@@ -935,14 +945,6 @@ static long do_splice_to(struct file *in, loff_t *ppos,
if (unlikely(ret < 0)) if (unlikely(ret < 0))
return ret; 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); return in->f_op->splice_read(in, ppos, pipe, len, flags);
} }
...@@ -1058,8 +1060,6 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, ...@@ -1058,8 +1060,6 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
return ret; return ret;
} }
EXPORT_SYMBOL(do_splice_direct);
/* /*
* After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same * 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 * location, so checking ->i_pipe is not enough to verify that this is a
......
...@@ -16,6 +16,21 @@ struct pipe_buffer { ...@@ -16,6 +16,21 @@ struct pipe_buffer {
unsigned int flags; unsigned int flags;
}; };
struct pipe_inode_info {
wait_queue_head_t wait;
unsigned int nrbufs, curbuf;
struct page *tmp_page;
unsigned int readers;
unsigned int writers;
unsigned int waiting_writers;
unsigned int r_counter;
unsigned int w_counter;
struct fasync_struct *fasync_readers;
struct fasync_struct *fasync_writers;
struct inode *inode;
struct pipe_buffer bufs[PIPE_BUFFERS];
};
/* /*
* Note on the nesting of these functions: * Note on the nesting of these functions:
* *
...@@ -38,21 +53,6 @@ struct pipe_buf_operations { ...@@ -38,21 +53,6 @@ struct pipe_buf_operations {
void (*get)(struct pipe_inode_info *, struct pipe_buffer *); void (*get)(struct pipe_inode_info *, struct pipe_buffer *);
}; };
struct pipe_inode_info {
wait_queue_head_t wait;
unsigned int nrbufs, curbuf;
struct page *tmp_page;
unsigned int readers;
unsigned int writers;
unsigned int waiting_writers;
unsigned int r_counter;
unsigned int w_counter;
struct fasync_struct *fasync_readers;
struct fasync_struct *fasync_writers;
struct inode *inode;
struct pipe_buffer bufs[PIPE_BUFFERS];
};
/* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual /* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual
memory allocation, whereas PIPE_BUF makes atomicity guarantees. */ memory allocation, whereas PIPE_BUF makes atomicity guarantees. */
#define PIPE_SIZE PAGE_SIZE #define PIPE_SIZE PAGE_SIZE
......
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