aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/direct.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-05-30 12:58:00 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-05-30 16:26:01 -0400
commitb4946ffb1860597b187d78d61ac6504177eb0ff8 (patch)
tree56e5df1992aa478b806e5a768eda668543a5bb89 /fs/nfs/direct.c
parent7a74fc4925067c2102175baef73f9b07ab519b71 (diff)
NFS: Fix a refcount leakage in O_DIRECT
The current code is leaking a reference to dreq->kref when the calls to nfs_direct_read_schedule() and nfs_direct_write_schedule() return an error. This patch moves the call to kref_put() from nfs_direct_wait() back into nfs_direct_read() and nfs_direct_write() (which are the functions that actually took the reference in the first place) fixing the leak. Thanks to Denis V. Lunev for spotting the bug and proposing the original fix. Acked-by: Denis V. Lunev <dlunev@gmail.com> Acked-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r--fs/nfs/direct.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 0c542ec92d5b..00eee87510fe 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -168,7 +168,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
168 return dreq; 168 return dreq;
169} 169}
170 170
171static void nfs_direct_req_release(struct kref *kref) 171static void nfs_direct_req_free(struct kref *kref)
172{ 172{
173 struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); 173 struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref);
174 174
@@ -177,6 +177,11 @@ static void nfs_direct_req_release(struct kref *kref)
177 kmem_cache_free(nfs_direct_cachep, dreq); 177 kmem_cache_free(nfs_direct_cachep, dreq);
178} 178}
179 179
180static void nfs_direct_req_release(struct nfs_direct_req *dreq)
181{
182 kref_put(&dreq->kref, nfs_direct_req_free);
183}
184
180/* 185/*
181 * Collects and returns the final error value/byte-count. 186 * Collects and returns the final error value/byte-count.
182 */ 187 */
@@ -196,7 +201,6 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq)
196 result = dreq->count; 201 result = dreq->count;
197 202
198out: 203out:
199 kref_put(&dreq->kref, nfs_direct_req_release);
200 return (ssize_t) result; 204 return (ssize_t) result;
201} 205}
202 206
@@ -214,7 +218,7 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
214 } 218 }
215 complete_all(&dreq->completion); 219 complete_all(&dreq->completion);
216 220
217 kref_put(&dreq->kref, nfs_direct_req_release); 221 nfs_direct_req_release(dreq);
218} 222}
219 223
220/* 224/*
@@ -369,6 +373,7 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
369 if (!result) 373 if (!result)
370 result = nfs_direct_wait(dreq); 374 result = nfs_direct_wait(dreq);
371 rpc_clnt_sigunmask(clnt, &oldset); 375 rpc_clnt_sigunmask(clnt, &oldset);
376 nfs_direct_req_release(dreq);
372 377
373 return result; 378 return result;
374} 379}
@@ -716,6 +721,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
716 if (!result) 721 if (!result)
717 result = nfs_direct_wait(dreq); 722 result = nfs_direct_wait(dreq);
718 rpc_clnt_sigunmask(clnt, &oldset); 723 rpc_clnt_sigunmask(clnt, &oldset);
724 nfs_direct_req_release(dreq);
719 725
720 return result; 726 return result;
721} 727}