Gitweb: http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b4946ffb1860597b187d78d61ac6504177eb0ff8 Commit: b4946ffb1860597b187d78d61ac6504177eb0ff8 Parent: 7a74fc4925067c2102175baef73f9b07ab519b71 Author: Trond Myklebust <[EMAIL PROTECTED]> AuthorDate: Wed May 30 12:58:00 2007 -0400 Committer: Trond Myklebust <[EMAIL PROTECTED]> CommitDate: Wed May 30 16:26:01 2007 -0400
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 <[EMAIL PROTECTED]> Acked-by: Chuck Lever <[EMAIL PROTECTED]> Signed-off-by: Trond Myklebust <[EMAIL PROTECTED]> --- fs/nfs/direct.c | 12 +++++++++--- 1 files changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 0c542ec..00eee87 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) return dreq; } -static void nfs_direct_req_release(struct kref *kref) +static void nfs_direct_req_free(struct kref *kref) { struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); @@ -177,6 +177,11 @@ static void nfs_direct_req_release(struct kref *kref) kmem_cache_free(nfs_direct_cachep, dreq); } +static void nfs_direct_req_release(struct nfs_direct_req *dreq) +{ + kref_put(&dreq->kref, nfs_direct_req_free); +} + /* * Collects and returns the final error value/byte-count. */ @@ -196,7 +201,6 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq) result = dreq->count; out: - kref_put(&dreq->kref, nfs_direct_req_release); return (ssize_t) result; } @@ -214,7 +218,7 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq) } complete_all(&dreq->completion); - kref_put(&dreq->kref, nfs_direct_req_release); + nfs_direct_req_release(dreq); } /* @@ -369,6 +373,7 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size if (!result) result = nfs_direct_wait(dreq); rpc_clnt_sigunmask(clnt, &oldset); + nfs_direct_req_release(dreq); return result; } @@ -716,6 +721,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz if (!result) result = nfs_direct_wait(dreq); rpc_clnt_sigunmask(clnt, &oldset); + nfs_direct_req_release(dreq); return result; } - To unsubscribe from this list: send the line "unsubscribe git-commits-head" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html