]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
rds remove dev race.
authorZheng Li <zheng.x.li@oracle.com>
Tue, 4 Jun 2013 03:34:33 +0000 (11:34 +0800)
committerMukesh Kacker <mukesh.kacker@oracle.com>
Wed, 8 Jul 2015 20:37:58 +0000 (13:37 -0700)
Orabug: 16605377

RDS: make sure rds_ib_remove_one() returns only after the device is freed.

This is to avoid possible race condition in which rds_ib_remove_one() returns
prematurely and IB removes the underlying device. RDS later tries to free the
device and trips over.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
Signed-off-by: bang.nguyen@oracle.com
(cherry picked from commit 62dab719ea687129dc52df2c2eec3b730d628b7a)

net/rds/ib.c
net/rds/ib.h

index b80805b901772c7c198f785a174aaddd7739b379..ddeac1452c0acb5450d552c023df60996c1313fd 100644 (file)
@@ -171,7 +171,10 @@ static void rds_ib_dev_free(struct work_struct *work)
        if (rds_ibdev->vector_load)
                kfree(rds_ibdev->vector_load);
 
-       kfree(rds_ibdev);
+       WARN_ON(!waitqueue_active(&rds_ibdev->wait));
+
+       rds_ibdev->done = 1;
+       wake_up(&rds_ibdev->wait);
 }
 
 void rds_ib_dev_put(struct rds_ib_device *rds_ibdev)
@@ -244,6 +247,13 @@ void rds_ib_remove_one(struct ib_device *device)
        synchronize_rcu();
        rds_ib_dev_put(rds_ibdev);
        rds_ib_dev_put(rds_ibdev);
+
+       if (!wait_event_timeout(rds_ibdev->wait, rds_ibdev->done, 30*HZ))
+               printk(KERN_WARNING "RDS/IB: device cleanup timed out after "
+                       " 30 secs (refcount=%d)\n",
+                        atomic_read(&rds_ibdev->refcount));
+
+       kfree(rds_ibdev);
 }
 
 struct ib_client rds_ib_client = {
@@ -1201,6 +1211,8 @@ void rds_ib_add_one(struct ib_device *device)
        spin_lock_init(&rds_ibdev->spinlock);
        atomic_set(&rds_ibdev->refcount, 1);
        INIT_WORK(&rds_ibdev->free_work, rds_ib_dev_free);
+       init_waitqueue_head(&rds_ibdev->wait);
+       rds_ibdev->done = 0;
 
        rds_ibdev->max_wrs = dev_attr->max_qp_wr;
        rds_ibdev->max_sge = min(dev_attr->max_sge, RDS_IB_MAX_SGE);
index 6711c6cb64bb6fa1dd3a9214fc5db1c07de930d7..886d91f71546d9b33a3ffcafdef5bac68c6a869a 100644 (file)
@@ -333,6 +333,8 @@ struct rds_ib_device {
        struct rds_ib_port      *ports;
        struct ib_event_handler event_handler;
        int                     *vector_load;
+       wait_queue_head_t       wait;
+       int                     done;
 };
 
 #define pcidev_to_node(pcidev) pcibus_to_node(pcidev->bus)