diff options
Diffstat (limited to 'fs/pipe.c')
-rw-r--r-- | fs/pipe.c | 52 |
1 files changed, 41 insertions, 11 deletions
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/pipe_fs_i.h> | 15 | #include <linux/pipe_fs_i.h> |
16 | #include <linux/uio.h> | 16 | #include <linux/uio.h> |
17 | #include <linux/highmem.h> | 17 | #include <linux/highmem.h> |
18 | #include <linux/pagemap.h> | ||
18 | 19 | ||
19 | #include <asm/uaccess.h> | 20 | #include <asm/uaccess.h> |
20 | #include <asm/ioctls.h> | 21 | #include <asm/ioctls.h> |
@@ -94,11 +95,20 @@ static void anon_pipe_buf_release(struct pipe_inode_info *info, struct pipe_buff | |||
94 | { | 95 | { |
95 | struct page *page = buf->page; | 96 | struct page *page = buf->page; |
96 | 97 | ||
97 | if (info->tmp_page) { | 98 | /* |
98 | __free_page(page); | 99 | * If nobody else uses this page, and we don't already have a |
100 | * temporary page, let's keep track of it as a one-deep | ||
101 | * allocation cache | ||
102 | */ | ||
103 | if (page_count(page) == 1 && !info->tmp_page) { | ||
104 | info->tmp_page = page; | ||
99 | return; | 105 | return; |
100 | } | 106 | } |
101 | info->tmp_page = page; | 107 | |
108 | /* | ||
109 | * Otherwise just release our reference to it | ||
110 | */ | ||
111 | page_cache_release(page); | ||
102 | } | 112 | } |
103 | 113 | ||
104 | static void *anon_pipe_buf_map(struct file *file, struct pipe_inode_info *info, struct pipe_buffer *buf) | 114 | static void *anon_pipe_buf_map(struct file *file, struct pipe_inode_info *info, struct pipe_buffer *buf) |
@@ -111,11 +121,19 @@ static void anon_pipe_buf_unmap(struct pipe_inode_info *info, struct pipe_buffer | |||
111 | kunmap(buf->page); | 121 | kunmap(buf->page); |
112 | } | 122 | } |
113 | 123 | ||
124 | static int anon_pipe_buf_steal(struct pipe_inode_info *info, | ||
125 | struct pipe_buffer *buf) | ||
126 | { | ||
127 | buf->stolen = 1; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
114 | static struct pipe_buf_operations anon_pipe_buf_ops = { | 131 | static struct pipe_buf_operations anon_pipe_buf_ops = { |
115 | .can_merge = 1, | 132 | .can_merge = 1, |
116 | .map = anon_pipe_buf_map, | 133 | .map = anon_pipe_buf_map, |
117 | .unmap = anon_pipe_buf_unmap, | 134 | .unmap = anon_pipe_buf_unmap, |
118 | .release = anon_pipe_buf_release, | 135 | .release = anon_pipe_buf_release, |
136 | .steal = anon_pipe_buf_steal, | ||
119 | }; | 137 | }; |
120 | 138 | ||
121 | static ssize_t | 139 | static ssize_t |
@@ -152,6 +170,11 @@ pipe_readv(struct file *filp, const struct iovec *_iov, | |||
152 | chars = total_len; | 170 | chars = total_len; |
153 | 171 | ||
154 | addr = ops->map(filp, info, buf); | 172 | addr = ops->map(filp, info, buf); |
173 | if (IS_ERR(addr)) { | ||
174 | if (!ret) | ||
175 | ret = PTR_ERR(addr); | ||
176 | break; | ||
177 | } | ||
155 | error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars); | 178 | error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars); |
156 | ops->unmap(info, buf); | 179 | ops->unmap(info, buf); |
157 | if (unlikely(error)) { | 180 | if (unlikely(error)) { |
@@ -254,8 +277,16 @@ pipe_writev(struct file *filp, const struct iovec *_iov, | |||
254 | struct pipe_buf_operations *ops = buf->ops; | 277 | struct pipe_buf_operations *ops = buf->ops; |
255 | int offset = buf->offset + buf->len; | 278 | int offset = buf->offset + buf->len; |
256 | if (ops->can_merge && offset + chars <= PAGE_SIZE) { | 279 | if (ops->can_merge && offset + chars <= PAGE_SIZE) { |
257 | void *addr = ops->map(filp, info, buf); | 280 | void *addr; |
258 | int error = pipe_iov_copy_from_user(offset + addr, iov, chars); | 281 | int error; |
282 | |||
283 | addr = ops->map(filp, info, buf); | ||
284 | if (IS_ERR(addr)) { | ||
285 | error = PTR_ERR(addr); | ||
286 | goto out; | ||
287 | } | ||
288 | error = pipe_iov_copy_from_user(offset + addr, iov, | ||
289 | chars); | ||
259 | ops->unmap(info, buf); | 290 | ops->unmap(info, buf); |
260 | ret = error; | 291 | ret = error; |
261 | do_wakeup = 1; | 292 | do_wakeup = 1; |
@@ -568,7 +599,7 @@ pipe_rdwr_open(struct inode *inode, struct file *filp) | |||
568 | * The file_operations structs are not static because they | 599 | * The file_operations structs are not static because they |
569 | * are also used in linux/fs/fifo.c to do operations on FIFOs. | 600 | * are also used in linux/fs/fifo.c to do operations on FIFOs. |
570 | */ | 601 | */ |
571 | struct file_operations read_fifo_fops = { | 602 | const struct file_operations read_fifo_fops = { |
572 | .llseek = no_llseek, | 603 | .llseek = no_llseek, |
573 | .read = pipe_read, | 604 | .read = pipe_read, |
574 | .readv = pipe_readv, | 605 | .readv = pipe_readv, |
@@ -580,7 +611,7 @@ struct file_operations read_fifo_fops = { | |||
580 | .fasync = pipe_read_fasync, | 611 | .fasync = pipe_read_fasync, |
581 | }; | 612 | }; |
582 | 613 | ||
583 | struct file_operations write_fifo_fops = { | 614 | const struct file_operations write_fifo_fops = { |
584 | .llseek = no_llseek, | 615 | .llseek = no_llseek, |
585 | .read = bad_pipe_r, | 616 | .read = bad_pipe_r, |
586 | .write = pipe_write, | 617 | .write = pipe_write, |
@@ -592,7 +623,7 @@ struct file_operations write_fifo_fops = { | |||
592 | .fasync = pipe_write_fasync, | 623 | .fasync = pipe_write_fasync, |
593 | }; | 624 | }; |
594 | 625 | ||
595 | struct file_operations rdwr_fifo_fops = { | 626 | const struct file_operations rdwr_fifo_fops = { |
596 | .llseek = no_llseek, | 627 | .llseek = no_llseek, |
597 | .read = pipe_read, | 628 | .read = pipe_read, |
598 | .readv = pipe_readv, | 629 | .readv = pipe_readv, |
@@ -662,10 +693,9 @@ struct inode* pipe_new(struct inode* inode) | |||
662 | { | 693 | { |
663 | struct pipe_inode_info *info; | 694 | struct pipe_inode_info *info; |
664 | 695 | ||
665 | info = kmalloc(sizeof(struct pipe_inode_info), GFP_KERNEL); | 696 | info = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL); |
666 | if (!info) | 697 | if (!info) |
667 | goto fail_page; | 698 | goto fail_page; |
668 | memset(info, 0, sizeof(*info)); | ||
669 | inode->i_pipe = info; | 699 | inode->i_pipe = info; |
670 | 700 | ||
671 | init_waitqueue_head(PIPE_WAIT(*inode)); | 701 | init_waitqueue_head(PIPE_WAIT(*inode)); |
@@ -676,7 +706,7 @@ fail_page: | |||
676 | return NULL; | 706 | return NULL; |
677 | } | 707 | } |
678 | 708 | ||
679 | static struct vfsmount *pipe_mnt; | 709 | static struct vfsmount *pipe_mnt __read_mostly; |
680 | static int pipefs_delete_dentry(struct dentry *dentry) | 710 | static int pipefs_delete_dentry(struct dentry *dentry) |
681 | { | 711 | { |
682 | return 1; | 712 | return 1; |