[3.11.y.z extended stable] Patch "libceph: fix corruption when using page_count 0 page in rbd" has been added to staging queue

Luis Henriques luis.henriques at canonical.com
Fri May 30 09:29:21 UTC 2014

This is a note to let you know that I have just added a patch titled

    libceph: fix corruption when using page_count 0 page in rbd

to the linux-3.11.y-queue branch of the 3.11.y.z extended stable tree 
which can be found at:


If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.11.y.z tree, see



>From 9ffec3e90e9c42c58e591677499ac0f3190a8c5f Mon Sep 17 00:00:00 2001
From: Chunwei Chen <tuxoko at gmail.com>
Date: Wed, 23 Apr 2014 12:35:09 +0800
Subject: libceph: fix corruption when using page_count 0 page in rbd

commit 178eda29ca721842f2146378e73d43e0044c4166 upstream.

It has been reported that using ZFSonLinux on rbd will result in memory
corruption. The bug report can be found here:


The reason is that ZFS will send pages with page_count 0 into rbd, which in
turns send them to tcp_sendpage. However, tcp_sendpage cannot deal with
page_count 0, as it will do get_page and put_page, and erroneously free the

This type of issue has been noted before, and handled in iscsi, drbd,
etc. So, rbd should also handle this. This fix address this issue by fall back
to slower sendmsg when page_count 0 detected.

Cc: Sage Weil <sage at inktank.com>
Cc: Yehuda Sadeh <yehuda at inktank.com>
Signed-off-by: Chunwei Chen <tuxoko at gmail.com>
Reviewed-by: Ilya Dryomov <ilya.dryomov at inktank.com>
Signed-off-by: Luis Henriques <luis.henriques at canonical.com>
 net/ceph/messenger.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index f8579689d10d..33b4405da8ac 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -556,7 +556,7 @@ static int ceph_tcp_sendmsg(struct socket *sock, struct kvec *iov,
 	return r;

-static int ceph_tcp_sendpage(struct socket *sock, struct page *page,
+static int __ceph_tcp_sendpage(struct socket *sock, struct page *page,
 		     int offset, size_t size, bool more)
 	int flags = MSG_DONTWAIT | MSG_NOSIGNAL | (more ? MSG_MORE : MSG_EOR);
@@ -569,6 +569,24 @@ static int ceph_tcp_sendpage(struct socket *sock, struct page *page,
 	return ret;

+static int ceph_tcp_sendpage(struct socket *sock, struct page *page,
+		     int offset, size_t size, bool more)
+	int ret;
+	struct kvec iov;
+	/* sendpage cannot properly handle pages with page_count == 0,
+	 * we need to fallback to sendmsg if that's the case */
+	if (page_count(page) >= 1)
+		return __ceph_tcp_sendpage(sock, page, offset, size, more);
+	iov.iov_base = kmap(page) + offset;
+	iov.iov_len = size;
+	ret = ceph_tcp_sendmsg(sock, &iov, 1, size, more);
+	kunmap(page);
+	return ret;

  * Shutdown/close the socket for the given connection.

More information about the kernel-team mailing list