diff mbox series

[05/10] libceph: enable fallback to ceph_msg_new() in ceph_msgpool_get()

Message ID 20181017192029.23294-6-idryomov@gmail.com (mailing list archive)
State New, archived
Headers show
Series libceph: preallocate message data items | expand

Commit Message

Ilya Dryomov Oct. 17, 2018, 7:20 p.m. UTC
ceph_msgpool_get() can fall back to ceph_msg_new() when it is asked for
a message whose front portion is larger than pool->front_len.  However
the caller always passes 0, effectively disabling that code path.  The
allocation goes to the message pool and returns a message with a front
that is smaller than requested, setting us up for a crash.

One example of this is a directory with a large number of snapshots.
If its snap context doesn't fit, we oops in encode_request_partial().

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
---
 net/ceph/msgpool.c    | 2 +-
 net/ceph/osd_client.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/net/ceph/msgpool.c b/net/ceph/msgpool.c
index 72571535883f..3dddc074f0d7 100644
--- a/net/ceph/msgpool.c
+++ b/net/ceph/msgpool.c
@@ -61,7 +61,7 @@  struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *pool,
 	if (front_len > pool->front_len) {
 		dout("msgpool_get %s need front %d, pool size is %d\n",
 		       pool->name, front_len, pool->front_len);
-		WARN_ON(1);
+		WARN_ON_ONCE(1);
 
 		/* try to alloc a fresh message */
 		return ceph_msg_new(pool->type, front_len, GFP_NOFS, false);
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index f403a483d51d..35bc77c8c230 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -641,7 +641,7 @@  int ceph_osdc_alloc_messages(struct ceph_osd_request *req, gfp_t gfp)
 	msg_size += 4 + 8; /* retry_attempt, features */
 
 	if (req->r_mempool)
-		msg = ceph_msgpool_get(&osdc->msgpool_op, 0);
+		msg = ceph_msgpool_get(&osdc->msgpool_op, msg_size);
 	else
 		msg = ceph_msg_new(CEPH_MSG_OSD_OP, msg_size, gfp, true);
 	if (!msg)
@@ -656,7 +656,7 @@  int ceph_osdc_alloc_messages(struct ceph_osd_request *req, gfp_t gfp)
 	msg_size += req->r_num_ops * sizeof(struct ceph_osd_op);
 
 	if (req->r_mempool)
-		msg = ceph_msgpool_get(&osdc->msgpool_op_reply, 0);
+		msg = ceph_msgpool_get(&osdc->msgpool_op_reply, msg_size);
 	else
 		msg = ceph_msg_new(CEPH_MSG_OSD_OPREPLY, msg_size, gfp, true);
 	if (!msg)