RDSRDMA: Fix cleanup of rds_iw_mr_pool
In the rds_iw_mr_pool struct the free_pinned field keeps track of memory pinned by free MRs. While this field is incremented properly upon allocation, it is never decremented upon unmapping. This would cause the rds_rdma module to crash the kernel upon unloading, by triggering the BUG_ON in the rds_iw_destroy_mr_pool function. This change keeps track of the MRs that become unpinned, so that free_pinned can be decremented appropriately. Signed-off-by: Jonathan Lallinger <jonathan@ogc.us> Signed-off-by: Steve Wise <swise@ogc.us> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
605b91c8f6
commit
85a6488949
|
@ -84,7 +84,8 @@ static int rds_iw_map_fastreg(struct rds_iw_mr_pool *pool,
|
|||
static void rds_iw_free_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
|
||||
static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
|
||||
struct list_head *unmap_list,
|
||||
struct list_head *kill_list);
|
||||
struct list_head *kill_list,
|
||||
int *unpinned);
|
||||
static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
|
||||
|
||||
static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwdev, struct rdma_cm_id **cm_id)
|
||||
|
@ -499,7 +500,7 @@ static int rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all)
|
|||
LIST_HEAD(unmap_list);
|
||||
LIST_HEAD(kill_list);
|
||||
unsigned long flags;
|
||||
unsigned int nfreed = 0, ncleaned = 0, free_goal;
|
||||
unsigned int nfreed = 0, ncleaned = 0, unpinned = 0, free_goal;
|
||||
int ret = 0;
|
||||
|
||||
rds_iw_stats_inc(s_iw_rdma_mr_pool_flush);
|
||||
|
@ -524,7 +525,8 @@ static int rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all)
|
|||
* will be destroyed by the unmap function.
|
||||
*/
|
||||
if (!list_empty(&unmap_list)) {
|
||||
ncleaned = rds_iw_unmap_fastreg_list(pool, &unmap_list, &kill_list);
|
||||
ncleaned = rds_iw_unmap_fastreg_list(pool, &unmap_list,
|
||||
&kill_list, &unpinned);
|
||||
/* If we've been asked to destroy all MRs, move those
|
||||
* that were simply cleaned to the kill list */
|
||||
if (free_all)
|
||||
|
@ -548,6 +550,7 @@ static int rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all)
|
|||
spin_unlock_irqrestore(&pool->list_lock, flags);
|
||||
}
|
||||
|
||||
atomic_sub(unpinned, &pool->free_pinned);
|
||||
atomic_sub(ncleaned, &pool->dirty_count);
|
||||
atomic_sub(nfreed, &pool->item_count);
|
||||
|
||||
|
@ -828,7 +831,8 @@ static void rds_iw_free_fastreg(struct rds_iw_mr_pool *pool,
|
|||
|
||||
static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
|
||||
struct list_head *unmap_list,
|
||||
struct list_head *kill_list)
|
||||
struct list_head *kill_list,
|
||||
int *unpinned)
|
||||
{
|
||||
struct rds_iw_mapping *mapping, *next;
|
||||
unsigned int ncleaned = 0;
|
||||
|
@ -855,6 +859,7 @@ static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
|
|||
|
||||
spin_lock_irqsave(&pool->list_lock, flags);
|
||||
list_for_each_entry_safe(mapping, next, unmap_list, m_list) {
|
||||
*unpinned += mapping->m_sg.len;
|
||||
list_move(&mapping->m_list, &laundered);
|
||||
ncleaned++;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue