Commit 9565c6a3 authored by Mitko Haralanov's avatar Mitko Haralanov Committed by Doug Ledford

IB/hfi1: Fix an interval RB node reference count leak

Commit e88c9271 ("IB/hfi1: Fix buffer cache corner case which
may cause corruption") introduced a bug which may cause a reference
count of a interval RB node to be leaked in the case where an SDMA
transfer from that node completes at the same time as the node is
being extended.

If a node is being extended, it is first removed from the RB tree
in order to be processed without the risk of an invalidation event
removing the node at the same time.

If a SDMA completion happens during that time, the completion handler
will fail to find the node in the RB tree and, therefore, fail to
correctly decrement its refcount. This leaves the node in the tree and
its pages pinned for the duration of the user process.

To prevent this from happening the io vector adds a reference to the
RB node, which is used during the SDMA completion instead of looking
up the node in the RB tree.

This change adds a performance improvement as a side effect by avoiding
the RB tree lookup.

Fixes: e88c9271 ("IB/hfi1: Fix buffer cache corner case which may cause corruption")
Reviewed-by: default avatarDean Luick <dean.luick@intel.com>
Reviewed-by: default avatarHarish Chegondi <harish.chegondi@intel.com>
Signed-off-by: default avatarMitko Haralanov <mitko.haralanov@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent eea57078
......@@ -166,6 +166,8 @@ static unsigned initial_pkt_count = 8;
#define SDMA_IOWAIT_TIMEOUT 1000 /* in milliseconds */
struct sdma_mmu_node;
struct user_sdma_iovec {
struct list_head list;
struct iovec iov;
......@@ -178,6 +180,7 @@ struct user_sdma_iovec {
* which we last left off.
*/
u64 offset;
struct sdma_mmu_node *node;
};
#define SDMA_CACHE_NODE_EVICT BIT(0)
......@@ -1153,6 +1156,7 @@ static int pin_vector_pages(struct user_sdma_request *req,
}
iovec->pages = node->pages;
iovec->npages = npages;
iovec->node = node;
ret = hfi1_mmu_rb_insert(&req->pq->sdma_rb_root, &node->rb);
if (ret) {
......@@ -1519,18 +1523,13 @@ static void user_sdma_free_request(struct user_sdma_request *req, bool unpin)
}
if (req->data_iovs) {
struct sdma_mmu_node *node;
struct mmu_rb_node *mnode;
int i;
for (i = 0; i < req->data_iovs; i++) {
mnode = hfi1_mmu_rb_search(
&req->pq->sdma_rb_root,
(unsigned long)req->iovs[i].iov.iov_base,
req->iovs[i].iov.iov_len);
if (!mnode || IS_ERR(mnode))
node = req->iovs[i].node;
if (!node)
continue;
node = container_of(mnode, struct sdma_mmu_node, rb);
if (unpin)
hfi1_mmu_rb_remove(&req->pq->sdma_rb_root,
&node->rb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment