Skip to content

Commit e7d4005

Browse files
committed
Merge branch 'Introduce-sendpage_ok-to-detect-misused-sendpage-in-network-related-drivers'
Coly Li says: ==================== Introduce sendpage_ok() to detect misused sendpage in network related drivers As Sagi Grimberg suggested, the original fix is refind to a more common inline routine: static inline bool sendpage_ok(struct page *page) { return (!PageSlab(page) && page_count(page) >= 1); } If sendpage_ok() returns true, the checking page can be handled by the concrete zero-copy sendpage method in network layer. The v10 series has 7 patches, fixes a WARN_ONCE() usage from v9 series, - The 1st patch in this series introduces sendpage_ok() in header file include/linux/net.h. - The 2nd patch adds WARN_ONCE() for improper zero-copy send in kernel_sendpage(). - The 3rd patch fixes the page checking issue in nvme-over-tcp driver. - The 4th patch adds page_count check by using sendpage_ok() in do_tcp_sendpages() as Eric Dumazet suggested. - The 5th and 6th patches just replace existing open coded checks with the inline sendpage_ok() routine. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents f30e25a + 40efc4d commit e7d4005

File tree

7 files changed

+28
-10
lines changed

7 files changed

+28
-10
lines changed

drivers/block/drbd/drbd_main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1553,7 +1553,7 @@ static int _drbd_send_page(struct drbd_peer_device *peer_device, struct page *pa
15531553
* put_page(); and would cause either a VM_BUG directly, or
15541554
* __page_cache_release a page that would actually still be referenced
15551555
* by someone, leading to some obscure delayed Oops somewhere else. */
1556-
if (drbd_disable_sendpage || (page_count(page) < 1) || PageSlab(page))
1556+
if (drbd_disable_sendpage || !sendpage_ok(page))
15571557
return _drbd_no_send_page(peer_device, page, offset, size, msg_flags);
15581558

15591559
msg_flags |= MSG_NOSIGNAL;

drivers/nvme/host/tcp.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -913,12 +913,11 @@ static int nvme_tcp_try_send_data(struct nvme_tcp_request *req)
913913
else
914914
flags |= MSG_MORE | MSG_SENDPAGE_NOTLAST;
915915

916-
/* can't zcopy slab pages */
917-
if (unlikely(PageSlab(page))) {
918-
ret = sock_no_sendpage(queue->sock, page, offset, len,
916+
if (sendpage_ok(page)) {
917+
ret = kernel_sendpage(queue->sock, page, offset, len,
919918
flags);
920919
} else {
921-
ret = kernel_sendpage(queue->sock, page, offset, len,
920+
ret = sock_no_sendpage(queue->sock, page, offset, len,
922921
flags);
923922
}
924923
if (ret <= 0)

drivers/scsi/libiscsi_tcp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ static void iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv)
128128
* coalescing neighboring slab objects into a single frag which
129129
* triggers one of hardened usercopy checks.
130130
*/
131-
if (!recv && page_count(sg_page(sg)) >= 1 && !PageSlab(sg_page(sg)))
131+
if (!recv && sendpage_ok(sg_page(sg)))
132132
return;
133133

134134
if (recv) {

include/linux/net.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/rcupdate.h>
2222
#include <linux/once.h>
2323
#include <linux/fs.h>
24+
#include <linux/mm.h>
2425
#include <linux/sockptr.h>
2526

2627
#include <uapi/linux/net.h>
@@ -286,6 +287,21 @@ do { \
286287
#define net_get_random_once_wait(buf, nbytes) \
287288
get_random_once_wait((buf), (nbytes))
288289

290+
/*
291+
* E.g. XFS meta- & log-data is in slab pages, or bcache meta
292+
* data pages, or other high order pages allocated by
293+
* __get_free_pages() without __GFP_COMP, which have a page_count
294+
* of 0 and/or have PageSlab() set. We cannot use send_page for
295+
* those, as that does get_page(); put_page(); and would cause
296+
* either a VM_BUG directly, or __page_cache_release a page that
297+
* would actually still be referenced by someone, leading to some
298+
* obscure delayed Oops somewhere else.
299+
*/
300+
static inline bool sendpage_ok(struct page *page)
301+
{
302+
return !PageSlab(page) && page_count(page) >= 1;
303+
}
304+
289305
int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
290306
size_t num, size_t len);
291307
int kernel_sendmsg_locked(struct sock *sk, struct msghdr *msg,

net/ceph/messenger.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ static int ceph_tcp_sendpage(struct socket *sock, struct page *page,
575575
* coalescing neighboring slab objects into a single frag which
576576
* triggers one of hardened usercopy checks.
577577
*/
578-
if (page_count(page) >= 1 && !PageSlab(page))
578+
if (sendpage_ok(page))
579579
sendpage = sock->ops->sendpage;
580580
else
581581
sendpage = sock_no_sendpage;

net/ipv4/tcp.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -970,7 +970,8 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
970970
long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
971971

972972
if (IS_ENABLED(CONFIG_DEBUG_VM) &&
973-
WARN_ONCE(PageSlab(page), "page must not be a Slab one"))
973+
WARN_ONCE(!sendpage_ok(page),
974+
"page must not be a Slab one and have page_count > 0"))
974975
return -EINVAL;
975976

976977
/* Wait for a connection to finish. One exception is TCP Fast Open

net/socket.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3638,9 +3638,11 @@ EXPORT_SYMBOL(kernel_getpeername);
36383638
int kernel_sendpage(struct socket *sock, struct page *page, int offset,
36393639
size_t size, int flags)
36403640
{
3641-
if (sock->ops->sendpage)
3641+
if (sock->ops->sendpage) {
3642+
/* Warn in case the improper page to zero-copy send */
3643+
WARN_ONCE(!sendpage_ok(page), "improper page for zero-copy send");
36423644
return sock->ops->sendpage(sock, page, offset, size, flags);
3643-
3645+
}
36443646
return sock_no_sendpage(sock, page, offset, size, flags);
36453647
}
36463648
EXPORT_SYMBOL(kernel_sendpage);

0 commit comments

Comments
 (0)