aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Axboe <axboe@suse.de>2006-05-01 13:59:03 -0400
committerJens Axboe <axboe@suse.de>2006-05-01 13:59:03 -0400
commitf84d751994441292593523c7069ed147176f6cab (patch)
treea1a0c4836289df86bb62e7eae5c80c66fca1643a
parent0568b409c74f7a125d92a09a3f386785700ef688 (diff)
[PATCH] pipe: introduce ->pin() buffer operation
The ->map() function is really expensive on highmem machines right now, since it has to use the slower kmap() instead of kmap_atomic(). Splice rarely needs to access the virtual address of a page, so it's a waste of time doing it. Introduce ->pin() to take over the responsibility of making sure the page data is valid. ->map() is then reduced to just kmap(). That way we can also share a most of the pipe buffer ops between pipe.c and splice.c Signed-off-by: Jens Axboe <axboe@suse.de>
-rw-r--r--fs/pipe.c39
-rw-r--r--fs/splice.c91
-rw-r--r--include/linux/pipe_fs_i.h21
3 files changed, 73 insertions, 78 deletions
diff --git a/fs/pipe.c b/fs/pipe.c
index 888f265011bf..d9644fd9cc0d 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -110,14 +110,14 @@ static void anon_pipe_buf_release(struct pipe_inode_info *pipe,
110 page_cache_release(page); 110 page_cache_release(page);
111} 111}
112 112
113static void * anon_pipe_buf_map(struct file *file, struct pipe_inode_info *pipe, 113void *generic_pipe_buf_map(struct pipe_inode_info *pipe,
114 struct pipe_buffer *buf) 114 struct pipe_buffer *buf)
115{ 115{
116 return kmap(buf->page); 116 return kmap(buf->page);
117} 117}
118 118
119static void anon_pipe_buf_unmap(struct pipe_inode_info *pipe, 119void generic_pipe_buf_unmap(struct pipe_inode_info *pipe,
120 struct pipe_buffer *buf) 120 struct pipe_buffer *buf)
121{ 121{
122 kunmap(buf->page); 122 kunmap(buf->page);
123} 123}
@@ -135,19 +135,24 @@ static int anon_pipe_buf_steal(struct pipe_inode_info *pipe,
135 return 1; 135 return 1;
136} 136}
137 137
138static void anon_pipe_buf_get(struct pipe_inode_info *info, 138void generic_pipe_buf_get(struct pipe_inode_info *info, struct pipe_buffer *buf)
139 struct pipe_buffer *buf)
140{ 139{
141 page_cache_get(buf->page); 140 page_cache_get(buf->page);
142} 141}
143 142
143int generic_pipe_buf_pin(struct pipe_inode_info *info, struct pipe_buffer *buf)
144{
145 return 0;
146}
147
144static struct pipe_buf_operations anon_pipe_buf_ops = { 148static struct pipe_buf_operations anon_pipe_buf_ops = {
145 .can_merge = 1, 149 .can_merge = 1,
146 .map = anon_pipe_buf_map, 150 .map = generic_pipe_buf_map,
147 .unmap = anon_pipe_buf_unmap, 151 .unmap = generic_pipe_buf_unmap,
152 .pin = generic_pipe_buf_pin,
148 .release = anon_pipe_buf_release, 153 .release = anon_pipe_buf_release,
149 .steal = anon_pipe_buf_steal, 154 .steal = anon_pipe_buf_steal,
150 .get = anon_pipe_buf_get, 155 .get = generic_pipe_buf_get,
151}; 156};
152 157
153static ssize_t 158static ssize_t
@@ -183,12 +188,14 @@ pipe_readv(struct file *filp, const struct iovec *_iov,
183 if (chars > total_len) 188 if (chars > total_len)
184 chars = total_len; 189 chars = total_len;
185 190
186 addr = ops->map(filp, pipe, buf); 191 error = ops->pin(pipe, buf);
187 if (IS_ERR(addr)) { 192 if (error) {
188 if (!ret) 193 if (!ret)
189 ret = PTR_ERR(addr); 194 error = ret;
190 break; 195 break;
191 } 196 }
197
198 addr = ops->map(pipe, buf);
192 error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars); 199 error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars);
193 ops->unmap(pipe, buf); 200 ops->unmap(pipe, buf);
194 if (unlikely(error)) { 201 if (unlikely(error)) {
@@ -300,11 +307,11 @@ pipe_writev(struct file *filp, const struct iovec *_iov,
300 void *addr; 307 void *addr;
301 int error; 308 int error;
302 309
303 addr = ops->map(filp, pipe, buf); 310 error = ops->pin(pipe, buf);
304 if (IS_ERR(addr)) { 311 if (error)
305 error = PTR_ERR(addr);
306 goto out; 312 goto out;
307 } 313
314 addr = ops->map(pipe, buf);
308 error = pipe_iov_copy_from_user(offset + addr, iov, 315 error = pipe_iov_copy_from_user(offset + addr, iov,
309 chars); 316 chars);
310 ops->unmap(pipe, buf); 317 ops->unmap(pipe, buf);
diff --git a/fs/splice.c b/fs/splice.c
index 1633778f3652..d7538d83c367 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -90,9 +90,8 @@ static void page_cache_pipe_buf_release(struct pipe_inode_info *info,
90 buf->flags &= ~PIPE_BUF_FLAG_LRU; 90 buf->flags &= ~PIPE_BUF_FLAG_LRU;
91} 91}
92 92
93static void *page_cache_pipe_buf_map(struct file *file, 93static int page_cache_pipe_buf_pin(struct pipe_inode_info *info,
94 struct pipe_inode_info *info, 94 struct pipe_buffer *buf)
95 struct pipe_buffer *buf)
96{ 95{
97 struct page *page = buf->page; 96 struct page *page = buf->page;
98 int err; 97 int err;
@@ -118,49 +117,25 @@ static void *page_cache_pipe_buf_map(struct file *file,
118 } 117 }
119 118
120 /* 119 /*
121 * Page is ok afterall, fall through to mapping. 120 * Page is ok afterall, we are done.
122 */ 121 */
123 unlock_page(page); 122 unlock_page(page);
124 } 123 }
125 124
126 return kmap(page); 125 return 0;
127error: 126error:
128 unlock_page(page); 127 unlock_page(page);
129 return ERR_PTR(err); 128 return err;
130}
131
132static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info,
133 struct pipe_buffer *buf)
134{
135 kunmap(buf->page);
136}
137
138static void *user_page_pipe_buf_map(struct file *file,
139 struct pipe_inode_info *pipe,
140 struct pipe_buffer *buf)
141{
142 return kmap(buf->page);
143}
144
145static void user_page_pipe_buf_unmap(struct pipe_inode_info *pipe,
146 struct pipe_buffer *buf)
147{
148 kunmap(buf->page);
149}
150
151static void page_cache_pipe_buf_get(struct pipe_inode_info *info,
152 struct pipe_buffer *buf)
153{
154 page_cache_get(buf->page);
155} 129}
156 130
157static struct pipe_buf_operations page_cache_pipe_buf_ops = { 131static struct pipe_buf_operations page_cache_pipe_buf_ops = {
158 .can_merge = 0, 132 .can_merge = 0,
159 .map = page_cache_pipe_buf_map, 133 .map = generic_pipe_buf_map,
160 .unmap = page_cache_pipe_buf_unmap, 134 .unmap = generic_pipe_buf_unmap,
135 .pin = page_cache_pipe_buf_pin,
161 .release = page_cache_pipe_buf_release, 136 .release = page_cache_pipe_buf_release,
162 .steal = page_cache_pipe_buf_steal, 137 .steal = page_cache_pipe_buf_steal,
163 .get = page_cache_pipe_buf_get, 138 .get = generic_pipe_buf_get,
164}; 139};
165 140
166static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe, 141static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe,
@@ -171,11 +146,12 @@ static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe,
171 146
172static struct pipe_buf_operations user_page_pipe_buf_ops = { 147static struct pipe_buf_operations user_page_pipe_buf_ops = {
173 .can_merge = 0, 148 .can_merge = 0,
174 .map = user_page_pipe_buf_map, 149 .map = generic_pipe_buf_map,
175 .unmap = user_page_pipe_buf_unmap, 150 .unmap = generic_pipe_buf_unmap,
151 .pin = generic_pipe_buf_pin,
176 .release = page_cache_pipe_buf_release, 152 .release = page_cache_pipe_buf_release,
177 .steal = user_page_pipe_buf_steal, 153 .steal = user_page_pipe_buf_steal,
178 .get = page_cache_pipe_buf_get, 154 .get = generic_pipe_buf_get,
179}; 155};
180 156
181/* 157/*
@@ -517,26 +493,16 @@ static int pipe_to_sendpage(struct pipe_inode_info *info,
517{ 493{
518 struct file *file = sd->file; 494 struct file *file = sd->file;
519 loff_t pos = sd->pos; 495 loff_t pos = sd->pos;
520 ssize_t ret; 496 int ret, more;
521 void *ptr;
522 int more;
523 497
524 /* 498 ret = buf->ops->pin(info, buf);
525 * Sub-optimal, but we are limited by the pipe ->map. We don't 499 if (!ret) {
526 * need a kmap'ed buffer here, we just want to make sure we 500 more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len;
527 * have the page pinned if the pipe page originates from the
528 * page cache.
529 */
530 ptr = buf->ops->map(file, info, buf);
531 if (IS_ERR(ptr))
532 return PTR_ERR(ptr);
533
534 more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len;
535 501
536 ret = file->f_op->sendpage(file, buf->page, buf->offset, sd->len, 502 ret = file->f_op->sendpage(file, buf->page, buf->offset,
537 &pos, more); 503 sd->len, &pos, more);
504 }
538 505
539 buf->ops->unmap(info, buf);
540 return ret; 506 return ret;
541} 507}
542 508
@@ -569,15 +535,14 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf,
569 unsigned int offset, this_len; 535 unsigned int offset, this_len;
570 struct page *page; 536 struct page *page;
571 pgoff_t index; 537 pgoff_t index;
572 char *src;
573 int ret; 538 int ret;
574 539
575 /* 540 /*
576 * make sure the data in this buffer is uptodate 541 * make sure the data in this buffer is uptodate
577 */ 542 */
578 src = buf->ops->map(file, info, buf); 543 ret = buf->ops->pin(info, buf);
579 if (IS_ERR(src)) 544 if (unlikely(ret))
580 return PTR_ERR(src); 545 return ret;
581 546
582 index = sd->pos >> PAGE_CACHE_SHIFT; 547 index = sd->pos >> PAGE_CACHE_SHIFT;
583 offset = sd->pos & ~PAGE_CACHE_MASK; 548 offset = sd->pos & ~PAGE_CACHE_MASK;
@@ -666,11 +631,16 @@ find_page:
666 goto out; 631 goto out;
667 632
668 if (buf->page != page) { 633 if (buf->page != page) {
669 char *dst = kmap_atomic(page, KM_USER0); 634 /*
635 * Careful, ->map() uses KM_USER0!
636 */
637 char *src = buf->ops->map(info, buf);
638 char *dst = kmap_atomic(page, KM_USER1);
670 639
671 memcpy(dst + offset, src + buf->offset, this_len); 640 memcpy(dst + offset, src + buf->offset, this_len);
672 flush_dcache_page(page); 641 flush_dcache_page(page);
673 kunmap_atomic(dst, KM_USER0); 642 kunmap_atomic(dst, KM_USER1);
643 buf->ops->unmap(info, buf);
674 } 644 }
675 645
676 ret = mapping->a_ops->commit_write(file, page, offset, offset+this_len); 646 ret = mapping->a_ops->commit_write(file, page, offset, offset+this_len);
@@ -690,7 +660,6 @@ out:
690 page_cache_release(page); 660 page_cache_release(page);
691 unlock_page(page); 661 unlock_page(page);
692out_nomem: 662out_nomem:
693 buf->ops->unmap(info, buf);
694 return ret; 663 return ret;
695} 664}
696 665
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
index 3130977fc6ab..b8aae1fc5185 100644
--- a/include/linux/pipe_fs_i.h
+++ b/include/linux/pipe_fs_i.h
@@ -14,10 +14,23 @@ struct pipe_buffer {
14 unsigned int flags; 14 unsigned int flags;
15}; 15};
16 16
17/*
18 * Note on the nesting of these functions:
19 *
20 * ->pin()
21 * ->steal()
22 * ...
23 * ->map()
24 * ...
25 * ->unmap()
26 *
27 * That is, ->map() must be called on a pinned buffer, same goes for ->steal().
28 */
17struct pipe_buf_operations { 29struct pipe_buf_operations {
18 int can_merge; 30 int can_merge;
19 void * (*map)(struct file *, struct pipe_inode_info *, struct pipe_buffer *); 31 void * (*map)(struct pipe_inode_info *, struct pipe_buffer *);
20 void (*unmap)(struct pipe_inode_info *, struct pipe_buffer *); 32 void (*unmap)(struct pipe_inode_info *, struct pipe_buffer *);
33 int (*pin)(struct pipe_inode_info *, struct pipe_buffer *);
21 void (*release)(struct pipe_inode_info *, struct pipe_buffer *); 34 void (*release)(struct pipe_inode_info *, struct pipe_buffer *);
22 int (*steal)(struct pipe_inode_info *, struct pipe_buffer *); 35 int (*steal)(struct pipe_inode_info *, struct pipe_buffer *);
23 void (*get)(struct pipe_inode_info *, struct pipe_buffer *); 36 void (*get)(struct pipe_inode_info *, struct pipe_buffer *);
@@ -50,6 +63,12 @@ struct pipe_inode_info * alloc_pipe_info(struct inode * inode);
50void free_pipe_info(struct inode * inode); 63void free_pipe_info(struct inode * inode);
51void __free_pipe_info(struct pipe_inode_info *); 64void __free_pipe_info(struct pipe_inode_info *);
52 65
66/* Generic pipe buffer ops functions */
67void *generic_pipe_buf_map(struct pipe_inode_info *, struct pipe_buffer *);
68void generic_pipe_buf_unmap(struct pipe_inode_info *, struct pipe_buffer *);
69void generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *);
70int generic_pipe_buf_pin(struct pipe_inode_info *, struct pipe_buffer *);
71
53/* 72/*
54 * splice is tied to pipes as a transport (at least for now), so we'll just 73 * splice is tied to pipes as a transport (at least for now), so we'll just
55 * add the splice flags here. 74 * add the splice flags here.