diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2007-11-07 02:30:13 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:53:31 -0500 |
commit | 9c55e01c0cc835818475a6ce8c4d684df9949ac8 (patch) | |
tree | 1115311436677f837a4b477e3fd23c5e0ae184ef | |
parent | bbdfc2f70610bebb841d0874dc901c648308e43a (diff) |
[TCP]: Splice receive support.
Support for network splice receive.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/net.h | 3 | ||||
-rw-r--r-- | include/linux/skbuff.h | 6 | ||||
-rw-r--r-- | include/net/tcp.h | 3 | ||||
-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 |
7 files changed, 401 insertions, 0 deletions
diff --git a/include/linux/net.h b/include/linux/net.h index 596131ea46f4..0235d917d5c3 100644 --- a/include/linux/net.h +++ b/include/linux/net.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <asm/socket.h> | 22 | #include <asm/socket.h> |
23 | 23 | ||
24 | struct poll_table_struct; | 24 | struct poll_table_struct; |
25 | struct pipe_inode_info; | ||
25 | struct inode; | 26 | struct inode; |
26 | struct net; | 27 | struct net; |
27 | 28 | ||
@@ -172,6 +173,8 @@ struct proto_ops { | |||
172 | struct vm_area_struct * vma); | 173 | struct vm_area_struct * vma); |
173 | ssize_t (*sendpage) (struct socket *sock, struct page *page, | 174 | ssize_t (*sendpage) (struct socket *sock, struct page *page, |
174 | int offset, size_t size, int flags); | 175 | int offset, size_t size, int flags); |
176 | ssize_t (*splice_read)(struct socket *sock, loff_t *ppos, | ||
177 | struct pipe_inode_info *pipe, size_t len, unsigned int flags); | ||
175 | }; | 178 | }; |
176 | 179 | ||
177 | struct net_proto_family { | 180 | struct net_proto_family { |
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index bddd50bd6878..d39f53ef66bb 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -95,6 +95,7 @@ | |||
95 | 95 | ||
96 | struct net_device; | 96 | struct net_device; |
97 | struct scatterlist; | 97 | struct scatterlist; |
98 | struct pipe_inode_info; | ||
98 | 99 | ||
99 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 100 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
100 | struct nf_conntrack { | 101 | struct nf_conntrack { |
@@ -1559,6 +1560,11 @@ extern int skb_store_bits(struct sk_buff *skb, int offset, | |||
1559 | extern __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, | 1560 | extern __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, |
1560 | int offset, u8 *to, int len, | 1561 | int offset, u8 *to, int len, |
1561 | __wsum csum); | 1562 | __wsum csum); |
1563 | extern int skb_splice_bits(struct sk_buff *skb, | ||
1564 | unsigned int offset, | ||
1565 | struct pipe_inode_info *pipe, | ||
1566 | unsigned int len, | ||
1567 | unsigned int flags); | ||
1562 | extern void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); | 1568 | extern void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); |
1563 | extern void skb_split(struct sk_buff *skb, | 1569 | extern void skb_split(struct sk_buff *skb, |
1564 | struct sk_buff *skb1, const u32 len); | 1570 | struct sk_buff *skb1, const u32 len); |
diff --git a/include/net/tcp.h b/include/net/tcp.h index cb5b033e0e59..d893b4480769 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -309,6 +309,9 @@ extern int tcp_twsk_unique(struct sock *sk, | |||
309 | 309 | ||
310 | extern void tcp_twsk_destructor(struct sock *sk); | 310 | extern void tcp_twsk_destructor(struct sock *sk); |
311 | 311 | ||
312 | extern ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos, | ||
313 | struct pipe_inode_info *pipe, size_t len, unsigned int flags); | ||
314 | |||
312 | static inline void tcp_dec_quickack_mode(struct sock *sk, | 315 | static inline void tcp_dec_quickack_mode(struct sock *sk, |
313 | const unsigned int pkts) | 316 | const unsigned int pkts) |
314 | { | 317 | { |
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 | { |