diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-06-16 09:52:25 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-06-22 13:24:01 -0400 |
commit | d5f8d3fe72594f2e896b407f78daf24f37ef4d53 (patch) | |
tree | d81f0644eb0ce3dc504e3cd77355406d654555fa /fs | |
parent | d3f6baaa34c54040b3ef30950e59b54ac0624b21 (diff) |
NFSv41: Fix a memory leak in nfs41_proc_async_sequence()
If the call to rpc_call_async() fails, then the arguments will not be
freed, since there will be no call to nfs41_sequence_call_done
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 39 |
1 files changed, 21 insertions, 18 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 70015dd60a98..89be778a6543 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -5078,18 +5078,27 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | |||
5078 | &res, args.sa_cache_this, 1); | 5078 | &res, args.sa_cache_this, 1); |
5079 | } | 5079 | } |
5080 | 5080 | ||
5081 | struct nfs4_sequence_data { | ||
5082 | struct nfs_client *clp; | ||
5083 | struct nfs4_sequence_args args; | ||
5084 | struct nfs4_sequence_res res; | ||
5085 | }; | ||
5086 | |||
5081 | static void nfs41_sequence_release(void *data) | 5087 | static void nfs41_sequence_release(void *data) |
5082 | { | 5088 | { |
5083 | struct nfs_client *clp = (struct nfs_client *)data; | 5089 | struct nfs4_sequence_data *calldata = data; |
5090 | struct nfs_client *clp = calldata->clp; | ||
5084 | 5091 | ||
5085 | if (atomic_read(&clp->cl_count) > 1) | 5092 | if (atomic_read(&clp->cl_count) > 1) |
5086 | nfs4_schedule_state_renewal(clp); | 5093 | nfs4_schedule_state_renewal(clp); |
5087 | nfs_put_client(clp); | 5094 | nfs_put_client(clp); |
5095 | kfree(calldata); | ||
5088 | } | 5096 | } |
5089 | 5097 | ||
5090 | static void nfs41_sequence_call_done(struct rpc_task *task, void *data) | 5098 | static void nfs41_sequence_call_done(struct rpc_task *task, void *data) |
5091 | { | 5099 | { |
5092 | struct nfs_client *clp = (struct nfs_client *)data; | 5100 | struct nfs4_sequence_data *calldata = data; |
5101 | struct nfs_client *clp = calldata->clp; | ||
5093 | 5102 | ||
5094 | nfs41_sequence_done(clp, task->tk_msg.rpc_resp, task->tk_status); | 5103 | nfs41_sequence_done(clp, task->tk_msg.rpc_resp, task->tk_status); |
5095 | 5104 | ||
@@ -5106,19 +5115,16 @@ static void nfs41_sequence_call_done(struct rpc_task *task, void *data) | |||
5106 | } | 5115 | } |
5107 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | 5116 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); |
5108 | out: | 5117 | out: |
5109 | kfree(task->tk_msg.rpc_argp); | ||
5110 | kfree(task->tk_msg.rpc_resp); | ||
5111 | |||
5112 | dprintk("<-- %s\n", __func__); | 5118 | dprintk("<-- %s\n", __func__); |
5113 | } | 5119 | } |
5114 | 5120 | ||
5115 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | 5121 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) |
5116 | { | 5122 | { |
5117 | struct nfs_client *clp; | 5123 | struct nfs4_sequence_data *calldata = data; |
5124 | struct nfs_client *clp = calldata->clp; | ||
5118 | struct nfs4_sequence_args *args; | 5125 | struct nfs4_sequence_args *args; |
5119 | struct nfs4_sequence_res *res; | 5126 | struct nfs4_sequence_res *res; |
5120 | 5127 | ||
5121 | clp = (struct nfs_client *)data; | ||
5122 | args = task->tk_msg.rpc_argp; | 5128 | args = task->tk_msg.rpc_argp; |
5123 | res = task->tk_msg.rpc_resp; | 5129 | res = task->tk_msg.rpc_resp; |
5124 | 5130 | ||
@@ -5136,8 +5142,7 @@ static const struct rpc_call_ops nfs41_sequence_ops = { | |||
5136 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | 5142 | static int nfs41_proc_async_sequence(struct nfs_client *clp, |
5137 | struct rpc_cred *cred) | 5143 | struct rpc_cred *cred) |
5138 | { | 5144 | { |
5139 | struct nfs4_sequence_args *args; | 5145 | struct nfs4_sequence_data *calldata; |
5140 | struct nfs4_sequence_res *res; | ||
5141 | struct rpc_message msg = { | 5146 | struct rpc_message msg = { |
5142 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | 5147 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], |
5143 | .rpc_cred = cred, | 5148 | .rpc_cred = cred, |
@@ -5145,20 +5150,18 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, | |||
5145 | 5150 | ||
5146 | if (!atomic_inc_not_zero(&clp->cl_count)) | 5151 | if (!atomic_inc_not_zero(&clp->cl_count)) |
5147 | return -EIO; | 5152 | return -EIO; |
5148 | args = kzalloc(sizeof(*args), GFP_NOFS); | 5153 | calldata = kmalloc(sizeof(*calldata), GFP_NOFS); |
5149 | res = kzalloc(sizeof(*res), GFP_NOFS); | 5154 | if (calldata == NULL) { |
5150 | if (!args || !res) { | ||
5151 | kfree(args); | ||
5152 | kfree(res); | ||
5153 | nfs_put_client(clp); | 5155 | nfs_put_client(clp); |
5154 | return -ENOMEM; | 5156 | return -ENOMEM; |
5155 | } | 5157 | } |
5156 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 5158 | calldata->res.sr_slotid = NFS4_MAX_SLOT_TABLE; |
5157 | msg.rpc_argp = args; | 5159 | msg.rpc_argp = &calldata->args; |
5158 | msg.rpc_resp = res; | 5160 | msg.rpc_resp = &calldata->res; |
5161 | calldata->clp = clp; | ||
5159 | 5162 | ||
5160 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | 5163 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, |
5161 | &nfs41_sequence_ops, (void *)clp); | 5164 | &nfs41_sequence_ops, calldata); |
5162 | } | 5165 | } |
5163 | 5166 | ||
5164 | struct nfs4_reclaim_complete_data { | 5167 | struct nfs4_reclaim_complete_data { |