From: Bang Nguyen Date: Mon, 28 Oct 2013 13:53:31 +0000 (-0700) Subject: rds/rdma_cm: send RDMA_CM_EVENT_ADDR_CHANGE event for active bonding X-Git-Tag: v4.1.12-92~293^2^2~38 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=7efbd5726f358583c5902213a99fd0ac1f16640c;p=users%2Fjedix%2Flinux-maple.git rds/rdma_cm: send RDMA_CM_EVENT_ADDR_CHANGE event for active bonding Orabug: 18421516 This patch is forward ported from ofa-2.6.32-400.1.1.el5.x86_64-1.5.5-4.1.15 Signed-off-by: Bang Nguyen Signed-off-by: Avneesh Pant Signed-off-by: Chien Yen Signed-off-by: Ajaykumar Hotchandani (cherry picked from commit b90f280baeedf4a56fae0c248d108ae118bb94ab) Signed-off-by: Jerry Snitselaar Conflicts: drivers/infiniband/core/cma.c --- diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 3eef7e352a72..f1f2eb60ac44 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2267,6 +2267,42 @@ int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse) } EXPORT_SYMBOL(rdma_set_reuseaddr); +int rdma_notify_addr_change(struct sockaddr *addr) +{ + struct cma_device *cma_dev; + struct rdma_id_private *id_priv; + struct sockaddr *src_addr; + struct cma_ndev_work *work; + int ret; + + mutex_lock(&lock); + list_for_each_entry(cma_dev, &dev_list, list) { + list_for_each_entry(id_priv, &cma_dev->id_list, list) { + src_addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; + if (addr->sa_family == AF_INET && + addr->sa_family == src_addr->sa_family && + ((struct sockaddr_in *) addr)->sin_addr.s_addr == + ((struct sockaddr_in *) src_addr)->sin_addr.s_addr) { + work = kzalloc(sizeof *work, GFP_ATOMIC); + if (!work) { + ret = -ENOMEM; + goto out; + } + + INIT_WORK(&work->work, cma_ndev_work_handler); + work->id = id_priv; + work->event.event = RDMA_CM_EVENT_ADDR_CHANGE; + atomic_inc(&id_priv->refcount); + queue_work(cma_wq, &work->work); + } + } + } +out: + mutex_unlock(&lock); + return ret; +} +EXPORT_SYMBOL(rdma_notify_addr_change); + int rdma_set_afonly(struct rdma_cm_id *id, int afonly) { struct rdma_id_private *id_priv; diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index 1ed2088dc9f5..feb5f95c129d 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -191,6 +191,14 @@ void rdma_destroy_id(struct rdma_cm_id *id); */ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr); +/** + * rdma_notify_addr_change - Notify users that its IP has moved to a + * different device. + * + * @addr: address information. + */ +int rdma_notify_addr_change(struct sockaddr *addr); + /** * rdma_resolve_addr - Resolve destination and optional source addresses * from IP addresses to an RDMA address. If successful, the specified diff --git a/net/rds/ib.c b/net/rds/ib.c index 948a3b3c0363..7bf7aa4c0e2e 100644 --- a/net/rds/ib.c +++ b/net/rds/ib.c @@ -559,6 +559,22 @@ static void rds_ib_conn_drop(struct work_struct *_work) kfree(work); } +static void rds_ib_notify_addr_change(struct work_struct *_work) +{ + struct rds_ib_addr_change_work *work = + container_of(_work, struct rds_ib_addr_change_work, work.work); + struct sockaddr_in sin; + int ret; + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = work->addr; + sin.sin_port = 0; + + ret = rdma_notify_addr_change((struct sockaddr *)&sin); + + kfree(work); +} + static int rds_ib_move_ip(char *from_dev, char *to_dev, u8 from_port, @@ -583,6 +599,7 @@ static int rds_ib_move_ip(char *from_dev, struct rds_ib_connection *ic, *ic2; struct rds_ib_device *rds_ibdev; struct rds_ib_conn_drop_work *work; + struct rds_ib_addr_change_work *work_addrchange; page = alloc_page(GFP_HIGHUSER); if (!page) { @@ -779,6 +796,15 @@ static int rds_ib_move_ip(char *from_dev, } } spin_unlock_bh(&rds_ibdev->spinlock); + + work_addrchange = kzalloc(sizeof *work, GFP_ATOMIC); + if (!work_addrchange) { + printk(KERN_WARNING "RDS/IB: failed to allocate work\n"); + goto out; + } + work_addrchange->addr = addr; + INIT_DELAYED_WORK(&work_addrchange->work, rds_ib_notify_addr_change); + queue_delayed_work(rds_wq, &work_addrchange->work, 10); } out: diff --git a/net/rds/ib.h b/net/rds/ib.h index 419b51e5ce66..eda984eeaf1d 100644 --- a/net/rds/ib.h +++ b/net/rds/ib.h @@ -324,6 +324,11 @@ struct rds_ib_conn_drop_work { struct rds_ib_connection *conn; }; +struct rds_ib_addr_change_work { + struct delayed_work work; + __be32 addr; +}; + enum { RDS_IB_MR_8K_POOL, RDS_IB_MR_1M_POOL, diff --git a/net/rds/rdma_transport.c b/net/rds/rdma_transport.c index 9e7c4bcf89c0..70019e1947e7 100644 --- a/net/rds/rdma_transport.c +++ b/net/rds/rdma_transport.c @@ -203,6 +203,8 @@ int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id, break; case RDMA_CM_EVENT_ADDR_CHANGE: + rdsdebug("ADDR_CHANGE event <%u.%u.%u.%u,%u.%u.%u.%u>\n", + NIPQUAD(conn->c_laddr), NIPQUAD(conn->c_faddr)); #if RDMA_RDS_APM_SUPPORTED if (conn && !rds_ib_apm_enabled) rds_conn_drop(conn);