aboutsummaryrefslogtreecommitdiffstats
path: root/fs/pipe.c
diff options
context:
space:
mode:
authorJens Axboe <jens.axboe@oracle.com>2010-05-20 04:43:18 -0400
committerJens Axboe <jens.axboe@oracle.com>2010-05-21 15:12:40 -0400
commit35f3d14dbbc58447c61e38a162ea10add6b31dc7 (patch)
tree3e03cd540b7dcdac82195c4e76862c0ce6daaaf0 /fs/pipe.c
parent3d42b3612891baecf709d93f28655a6882a65d41 (diff)
pipe: add support for shrinking and growing pipes
This patch adds F_GETPIPE_SZ and F_SETPIPE_SZ fcntl() actions for growing and shrinking the size of a pipe and adjusts pipe.c and splice.c (and relay and network splice) usage to work with these larger (or smaller) pipes. Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'fs/pipe.c')
-rw-r--r--fs/pipe.c107
1 files changed, 95 insertions, 12 deletions
diff --git a/fs/pipe.c b/fs/pipe.c
index 37ba29ff3158..054b8a6a2c7a 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -11,6 +11,7 @@
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/fs.h> 13#include <linux/fs.h>
14#include <linux/log2.h>
14#include <linux/mount.h> 15#include <linux/mount.h>
15#include <linux/pipe_fs_i.h> 16#include <linux/pipe_fs_i.h>
16#include <linux/uio.h> 17#include <linux/uio.h>
@@ -390,7 +391,7 @@ redo:
390 if (!buf->len) { 391 if (!buf->len) {
391 buf->ops = NULL; 392 buf->ops = NULL;
392 ops->release(pipe, buf); 393 ops->release(pipe, buf);
393 curbuf = (curbuf + 1) & (PIPE_BUFFERS-1); 394 curbuf = (curbuf + 1) & (pipe->buffers - 1);
394 pipe->curbuf = curbuf; 395 pipe->curbuf = curbuf;
395 pipe->nrbufs = --bufs; 396 pipe->nrbufs = --bufs;
396 do_wakeup = 1; 397 do_wakeup = 1;
@@ -472,7 +473,7 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov,
472 chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */ 473 chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */
473 if (pipe->nrbufs && chars != 0) { 474 if (pipe->nrbufs && chars != 0) {
474 int lastbuf = (pipe->curbuf + pipe->nrbufs - 1) & 475 int lastbuf = (pipe->curbuf + pipe->nrbufs - 1) &
475 (PIPE_BUFFERS-1); 476 (pipe->buffers - 1);
476 struct pipe_buffer *buf = pipe->bufs + lastbuf; 477 struct pipe_buffer *buf = pipe->bufs + lastbuf;
477 const struct pipe_buf_operations *ops = buf->ops; 478 const struct pipe_buf_operations *ops = buf->ops;
478 int offset = buf->offset + buf->len; 479 int offset = buf->offset + buf->len;
@@ -518,8 +519,8 @@ redo1:
518 break; 519 break;
519 } 520 }
520 bufs = pipe->nrbufs; 521 bufs = pipe->nrbufs;
521 if (bufs < PIPE_BUFFERS) { 522 if (bufs < pipe->buffers) {
522 int newbuf = (pipe->curbuf + bufs) & (PIPE_BUFFERS-1); 523 int newbuf = (pipe->curbuf + bufs) & (pipe->buffers-1);
523 struct pipe_buffer *buf = pipe->bufs + newbuf; 524 struct pipe_buffer *buf = pipe->bufs + newbuf;
524 struct page *page = pipe->tmp_page; 525 struct page *page = pipe->tmp_page;
525 char *src; 526 char *src;
@@ -580,7 +581,7 @@ redo2:
580 if (!total_len) 581 if (!total_len)
581 break; 582 break;
582 } 583 }
583 if (bufs < PIPE_BUFFERS) 584 if (bufs < pipe->buffers)
584 continue; 585 continue;
585 if (filp->f_flags & O_NONBLOCK) { 586 if (filp->f_flags & O_NONBLOCK) {
586 if (!ret) 587 if (!ret)
@@ -640,7 +641,7 @@ static long pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
640 nrbufs = pipe->nrbufs; 641 nrbufs = pipe->nrbufs;
641 while (--nrbufs >= 0) { 642 while (--nrbufs >= 0) {
642 count += pipe->bufs[buf].len; 643 count += pipe->bufs[buf].len;
643 buf = (buf+1) & (PIPE_BUFFERS-1); 644 buf = (buf+1) & (pipe->buffers - 1);
644 } 645 }
645 mutex_unlock(&inode->i_mutex); 646 mutex_unlock(&inode->i_mutex);
646 647
@@ -671,7 +672,7 @@ pipe_poll(struct file *filp, poll_table *wait)
671 } 672 }
672 673
673 if (filp->f_mode & FMODE_WRITE) { 674 if (filp->f_mode & FMODE_WRITE) {
674 mask |= (nrbufs < PIPE_BUFFERS) ? POLLOUT | POLLWRNORM : 0; 675 mask |= (nrbufs < pipe->buffers) ? POLLOUT | POLLWRNORM : 0;
675 /* 676 /*
676 * Most Unices do not set POLLERR for FIFOs but on Linux they 677 * Most Unices do not set POLLERR for FIFOs but on Linux they
677 * behave exactly like pipes for poll(). 678 * behave exactly like pipes for poll().
@@ -877,25 +878,32 @@ struct pipe_inode_info * alloc_pipe_info(struct inode *inode)
877 878
878 pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL); 879 pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
879 if (pipe) { 880 if (pipe) {
880 init_waitqueue_head(&pipe->wait); 881 pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * PIPE_DEF_BUFFERS, GFP_KERNEL);
881 pipe->r_counter = pipe->w_counter = 1; 882 if (pipe->bufs) {
882 pipe->inode = inode; 883 init_waitqueue_head(&pipe->wait);
884 pipe->r_counter = pipe->w_counter = 1;
885 pipe->inode = inode;
886 pipe->buffers = PIPE_DEF_BUFFERS;
887 return pipe;
888 }
889 kfree(pipe);
883 } 890 }
884 891
885 return pipe; 892 return NULL;
886} 893}
887 894
888void __free_pipe_info(struct pipe_inode_info *pipe) 895void __free_pipe_info(struct pipe_inode_info *pipe)
889{ 896{
890 int i; 897 int i;
891 898
892 for (i = 0; i < PIPE_BUFFERS; i++) { 899 for (i = 0; i < pipe->buffers; i++) {
893 struct pipe_buffer *buf = pipe->bufs + i; 900 struct pipe_buffer *buf = pipe->bufs + i;
894 if (buf->ops) 901 if (buf->ops)
895 buf->ops->release(pipe, buf); 902 buf->ops->release(pipe, buf);
896 } 903 }
897 if (pipe->tmp_page) 904 if (pipe->tmp_page)
898 __free_page(pipe->tmp_page); 905 __free_page(pipe->tmp_page);
906 kfree(pipe->bufs);
899 kfree(pipe); 907 kfree(pipe);
900} 908}
901 909
@@ -1094,6 +1102,81 @@ SYSCALL_DEFINE1(pipe, int __user *, fildes)
1094} 1102}
1095 1103
1096/* 1104/*
1105 * Allocate a new array of pipe buffers and copy the info over. Returns the
1106 * pipe size if successful, or return -ERROR on error.
1107 */
1108static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
1109{
1110 struct pipe_buffer *bufs;
1111
1112 /*
1113 * Must be a power-of-2 currently
1114 */
1115 if (!is_power_of_2(arg))
1116 return -EINVAL;
1117
1118 /*
1119 * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't
1120 * expect a lot of shrink+grow operations, just free and allocate
1121 * again like we would do for growing. If the pipe currently
1122 * contains more buffers than arg, then return busy.
1123 */
1124 if (arg < pipe->nrbufs)
1125 return -EBUSY;
1126
1127 bufs = kcalloc(arg, sizeof(struct pipe_buffer), GFP_KERNEL);
1128 if (unlikely(!bufs))
1129 return -ENOMEM;
1130
1131 /*
1132 * The pipe array wraps around, so just start the new one at zero
1133 * and adjust the indexes.
1134 */
1135 if (pipe->nrbufs) {
1136 const unsigned int tail = pipe->nrbufs & (pipe->buffers - 1);
1137 const unsigned int head = pipe->nrbufs - tail;
1138
1139 if (head)
1140 memcpy(bufs, pipe->bufs + pipe->curbuf, head * sizeof(struct pipe_buffer));
1141 if (tail)
1142 memcpy(bufs + head, pipe->bufs + pipe->curbuf, tail * sizeof(struct pipe_buffer));
1143 }
1144
1145 pipe->curbuf = 0;
1146 kfree(pipe->bufs);
1147 pipe->bufs = bufs;
1148 pipe->buffers = arg;
1149 return arg;
1150}
1151
1152long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
1153{
1154 struct pipe_inode_info *pipe;
1155 long ret;
1156
1157 pipe = file->f_path.dentry->d_inode->i_pipe;
1158 if (!pipe)
1159 return -EBADF;
1160
1161 mutex_lock(&pipe->inode->i_mutex);
1162
1163 switch (cmd) {
1164 case F_SETPIPE_SZ:
1165 ret = pipe_set_size(pipe, arg);
1166 break;
1167 case F_GETPIPE_SZ:
1168 ret = pipe->buffers;
1169 break;
1170 default:
1171 ret = -EINVAL;
1172 break;
1173 }
1174
1175 mutex_unlock(&pipe->inode->i_mutex);
1176 return ret;
1177}
1178
1179/*
1097 * pipefs should _never_ be mounted by userland - too much of security hassle, 1180 * pipefs should _never_ be mounted by userland - too much of security hassle,
1098 * no real gain from having the whole whorehouse mounted. So we don't need 1181 * no real gain from having the whole whorehouse mounted. So we don't need
1099 * any operations on the root directory. However, we need a non-trivial 1182 * any operations on the root directory. However, we need a non-trivial