Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3422bfda authored by Zhipeng Lu's avatar Zhipeng Lu Committed by Greg Kroah-Hartman
Browse files

fjes: fix memleaks in fjes_hw_setup



[ Upstream commit f6cc4b6a3ae53df425771000e9c9540cce9b7bb1 ]

In fjes_hw_setup, it allocates several memory and delay the deallocation
to the fjes_hw_exit in fjes_probe through the following call chain:

fjes_probe
  |-> fjes_hw_init
        |-> fjes_hw_setup
  |-> fjes_hw_exit

However, when fjes_hw_setup fails, fjes_hw_exit won't be called and thus
all the resources allocated in fjes_hw_setup will be leaked. In this
patch, we free those resources in fjes_hw_setup and prevents such leaks.

Fixes: 2fcbca68 ("fjes: platform_driver's .probe and .remove routine")
Signed-off-by: default avatarZhipeng Lu <alexious@zju.edu.cn>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Link: https://lore.kernel.org/r/20240122172445.3841883-1-alexious@zju.edu.cn


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 07bcc3cd
Loading
Loading
Loading
Loading
+30 −7
Original line number Diff line number Diff line
@@ -220,21 +220,25 @@ static int fjes_hw_setup(struct fjes_hw *hw)

	mem_size = FJES_DEV_REQ_BUF_SIZE(hw->max_epid);
	hw->hw_info.req_buf = kzalloc(mem_size, GFP_KERNEL);
	if (!(hw->hw_info.req_buf))
		return -ENOMEM;
	if (!(hw->hw_info.req_buf)) {
		result = -ENOMEM;
		goto free_ep_info;
	}

	hw->hw_info.req_buf_size = mem_size;

	mem_size = FJES_DEV_RES_BUF_SIZE(hw->max_epid);
	hw->hw_info.res_buf = kzalloc(mem_size, GFP_KERNEL);
	if (!(hw->hw_info.res_buf))
		return -ENOMEM;
	if (!(hw->hw_info.res_buf)) {
		result = -ENOMEM;
		goto free_req_buf;
	}

	hw->hw_info.res_buf_size = mem_size;

	result = fjes_hw_alloc_shared_status_region(hw);
	if (result)
		return result;
		goto free_res_buf;

	hw->hw_info.buffer_share_bit = 0;
	hw->hw_info.buffer_unshare_reserve_bit = 0;
@@ -245,11 +249,11 @@ static int fjes_hw_setup(struct fjes_hw *hw)

			result = fjes_hw_alloc_epbuf(&buf_pair->tx);
			if (result)
				return result;
				goto free_epbuf;

			result = fjes_hw_alloc_epbuf(&buf_pair->rx);
			if (result)
				return result;
				goto free_epbuf;

			spin_lock_irqsave(&hw->rx_status_lock, flags);
			fjes_hw_setup_epbuf(&buf_pair->tx, mac,
@@ -272,6 +276,25 @@ static int fjes_hw_setup(struct fjes_hw *hw)
	fjes_hw_init_command_registers(hw, &param);

	return 0;

free_epbuf:
	for (epidx = 0; epidx < hw->max_epid ; epidx++) {
		if (epidx == hw->my_epid)
			continue;
		fjes_hw_free_epbuf(&hw->ep_shm_info[epidx].tx);
		fjes_hw_free_epbuf(&hw->ep_shm_info[epidx].rx);
	}
	fjes_hw_free_shared_status_region(hw);
free_res_buf:
	kfree(hw->hw_info.res_buf);
	hw->hw_info.res_buf = NULL;
free_req_buf:
	kfree(hw->hw_info.req_buf);
	hw->hw_info.req_buf = NULL;
free_ep_info:
	kfree(hw->ep_shm_info);
	hw->ep_shm_info = NULL;
	return result;
}

static void fjes_hw_cleanup(struct fjes_hw *hw)