From: Luis Henriques <lhenriques@suse.com>
Date: Tue, 30 May 2017 19:20:22 +0100
Subject: ceph: memory leak in ceph_direct_read_write callback
Patch-mainline: Never, it fixes SUSE-specific code that has never been
merged upstream
References: bsc#1041810
Running xfstest generic/036 with kmemleak enabled shows several suspected
leaks:
unreferenced object 0xffff880077b86168 (size 8):
comm "a.out", pid 231, jiffies 4294898530 (age 43.656s)
hex dump (first 8 bytes):
00 3b 06 00 00 ea ff ff .;......
backtrace:
[<ffffffff81589f3e>] kmemleak_alloc+0x4e/0xb0
[<ffffffff8111cb24>] __kmalloc+0x134/0x1b0
[<ffffffff812d7045>] ceph_direct_read_write+0x3b5/0xd70
[<ffffffff812d86db>] ceph_write_iter+0x3eb/0xd80
[<ffffffff81168c70>] aio_run_iocb+0x220/0x2a0
[<ffffffff8116a346>] do_io_submit+0x296/0x4b0
[<ffffffff8116a570>] SyS_io_submit+0x10/0x20
[<ffffffff8158e517>] entry_SYSCALL_64_fastpath+0x12/0x66
[<ffffffffffffffff>] 0xffffffffffffffff
ceph_direct_read_write() allocates an array of struct pages using
dio_get_pages_alloc() and never frees it -- the ceph_aio_complete_req
callback is supposed to do that. However, this function is retrieving the
ceph_osd_data struct with osd_req_op_extent_osd_response_data() only, and
ignoring the fact that the operation could have been a CEPH_OSD_OP_WRITE*.
This patch verifies uses the correct function to initialize this struct
after checking aio_req->write.
Reviewed-by: David Disseldorp <ddiss@suse.de>
Signed-off-by: Luis Henriques <lhenriques@suse.com>
---
fs/ceph/file.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index b51d0548bd9e..e4327fc778b2 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -695,10 +695,15 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req)
int rc = req->r_result;
struct inode *inode = req->r_inode;
struct ceph_aio_request *aio_req = req->r_priv;
- struct ceph_osd_data *osd_data = osd_req_op_extent_osd_response_data(req, 0);
- int num_pages = calc_pages_for((u64)osd_data->alignment,
- osd_data->length);
+ struct ceph_osd_data *osd_data;
+ int num_pages;
+ if (aio_req->write)
+ osd_data = osd_req_op_extent_osd_request_data(req, 0);
+ else
+ osd_data = osd_req_op_extent_osd_response_data(req, 0);
+ num_pages = calc_pages_for((u64)osd_data->alignment,
+ osd_data->length);
dout("ceph_aio_complete_req %p rc %d bytes %llu\n",
inode, rc, osd_data->length);