Skip to content

Commit

Permalink
NFS: Fix a refcount leakage in O_DIRECT
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Trond Myklebust authored and Trond Myklebust committed May 30, 2007
1 parent 7a74fc4 commit b4946ff
Showing 1 changed file with 9 additions and 3 deletions.
12 changes: 9 additions & 3 deletions fs/nfs/direct.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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.
*/
Expand All @@ -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;
}

Expand All @@ -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);
}

/*
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit b4946ff

Please sign in to comment.