diff options
Diffstat (limited to 'fs/pipe.c')
| -rw-r--r-- | fs/pipe.c | 122 |
1 files changed, 110 insertions, 12 deletions
| @@ -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> |
| @@ -18,11 +19,18 @@ | |||
| 18 | #include <linux/pagemap.h> | 19 | #include <linux/pagemap.h> |
| 19 | #include <linux/audit.h> | 20 | #include <linux/audit.h> |
| 20 | #include <linux/syscalls.h> | 21 | #include <linux/syscalls.h> |
| 22 | #include <linux/fcntl.h> | ||
| 21 | 23 | ||
| 22 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
| 23 | #include <asm/ioctls.h> | 25 | #include <asm/ioctls.h> |
| 24 | 26 | ||
| 25 | /* | 27 | /* |
| 28 | * The max size that a non-root user is allowed to grow the pipe. Can | ||
| 29 | * be set by root in /proc/sys/fs/pipe-max-pages | ||
| 30 | */ | ||
| 31 | unsigned int pipe_max_pages = PIPE_DEF_BUFFERS * 16; | ||
| 32 | |||
| 33 | /* | ||
| 26 | * We use a start+len construction, which provides full use of the | 34 | * We use a start+len construction, which provides full use of the |
| 27 | * allocated memory. | 35 | * allocated memory. |
| 28 | * -- Florian Coosmann (FGC) | 36 | * -- Florian Coosmann (FGC) |
| @@ -390,7 +398,7 @@ redo: | |||
| 390 | if (!buf->len) { | 398 | if (!buf->len) { |
| 391 | buf->ops = NULL; | 399 | buf->ops = NULL; |
| 392 | ops->release(pipe, buf); | 400 | ops->release(pipe, buf); |
| 393 | curbuf = (curbuf + 1) & (PIPE_BUFFERS-1); | 401 | curbuf = (curbuf + 1) & (pipe->buffers - 1); |
| 394 | pipe->curbuf = curbuf; | 402 | pipe->curbuf = curbuf; |
| 395 | pipe->nrbufs = --bufs; | 403 | pipe->nrbufs = --bufs; |
| 396 | do_wakeup = 1; | 404 | do_wakeup = 1; |
| @@ -472,7 +480,7 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov, | |||
| 472 | chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */ | 480 | chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */ |
| 473 | if (pipe->nrbufs && chars != 0) { | 481 | if (pipe->nrbufs && chars != 0) { |
| 474 | int lastbuf = (pipe->curbuf + pipe->nrbufs - 1) & | 482 | int lastbuf = (pipe->curbuf + pipe->nrbufs - 1) & |
| 475 | (PIPE_BUFFERS-1); | 483 | (pipe->buffers - 1); |
| 476 | struct pipe_buffer *buf = pipe->bufs + lastbuf; | 484 | struct pipe_buffer *buf = pipe->bufs + lastbuf; |
| 477 | const struct pipe_buf_operations *ops = buf->ops; | 485 | const struct pipe_buf_operations *ops = buf->ops; |
| 478 | int offset = buf->offset + buf->len; | 486 | int offset = buf->offset + buf->len; |
| @@ -518,8 +526,8 @@ redo1: | |||
| 518 | break; | 526 | break; |
| 519 | } | 527 | } |
| 520 | bufs = pipe->nrbufs; | 528 | bufs = pipe->nrbufs; |
| 521 | if (bufs < PIPE_BUFFERS) { | 529 | if (bufs < pipe->buffers) { |
| 522 | int newbuf = (pipe->curbuf + bufs) & (PIPE_BUFFERS-1); | 530 | int newbuf = (pipe->curbuf + bufs) & (pipe->buffers-1); |
| 523 | struct pipe_buffer *buf = pipe->bufs + newbuf; | 531 | struct pipe_buffer *buf = pipe->bufs + newbuf; |
| 524 | struct page *page = pipe->tmp_page; | 532 | struct page *page = pipe->tmp_page; |
| 525 | char *src; | 533 | char *src; |
| @@ -580,7 +588,7 @@ redo2: | |||
| 580 | if (!total_len) | 588 | if (!total_len) |
| 581 | break; | 589 | break; |
| 582 | } | 590 | } |
| 583 | if (bufs < PIPE_BUFFERS) | 591 | if (bufs < pipe->buffers) |
| 584 | continue; | 592 | continue; |
| 585 | if (filp->f_flags & O_NONBLOCK) { | 593 | if (filp->f_flags & O_NONBLOCK) { |
| 586 | if (!ret) | 594 | if (!ret) |
| @@ -640,7 +648,7 @@ static long pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
| 640 | nrbufs = pipe->nrbufs; | 648 | nrbufs = pipe->nrbufs; |
| 641 | while (--nrbufs >= 0) { | 649 | while (--nrbufs >= 0) { |
| 642 | count += pipe->bufs[buf].len; | 650 | count += pipe->bufs[buf].len; |
| 643 | buf = (buf+1) & (PIPE_BUFFERS-1); | 651 | buf = (buf+1) & (pipe->buffers - 1); |
| 644 | } | 652 | } |
| 645 | mutex_unlock(&inode->i_mutex); | 653 | mutex_unlock(&inode->i_mutex); |
| 646 | 654 | ||
| @@ -671,7 +679,7 @@ pipe_poll(struct file *filp, poll_table *wait) | |||
| 671 | } | 679 | } |
| 672 | 680 | ||
| 673 | if (filp->f_mode & FMODE_WRITE) { | 681 | if (filp->f_mode & FMODE_WRITE) { |
| 674 | mask |= (nrbufs < PIPE_BUFFERS) ? POLLOUT | POLLWRNORM : 0; | 682 | mask |= (nrbufs < pipe->buffers) ? POLLOUT | POLLWRNORM : 0; |
| 675 | /* | 683 | /* |
| 676 | * Most Unices do not set POLLERR for FIFOs but on Linux they | 684 | * Most Unices do not set POLLERR for FIFOs but on Linux they |
| 677 | * behave exactly like pipes for poll(). | 685 | * behave exactly like pipes for poll(). |
| @@ -877,25 +885,32 @@ struct pipe_inode_info * alloc_pipe_info(struct inode *inode) | |||
| 877 | 885 | ||
| 878 | pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL); | 886 | pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL); |
| 879 | if (pipe) { | 887 | if (pipe) { |
| 880 | init_waitqueue_head(&pipe->wait); | 888 | pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * PIPE_DEF_BUFFERS, GFP_KERNEL); |
| 881 | pipe->r_counter = pipe->w_counter = 1; | 889 | if (pipe->bufs) { |
| 882 | pipe->inode = inode; | 890 | init_waitqueue_head(&pipe->wait); |
| 891 | pipe->r_counter = pipe->w_counter = 1; | ||
| 892 | pipe->inode = inode; | ||
| 893 | pipe->buffers = PIPE_DEF_BUFFERS; | ||
| 894 | return pipe; | ||
| 895 | } | ||
| 896 | kfree(pipe); | ||
| 883 | } | 897 | } |
| 884 | 898 | ||
| 885 | return pipe; | 899 | return NULL; |
| 886 | } | 900 | } |
| 887 | 901 | ||
| 888 | void __free_pipe_info(struct pipe_inode_info *pipe) | 902 | void __free_pipe_info(struct pipe_inode_info *pipe) |
| 889 | { | 903 | { |
| 890 | int i; | 904 | int i; |
| 891 | 905 | ||
| 892 | for (i = 0; i < PIPE_BUFFERS; i++) { | 906 | for (i = 0; i < pipe->buffers; i++) { |
| 893 | struct pipe_buffer *buf = pipe->bufs + i; | 907 | struct pipe_buffer *buf = pipe->bufs + i; |
| 894 | if (buf->ops) | 908 | if (buf->ops) |
| 895 | buf->ops->release(pipe, buf); | 909 | buf->ops->release(pipe, buf); |
| 896 | } | 910 | } |
| 897 | if (pipe->tmp_page) | 911 | if (pipe->tmp_page) |
| 898 | __free_page(pipe->tmp_page); | 912 | __free_page(pipe->tmp_page); |
| 913 | kfree(pipe->bufs); | ||
| 899 | kfree(pipe); | 914 | kfree(pipe); |
| 900 | } | 915 | } |
| 901 | 916 | ||
| @@ -1094,6 +1109,89 @@ SYSCALL_DEFINE1(pipe, int __user *, fildes) | |||
| 1094 | } | 1109 | } |
| 1095 | 1110 | ||
| 1096 | /* | 1111 | /* |
| 1112 | * Allocate a new array of pipe buffers and copy the info over. Returns the | ||
| 1113 | * pipe size if successful, or return -ERROR on error. | ||
| 1114 | */ | ||
| 1115 | static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) | ||
| 1116 | { | ||
| 1117 | struct pipe_buffer *bufs; | ||
| 1118 | |||
| 1119 | /* | ||
| 1120 | * Must be a power-of-2 currently | ||
| 1121 | */ | ||
| 1122 | if (!is_power_of_2(arg)) | ||
| 1123 | return -EINVAL; | ||
| 1124 | |||
| 1125 | /* | ||
| 1126 | * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't | ||
| 1127 | * expect a lot of shrink+grow operations, just free and allocate | ||
| 1128 | * again like we would do for growing. If the pipe currently | ||
| 1129 | * contains more buffers than arg, then return busy. | ||
| 1130 | */ | ||
| 1131 | if (arg < pipe->nrbufs) | ||
| 1132 | return -EBUSY; | ||
| 1133 | |||
| 1134 | bufs = kcalloc(arg, sizeof(struct pipe_buffer), GFP_KERNEL); | ||
| 1135 | if (unlikely(!bufs)) | ||
| 1136 | return -ENOMEM; | ||
| 1137 | |||
| 1138 | /* | ||
| 1139 | * The pipe array wraps around, so just start the new one at zero | ||
| 1140 | * and adjust the indexes. | ||
| 1141 | */ | ||
| 1142 | if (pipe->nrbufs) { | ||
| 1143 | const unsigned int tail = pipe->nrbufs & (pipe->buffers - 1); | ||
| 1144 | const unsigned int head = pipe->nrbufs - tail; | ||
| 1145 | |||
| 1146 | if (head) | ||
| 1147 | memcpy(bufs, pipe->bufs + pipe->curbuf, head * sizeof(struct pipe_buffer)); | ||
| 1148 | if (tail) | ||
| 1149 | memcpy(bufs + head, pipe->bufs + pipe->curbuf, tail * sizeof(struct pipe_buffer)); | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | pipe->curbuf = 0; | ||
| 1153 | kfree(pipe->bufs); | ||
| 1154 | pipe->bufs = bufs; | ||
| 1155 | pipe->buffers = arg; | ||
| 1156 | return arg; | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) | ||
| 1160 | { | ||
| 1161 | struct pipe_inode_info *pipe; | ||
| 1162 | long ret; | ||
| 1163 | |||
| 1164 | pipe = file->f_path.dentry->d_inode->i_pipe; | ||
| 1165 | if (!pipe) | ||
| 1166 | return -EBADF; | ||
| 1167 | |||
| 1168 | mutex_lock(&pipe->inode->i_mutex); | ||
| 1169 | |||
| 1170 | switch (cmd) { | ||
| 1171 | case F_SETPIPE_SZ: | ||
| 1172 | if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages) | ||
| 1173 | return -EINVAL; | ||
| 1174 | /* | ||
| 1175 | * The pipe needs to be at least 2 pages large to | ||
| 1176 | * guarantee POSIX behaviour. | ||
| 1177 | */ | ||
| 1178 | if (arg < 2) | ||
| 1179 | return -EINVAL; | ||
| 1180 | ret = pipe_set_size(pipe, arg); | ||
| 1181 | break; | ||
| 1182 | case F_GETPIPE_SZ: | ||
| 1183 | ret = pipe->buffers; | ||
| 1184 | break; | ||
| 1185 | default: | ||
| 1186 | ret = -EINVAL; | ||
| 1187 | break; | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | mutex_unlock(&pipe->inode->i_mutex); | ||
| 1191 | return ret; | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | /* | ||
| 1097 | * pipefs should _never_ be mounted by userland - too much of security hassle, | 1195 | * 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 | 1196 | * 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 | 1197 | * any operations on the root directory. However, we need a non-trivial |
