Commit 95621e78 authored by Zizhi Wo's avatar Zizhi Wo
Browse files

cifs: Fix pages leak when cifs_writedata allocate fails in cifs_writedata_direct_alloc()

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IAOH1I



--------------------------------

The function cifs_writedata_alloc() first allocates pages and then executes
cifs_writedata_direct_alloc(). If the subsequent allocation of wdata fails,
the previously allocated pages are not released, leading to a memory leak:

[root@fedora debug]# cat kmemleak
unreferenced object 0xff110001287aa000 (size 8192):
  comm "kworker/u220:9", pid 1604, jiffies 4294753971 (age 19.114s)
  hex dump (first 32 bytes):
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  backtrace:
    [<00000000c80fa56d>] kmemleak_alloc+0x65/0xd0
    [<0000000032ff36c6>] __kmalloc+0x641/0xa50
    [<00000000da9a4c31>] cifs_writedata_alloc+0x1d/0x30
    [<00000000337073aa>] cifs_writepages+0x3e0/0x1990
    [<0000000095bfb1fd>] do_writepages+0x31/0xb0
    [<00000000321368a2>] __writeback_single_inode+0x4f/0x550
    [<00000000f200b315>] writeback_sb_inodes+0x24a/0x7a0
    [<00000000badd6d82>] __writeback_inodes_wb+0x88/0x120
    [<000000000632fc4a>] wb_writeback+0x3aa/0x4c0
    [<00000000c184a6e4>] wb_workfn+0x507/0x770
    [<000000005d8f6f94>] process_one_work+0x226/0x540
    [<000000000c3dd58a>] worker_thread+0x1b3/0x680
    [<00000000457537ac>] kthread+0x159/0x1c0
    [<000000000ef58c85>] ret_from_fork+0x1f/0x30

This issue can be avoided by promptly using kvfree.

Fixes: 8e7360f6 ("CIFS: Add support for direct pages in wdata")
Signed-off-by: default avatarZizhi Wo <wozizhi@huawei.com>
parent 6827f6e2
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -2119,12 +2119,17 @@ cifs_writev_complete(struct work_struct *work)
struct cifs_writedata *
cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
{
	struct cifs_writedata *wdata = NULL;

	struct page **pages =
		kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
	if (pages)
		return cifs_writedata_direct_alloc(pages, complete);
	if (pages) {
		wdata = cifs_writedata_direct_alloc(pages, complete);
		if (!wdata)
			kvfree(pages);
	}

	return NULL;
	return wdata;
}

struct cifs_writedata *