diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/core/skbuff.c | 246 | ||||
| -rw-r--r-- | net/ipv4/af_inet.c | 1 | ||||
| -rw-r--r-- | net/ipv4/tcp.c | 129 | ||||
| -rw-r--r-- | net/socket.c | 13 |
4 files changed, 389 insertions, 0 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index b6283779e93d..98420f9c4b6d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
| @@ -52,6 +52,7 @@ | |||
| 52 | #endif | 52 | #endif |
| 53 | #include <linux/string.h> | 53 | #include <linux/string.h> |
| 54 | #include <linux/skbuff.h> | 54 | #include <linux/skbuff.h> |
| 55 | #include <linux/splice.h> | ||
| 55 | #include <linux/cache.h> | 56 | #include <linux/cache.h> |
| 56 | #include <linux/rtnetlink.h> | 57 | #include <linux/rtnetlink.h> |
| 57 | #include <linux/init.h> | 58 | #include <linux/init.h> |
| @@ -71,6 +72,40 @@ | |||
| 71 | static struct kmem_cache *skbuff_head_cache __read_mostly; | 72 | static struct kmem_cache *skbuff_head_cache __read_mostly; |
| 72 | static struct kmem_cache *skbuff_fclone_cache __read_mostly; | 73 | static struct kmem_cache *skbuff_fclone_cache __read_mostly; |
| 73 | 74 | ||
| 75 | static void sock_pipe_buf_release(struct pipe_inode_info *pipe, | ||
| 76 | struct pipe_buffer *buf) | ||
| 77 | { | ||
| 78 | struct sk_buff *skb = (struct sk_buff *) buf->private; | ||
| 79 | |||
| 80 | kfree_skb(skb); | ||
| 81 | } | ||
| 82 | |||
| 83 | static void sock_pipe_buf_get(struct pipe_inode_info *pipe, | ||
| 84 | struct pipe_buffer *buf) | ||
| 85 | { | ||
| 86 | struct sk_buff *skb = (struct sk_buff *) buf->private; | ||
| 87 | |||
| 88 | skb_get(skb); | ||
| 89 | } | ||
| 90 | |||
| 91 | static int sock_pipe_buf_steal(struct pipe_inode_info *pipe, | ||
| 92 | struct pipe_buffer *buf) | ||
| 93 | { | ||
| 94 | return 1; | ||
| 95 | } | ||
| 96 | |||
| 97 | |||
| 98 | /* Pipe buffer operations for a socket. */ | ||
| 99 | static struct pipe_buf_operations sock_pipe_buf_ops = { | ||
| 100 | .can_merge = 0, | ||
| 101 | .map = generic_pipe_buf_map, | ||
| 102 | .unmap = generic_pipe_buf_unmap, | ||
| 103 | .confirm = generic_pipe_buf_confirm, | ||
| 104 | .release = sock_pipe_buf_release, | ||
| 105 | .steal = sock_pipe_buf_steal, | ||
| 106 | .get = sock_pipe_buf_get, | ||
| 107 | }; | ||
| 108 | |||
| 74 | /* | 109 | /* |
| 75 | * Keep out-of-line to prevent kernel bloat. | 110 | * Keep out-of-line to prevent kernel bloat. |
| 76 | * __builtin_return_address is not used because it is not always | 111 | * __builtin_return_address is not used because it is not always |
| @@ -1122,6 +1157,217 @@ fault: | |||
| 1122 | return -EFAULT; | 1157 | return -EFAULT; |
| 1123 | } | 1158 | } |
| 1124 | 1159 | ||
| 1160 | /* | ||
| 1161 | * Callback from splice_to_pipe(), if we need to release some pages | ||
| 1162 | * at the end of the spd in case we error'ed out in filling the pipe. | ||
| 1163 | */ | ||
| 1164 | static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i) | ||
| 1165 | { | ||
| 1166 | struct sk_buff *skb = (struct sk_buff *) spd->partial[i].private; | ||
| 1167 | |||
| 1168 | kfree_skb(skb); | ||
| 1169 | } | ||
| 1170 | |||
| 1171 | /* | ||
| 1172 | * Fill page/offset/length into spd, if it can hold more pages. | ||
| 1173 | */ | ||
| 1174 | static inline int spd_fill_page(struct splice_pipe_desc *spd, struct page *page, | ||
| 1175 | unsigned int len, unsigned int offset, | ||
| 1176 | struct sk_buff *skb) | ||
| 1177 | { | ||
| 1178 | if (unlikely(spd->nr_pages == PIPE_BUFFERS)) | ||
| 1179 | return 1; | ||
| 1180 | |||
| 1181 | spd->pages[spd->nr_pages] = page; | ||
| 1182 | spd->partial[spd->nr_pages].len = len; | ||
| 1183 | spd->partial[spd->nr_pages].offset = offset; | ||
| 1184 | spd->partial[spd->nr_pages].private = (unsigned long) skb_get(skb); | ||
| 1185 | spd->nr_pages++; | ||
| 1186 | return 0; | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | /* | ||
| 1190 | * Map linear and fragment data from the skb to spd. Returns number of | ||
| 1191 | * pages mapped. | ||
| 1192 | */ | ||
| 1193 | static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset, | ||
| 1194 | unsigned int *total_len, | ||
| 1195 | struct splice_pipe_desc *spd) | ||
| 1196 | { | ||
| 1197 | unsigned int nr_pages = spd->nr_pages; | ||
| 1198 | unsigned int poff, plen, len, toff, tlen; | ||
| 1199 | int headlen, seg; | ||
| 1200 | |||
| 1201 | toff = *offset; | ||
| 1202 | tlen = *total_len; | ||
| 1203 | if (!tlen) | ||
| 1204 | goto err; | ||
| 1205 | |||
| 1206 | /* | ||
| 1207 | * if the offset is greater than the linear part, go directly to | ||
| 1208 | * the fragments. | ||
| 1209 | */ | ||
| 1210 | headlen = skb_headlen(skb); | ||
| 1211 | if (toff >= headlen) { | ||
| 1212 | toff -= headlen; | ||
| 1213 | goto map_frag; | ||
| 1214 | } | ||
| 1215 | |||
| 1216 | /* | ||
| 1217 | * first map the linear region into the pages/partial map, skipping | ||
| 1218 | * any potential initial offset. | ||
| 1219 | */ | ||
| 1220 | len = 0; | ||
| 1221 | while (len < headlen) { | ||
| 1222 | void *p = skb->data + len; | ||
| 1223 | |||
| 1224 | poff = (unsigned long) p & (PAGE_SIZE - 1); | ||
| 1225 | plen = min_t(unsigned int, headlen - len, PAGE_SIZE - poff); | ||
| 1226 | len += plen; | ||
| 1227 | |||
| 1228 | if (toff) { | ||
| 1229 | if (plen <= toff) { | ||
| 1230 | toff -= plen; | ||
| 1231 | continue; | ||
| 1232 | } | ||
| 1233 | plen -= toff; | ||
| 1234 | poff += toff; | ||
| 1235 | toff = 0; | ||
| 1236 | } | ||
| 1237 | |||
| 1238 | plen = min(plen, tlen); | ||
| 1239 | if (!plen) | ||
| 1240 | break; | ||
| 1241 | |||
| 1242 | /* | ||
| 1243 | * just jump directly to update and return, no point | ||
| 1244 | * in going over fragments when the output is full. | ||
| 1245 | */ | ||
| 1246 | if (spd_fill_page(spd, virt_to_page(p), plen, poff, skb)) | ||
| 1247 | goto done; | ||
| 1248 | |||
| 1249 | tlen -= plen; | ||
| 1250 | } | ||
| 1251 | |||
| 1252 | /* | ||
| 1253 | * then map the fragments | ||
| 1254 | */ | ||
| 1255 | map_frag: | ||
| 1256 | for (seg = 0; seg < skb_shinfo(skb)->nr_frags; seg++) { | ||
| 1257 | const skb_frag_t *f = &skb_shinfo(skb)->frags[seg]; | ||
| 1258 | |||
| 1259 | plen = f->size; | ||
| 1260 | poff = f->page_offset; | ||
| 1261 | |||
| 1262 | if (toff) { | ||
| 1263 | if (plen <= toff) { | ||
| 1264 | toff -= plen; | ||
| 1265 | continue; | ||
| 1266 | } | ||
| 1267 | plen -= toff; | ||
| 1268 | poff += toff; | ||
| 1269 | toff = 0; | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | plen = min(plen, tlen); | ||
| 1273 | if (!plen) | ||
| 1274 | break; | ||
| 1275 | |||
| 1276 | if (spd_fill_page(spd, f->page, plen, poff, skb)) | ||
| 1277 | break; | ||
| 1278 | |||
| 1279 | tlen -= plen; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | done: | ||
| 1283 | if (spd->nr_pages - nr_pages) { | ||
| 1284 | *offset = 0; | ||
| 1285 | *total_len = tlen; | ||
| 1286 | return 0; | ||
| 1287 | } | ||
| 1288 | err: | ||
| 1289 | return 1; | ||
| 1290 | } | ||
| 1291 | |||
| 1292 | /* | ||
| 1293 | * Map data from the skb to a pipe. Should handle both the linear part, | ||
| 1294 | * the fragments, and the frag list. It does NOT handle frag lists within | ||
| 1295 | * the frag list, if such a thing exists. We'd probably need to recurse to | ||
| 1296 | * handle that cleanly. | ||
| 1297 | */ | ||
| 1298 | int skb_splice_bits(struct sk_buff *__skb, unsigned int offset, | ||
| 1299 | struct pipe_inode_info *pipe, unsigned int tlen, | ||
| 1300 | unsigned int flags) | ||
| 1301 | { | ||
| 1302 | struct partial_page partial[PIPE_BUFFERS]; | ||
| 1303 | struct page *pages[PIPE_BUFFERS]; | ||
| 1304 | struct splice_pipe_desc spd = { | ||
| 1305 | .pages = pages, | ||
| 1306 | .partial = partial, | ||
| 1307 | .flags = flags, | ||
| 1308 | .ops = &sock_pipe_buf_ops, | ||
| 1309 | .spd_release = sock_spd_release, | ||
| 1310 | }; | ||
| 1311 | struct sk_buff *skb; | ||
| 1312 | |||
| 1313 | /* | ||
| 1314 | * I'd love to avoid the clone here, but tcp_read_sock() | ||
| 1315 | * ignores reference counts and unconditonally kills the sk_buff | ||
| 1316 | * on return from the actor. | ||
| 1317 | */ | ||
| 1318 | skb = skb_clone(__skb, GFP_KERNEL); | ||
| 1319 | if (unlikely(!skb)) | ||
| 1320 | return -ENOMEM; | ||
| 1321 | |||
| 1322 | /* | ||
| 1323 | * __skb_splice_bits() only fails if the output has no room left, | ||
| 1324 | * so no point in going over the frag_list for the error case. | ||
| 1325 | */ | ||
| 1326 | if (__skb_splice_bits(skb, &offset, &tlen, &spd)) | ||
| 1327 | goto done; | ||
| 1328 | else if (!tlen) | ||
| 1329 | goto done; | ||
| 1330 | |||
| 1331 | /* | ||
| 1332 | * now see if we have a frag_list to map | ||
| 1333 | */ | ||
| 1334 | if (skb_shinfo(skb)->frag_list) { | ||
| 1335 | struct sk_buff *list = skb_shinfo(skb)->frag_list; | ||
| 1336 | |||
| 1337 | for (; list && tlen; list = list->next) { | ||
| 1338 | if (__skb_splice_bits(list, &offset, &tlen, &spd)) | ||
| 1339 | break; | ||
| 1340 | } | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | done: | ||
| 1344 | /* | ||
| 1345 | * drop our reference to the clone, the pipe consumption will | ||
| 1346 | * drop the rest. | ||
| 1347 | */ | ||
| 1348 | kfree_skb(skb); | ||
| 1349 | |||
| 1350 | if (spd.nr_pages) { | ||
| 1351 | int ret; | ||
| 1352 | |||
| 1353 | /* | ||
| 1354 | * Drop the socket lock, otherwise we have reverse | ||
| 1355 | * locking dependencies between sk_lock and i_mutex | ||
| 1356 | * here as compared to sendfile(). We enter here | ||
| 1357 | * with the socket lock held, and splice_to_pipe() will | ||
| 1358 | * grab the pipe inode lock. For sendfile() emulation, | ||
| 1359 | * we call into ->sendpage() with the i_mutex lock held | ||
| 1360 | * and networking will grab the socket lock. | ||
| 1361 | */ | ||
| 1362 | release_sock(__skb->sk); | ||
| 1363 | ret = splice_to_pipe(pipe, &spd); | ||
| 1364 | lock_sock(__skb->sk); | ||
| 1365 | return ret; | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | return 0; | ||
| 1369 | } | ||
| 1370 | |||
| 1125 | /** | 1371 | /** |
| 1126 | * skb_store_bits - store bits from kernel buffer to skb | 1372 | * skb_store_bits - store bits from kernel buffer to skb |
| 1127 | * @skb: destination buffer | 1373 | * @skb: destination buffer |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index d2f22e74b267..c75f20b49935 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
| @@ -838,6 +838,7 @@ const struct proto_ops inet_stream_ops = { | |||
| 838 | .recvmsg = sock_common_recvmsg, | 838 | .recvmsg = sock_common_recvmsg, |
| 839 | .mmap = sock_no_mmap, | 839 | .mmap = sock_no_mmap, |
| 840 | .sendpage = tcp_sendpage, | 840 | .sendpage = tcp_sendpage, |
| 841 | .splice_read = tcp_splice_read, | ||
| 841 | #ifdef CONFIG_COMPAT | 842 | #ifdef CONFIG_COMPAT |
| 842 | .compat_setsockopt = compat_sock_common_setsockopt, | 843 | .compat_setsockopt = compat_sock_common_setsockopt, |
| 843 | .compat_getsockopt = compat_sock_common_getsockopt, | 844 | .compat_getsockopt = compat_sock_common_getsockopt, |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 8e65182f7af1..56ed40703f98 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
| @@ -254,6 +254,10 @@ | |||
| 254 | #include <linux/poll.h> | 254 | #include <linux/poll.h> |
| 255 | #include <linux/init.h> | 255 | #include <linux/init.h> |
| 256 | #include <linux/fs.h> | 256 | #include <linux/fs.h> |
| 257 | #include <linux/skbuff.h> | ||
| 258 | #include <linux/splice.h> | ||
| 259 | #include <linux/net.h> | ||
| 260 | #include <linux/socket.h> | ||
| 257 | #include <linux/random.h> | 261 | #include <linux/random.h> |
| 258 | #include <linux/bootmem.h> | 262 | #include <linux/bootmem.h> |
| 259 | #include <linux/cache.h> | 263 | #include <linux/cache.h> |
| @@ -265,6 +269,7 @@ | |||
| 265 | #include <net/xfrm.h> | 269 | #include <net/xfrm.h> |
| 266 | #include <net/ip.h> | 270 | #include <net/ip.h> |
| 267 | #include <net/netdma.h> | 271 | #include <net/netdma.h> |
| 272 | #include <net/sock.h> | ||
| 268 | 273 | ||
| 269 | #include <asm/uaccess.h> | 274 | #include <asm/uaccess.h> |
| 270 | #include <asm/ioctls.h> | 275 | #include <asm/ioctls.h> |
| @@ -292,6 +297,15 @@ EXPORT_SYMBOL(tcp_memory_allocated); | |||
| 292 | EXPORT_SYMBOL(tcp_sockets_allocated); | 297 | EXPORT_SYMBOL(tcp_sockets_allocated); |
| 293 | 298 | ||
| 294 | /* | 299 | /* |
| 300 | * TCP splice context | ||
| 301 | */ | ||
| 302 | struct tcp_splice_state { | ||
| 303 | struct pipe_inode_info *pipe; | ||
| 304 | size_t len; | ||
| 305 | unsigned int flags; | ||
| 306 | }; | ||
| 307 | |||
| 308 | /* | ||
| 295 | * Pressure flag: try to collapse. | 309 | * Pressure flag: try to collapse. |
| 296 | * Technical note: it is used by multiple contexts non atomically. | 310 | * Technical note: it is used by multiple contexts non atomically. |
| 297 | * All the sk_stream_mem_schedule() is of this nature: accounting | 311 | * All the sk_stream_mem_schedule() is of this nature: accounting |
| @@ -501,6 +515,120 @@ static inline void tcp_push(struct sock *sk, int flags, int mss_now, | |||
| 501 | } | 515 | } |
| 502 | } | 516 | } |
| 503 | 517 | ||
| 518 | int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, | ||
| 519 | unsigned int offset, size_t len) | ||
| 520 | { | ||
| 521 | struct tcp_splice_state *tss = rd_desc->arg.data; | ||
| 522 | |||
| 523 | return skb_splice_bits(skb, offset, tss->pipe, tss->len, tss->flags); | ||
| 524 | } | ||
| 525 | |||
| 526 | static int __tcp_splice_read(struct sock *sk, struct tcp_splice_state *tss) | ||
| 527 | { | ||
| 528 | /* Store TCP splice context information in read_descriptor_t. */ | ||
| 529 | read_descriptor_t rd_desc = { | ||
| 530 | .arg.data = tss, | ||
| 531 | }; | ||
| 532 | |||
| 533 | return tcp_read_sock(sk, &rd_desc, tcp_splice_data_recv); | ||
| 534 | } | ||
| 535 | |||
| 536 | /** | ||
| 537 | * tcp_splice_read - splice data from TCP socket to a pipe | ||
| 538 | * @sock: socket to splice from | ||
| 539 | * @ppos: position (not valid) | ||
| 540 | * @pipe: pipe to splice to | ||
| 541 | * @len: number of bytes to splice | ||
| 542 | * @flags: splice modifier flags | ||
| 543 | * | ||
| 544 | * Description: | ||
| 545 | * Will read pages from given socket and fill them into a pipe. | ||
| 546 | * | ||
| 547 | **/ | ||
| 548 | ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, | ||
| 549 | struct pipe_inode_info *pipe, size_t len, | ||
| 550 | unsigned int flags) | ||
| 551 | { | ||
| 552 | struct sock *sk = sock->sk; | ||
| 553 | struct tcp_splice_state tss = { | ||
| 554 | .pipe = pipe, | ||
| 555 | .len = len, | ||
| 556 | .flags = flags, | ||
| 557 | }; | ||
| 558 | long timeo; | ||
| 559 | ssize_t spliced; | ||
| 560 | int ret; | ||
| 561 | |||
| 562 | /* | ||
| 563 | * We can't seek on a socket input | ||
| 564 | */ | ||
| 565 | if (unlikely(*ppos)) | ||
| 566 | return -ESPIPE; | ||
| 567 | |||
| 568 | ret = spliced = 0; | ||
| 569 | |||
| 570 | lock_sock(sk); | ||
| 571 | |||
| 572 | timeo = sock_rcvtimeo(sk, flags & SPLICE_F_NONBLOCK); | ||
| 573 | while (tss.len) { | ||
| 574 | ret = __tcp_splice_read(sk, &tss); | ||
| 575 | if (ret < 0) | ||
| 576 | break; | ||
| 577 | else if (!ret) { | ||
| 578 | if (spliced) | ||
| 579 | break; | ||
| 580 | if (flags & SPLICE_F_NONBLOCK) { | ||
| 581 | ret = -EAGAIN; | ||
| 582 | break; | ||
| 583 | } | ||
| 584 | if (sock_flag(sk, SOCK_DONE)) | ||
| 585 | break; | ||
| 586 | if (sk->sk_err) { | ||
| 587 | ret = sock_error(sk); | ||
| 588 | break; | ||
| 589 | } | ||
| 590 | if (sk->sk_shutdown & RCV_SHUTDOWN) | ||
| 591 | break; | ||
| 592 | if (sk->sk_state == TCP_CLOSE) { | ||
| 593 | /* | ||
| 594 | * This occurs when user tries to read | ||
| 595 | * from never connected socket. | ||
| 596 | */ | ||
| 597 | if (!sock_flag(sk, SOCK_DONE)) | ||
| 598 | ret = -ENOTCONN; | ||
| 599 | break; | ||
| 600 | } | ||
| 601 | if (!timeo) { | ||
| 602 | ret = -EAGAIN; | ||
| 603 | break; | ||
| 604 | } | ||
| 605 | sk_wait_data(sk, &timeo); | ||
| 606 | if (signal_pending(current)) { | ||
| 607 | ret = sock_intr_errno(timeo); | ||
| 608 | break; | ||
| 609 | } | ||
| 610 | continue; | ||
| 611 | } | ||
| 612 | tss.len -= ret; | ||
| 613 | spliced += ret; | ||
| 614 | |||
| 615 | release_sock(sk); | ||
| 616 | lock_sock(sk); | ||
| 617 | |||
| 618 | if (sk->sk_err || sk->sk_state == TCP_CLOSE || | ||
| 619 | (sk->sk_shutdown & RCV_SHUTDOWN) || !timeo || | ||
| 620 | signal_pending(current)) | ||
| 621 | break; | ||
| 622 | } | ||
| 623 | |||
| 624 | release_sock(sk); | ||
| 625 | |||
| 626 | if (spliced) | ||
| 627 | return spliced; | ||
| 628 | |||
| 629 | return ret; | ||
| 630 | } | ||
| 631 | |||
| 504 | static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, | 632 | static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, |
| 505 | size_t psize, int flags) | 633 | size_t psize, int flags) |
| 506 | { | 634 | { |
| @@ -2532,6 +2660,7 @@ EXPORT_SYMBOL(tcp_poll); | |||
| 2532 | EXPORT_SYMBOL(tcp_read_sock); | 2660 | EXPORT_SYMBOL(tcp_read_sock); |
| 2533 | EXPORT_SYMBOL(tcp_recvmsg); | 2661 | EXPORT_SYMBOL(tcp_recvmsg); |
| 2534 | EXPORT_SYMBOL(tcp_sendmsg); | 2662 | EXPORT_SYMBOL(tcp_sendmsg); |
| 2663 | EXPORT_SYMBOL(tcp_splice_read); | ||
| 2535 | EXPORT_SYMBOL(tcp_sendpage); | 2664 | EXPORT_SYMBOL(tcp_sendpage); |
| 2536 | EXPORT_SYMBOL(tcp_setsockopt); | 2665 | EXPORT_SYMBOL(tcp_setsockopt); |
| 2537 | EXPORT_SYMBOL(tcp_shutdown); | 2666 | EXPORT_SYMBOL(tcp_shutdown); |
diff --git a/net/socket.c b/net/socket.c index 74784dfe8e5b..92fab9e1c602 100644 --- a/net/socket.c +++ b/net/socket.c | |||
| @@ -112,6 +112,9 @@ static long compat_sock_ioctl(struct file *file, | |||
| 112 | static int sock_fasync(int fd, struct file *filp, int on); | 112 | static int sock_fasync(int fd, struct file *filp, int on); |
| 113 | static ssize_t sock_sendpage(struct file *file, struct page *page, | 113 | static ssize_t sock_sendpage(struct file *file, struct page *page, |
| 114 | int offset, size_t size, loff_t *ppos, int more); | 114 | int offset, size_t size, loff_t *ppos, int more); |
| 115 | static ssize_t sock_splice_read(struct file *file, loff_t *ppos, | ||
| 116 | struct pipe_inode_info *pipe, size_t len, | ||
| 117 | unsigned int flags); | ||
| 115 | 118 | ||
| 116 | /* | 119 | /* |
| 117 | * Socket files have a set of 'special' operations as well as the generic file ones. These don't appear | 120 | * Socket files have a set of 'special' operations as well as the generic file ones. These don't appear |
| @@ -134,6 +137,7 @@ static const struct file_operations socket_file_ops = { | |||
| 134 | .fasync = sock_fasync, | 137 | .fasync = sock_fasync, |
| 135 | .sendpage = sock_sendpage, | 138 | .sendpage = sock_sendpage, |
| 136 | .splice_write = generic_splice_sendpage, | 139 | .splice_write = generic_splice_sendpage, |
| 140 | .splice_read = sock_splice_read, | ||
| 137 | }; | 141 | }; |
| 138 | 142 | ||
| 139 | /* | 143 | /* |
| @@ -691,6 +695,15 @@ static ssize_t sock_sendpage(struct file *file, struct page *page, | |||
| 691 | return sock->ops->sendpage(sock, page, offset, size, flags); | 695 | return sock->ops->sendpage(sock, page, offset, size, flags); |
| 692 | } | 696 | } |
| 693 | 697 | ||
| 698 | static ssize_t sock_splice_read(struct file *file, loff_t *ppos, | ||
| 699 | struct pipe_inode_info *pipe, size_t len, | ||
| 700 | unsigned int flags) | ||
| 701 | { | ||
| 702 | struct socket *sock = file->private_data; | ||
| 703 | |||
| 704 | return sock->ops->splice_read(sock, ppos, pipe, len, flags); | ||
| 705 | } | ||
| 706 | |||
| 694 | static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, | 707 | static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, |
| 695 | struct sock_iocb *siocb) | 708 | struct sock_iocb *siocb) |
| 696 | { | 709 | { |
