From: Zheng Li Date: Tue, 4 Jun 2013 03:34:33 +0000 (+0800) Subject: rds remove dev race. X-Git-Tag: v4.1.12-92~293^2^2~65 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=e61d9d253d4c5bf6e29288f4f3eeaa72f4d12b69;p=users%2Fjedix%2Flinux-maple.git rds remove dev race. 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 Signed-off-by: bang.nguyen@oracle.com (cherry picked from commit 62dab719ea687129dc52df2c2eec3b730d628b7a) --- diff --git a/net/rds/ib.c b/net/rds/ib.c index b80805b901772..ddeac1452c0ac 100644 --- a/net/rds/ib.c +++ b/net/rds/ib.c @@ -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); diff --git a/net/rds/ib.h b/net/rds/ib.h index 6711c6cb64bb6..886d91f71546d 100644 --- a/net/rds/ib.h +++ b/net/rds/ib.h @@ -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)