Skip to content

Commit 17ad31b

Browse files
jtlaytonchucklever
authored andcommitted
sunrpc: fix cache_request leak in cache_release
When a reader's file descriptor is closed while in the middle of reading a cache_request (rp->offset != 0), cache_release() decrements the request's readers count but never checks whether it should free the request. In cache_read(), when readers drops to 0 and CACHE_PENDING is clear, the cache_request is removed from the queue and freed along with its buffer and cache_head reference. cache_release() lacks this cleanup. The only other path that frees requests with readers == 0 is cache_dequeue(), but it runs only when CACHE_PENDING transitions from set to clear. If that transition already happened while readers was still non-zero, cache_dequeue() will have skipped the request, and no subsequent call will clean it up. Add the same cleanup logic from cache_read() to cache_release(): after decrementing readers, check if it reached 0 with CACHE_PENDING clear, and if so, dequeue and free the cache_request. Reported-by: NeilBrown <[email protected]> Fixes: 1da177e ("Linux-2.6.12-rc2") Cc: [email protected] Signed-off-by: Jeff Layton <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent e7fcf17 commit 17ad31b

1 file changed

Lines changed: 21 additions & 5 deletions

File tree

net/sunrpc/cache.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,24 +1061,40 @@ static int cache_release(struct inode *inode, struct file *filp,
10611061
struct cache_reader *rp = filp->private_data;
10621062

10631063
if (rp) {
1064+
struct cache_request *rq = NULL;
1065+
10641066
spin_lock(&queue_lock);
10651067
if (rp->offset) {
10661068
struct cache_queue *cq;
1067-
for (cq= &rp->q; &cq->list != &cd->queue;
1068-
cq = list_entry(cq->list.next, struct cache_queue, list))
1069+
for (cq = &rp->q; &cq->list != &cd->queue;
1070+
cq = list_entry(cq->list.next,
1071+
struct cache_queue, list))
10691072
if (!cq->reader) {
1070-
container_of(cq, struct cache_request, q)
1071-
->readers--;
1073+
struct cache_request *cr =
1074+
container_of(cq,
1075+
struct cache_request, q);
1076+
cr->readers--;
1077+
if (cr->readers == 0 &&
1078+
!test_bit(CACHE_PENDING,
1079+
&cr->item->flags)) {
1080+
list_del(&cr->q.list);
1081+
rq = cr;
1082+
}
10721083
break;
10731084
}
10741085
rp->offset = 0;
10751086
}
10761087
list_del(&rp->q.list);
10771088
spin_unlock(&queue_lock);
10781089

1090+
if (rq) {
1091+
cache_put(rq->item, cd);
1092+
kfree(rq->buf);
1093+
kfree(rq);
1094+
}
1095+
10791096
filp->private_data = NULL;
10801097
kfree(rp);
1081-
10821098
}
10831099
if (filp->f_mode & FMODE_WRITE) {
10841100
atomic_dec(&cd->writers);

0 commit comments

Comments
 (0)