Quoting r. Sean Hefty <[EMAIL PROTECTED]>: > Subject: RE: Fwd: issues in ipoib > > >Yes. But if the user already has to keep track of when the deregister > >of its SA client starts, then what is gained by taking a reference > >when a query starts? > > It seems cleaner to me. When a user calls query(), they provide a pointer to > their sa_client. We take a reference to that pointer and store it in the > sa_query structure. We now expect that pointer to be valid at a later point, > so > we can increment the reference count on it. Why not increment the reference > count when we take the actual reference and save off the pointer? > > The benefit is that when the user later tries to deregister, deregister will > block while there's an outstanding query. This eliminates the need for > clients > to track their queries, cancel all of them, then wait for them to complete > before calling deregister - which would involve another reference count and > completion structure on the part of the client. > > Thinking about this more, I can see where a user would want to create one > struct > ib_sa_client per device to simplify their life handling device removal. > > - Sean >
Here's a patch for you to play with. I'll drop this for now. -- Require registration with SA module, to prevent module text from going away while sa query callback is still running, and update all users. Signed-off-by: Michael S. Tsirkin <[EMAIL PROTECTED]> diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index d6f99d5..bf668b3 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -60,6 +60,10 @@ static struct ib_client cma_client = { .remove = cma_remove_one }; +static struct ib_sa_client cma_sa_client = { + .name = "cma" +}; + static LIST_HEAD(dev_list); static LIST_HEAD(listen_any_list); static DEFINE_MUTEX(lock); @@ -1140,7 +1144,7 @@ static int cma_query_ib_route(struct rdm path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr)); path_rec.numb_path = 1; - id_priv->query_id = ib_sa_path_rec_get(id_priv->id.device, + id_priv->query_id = ib_sa_path_rec_get(&cma_sa_client, id_priv->id.device, id_priv->id.port_num, &path_rec, IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH, @@ -1910,6 +1914,8 @@ static int cma_init(void) ret = ib_register_client(&cma_client); if (ret) goto err; + + ib_sa_register_client(&cma_sa_client); return 0; err: @@ -1919,6 +1925,7 @@ err: static void cma_cleanup(void) { + ib_sa_unregister_client(&cma_sa_client); ib_unregister_client(&cma_client); destroy_workqueue(cma_wq); idr_destroy(&sdp_ps); diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index aeda484..43b0323 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -78,6 +78,7 @@ struct ib_sa_query { struct ib_sa_port *port; struct ib_mad_send_buf *mad_buf; struct ib_sa_sm_ah *sm_ah; + struct ib_sa_client *client; int id; }; @@ -532,6 +533,20 @@ retry: return ret ? ret : id; } +static inline void ib_sa_client_get(struct ib_sa_query *query, + struct ib_sa_client *client) +{ + query->client = client; + atomic_inc(&client->users); +} + +static inline void ib_sa_client_put(struct ib_sa_query *query) +{ + struct ib_sa_client *client = query->client; + if (atomic_dec_and_test(&client->users)) + complete(&client->completion); +} + static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query, int status, struct ib_sa_mad *mad) @@ -547,6 +562,7 @@ static void ib_sa_path_rec_callback(stru query->callback(status, &rec, query->context); } else query->callback(status, NULL, query->context); + ib_sa_client_put(sa_query); } static void ib_sa_path_rec_release(struct ib_sa_query *sa_query) @@ -556,6 +572,7 @@ static void ib_sa_path_rec_release(struc /** * ib_sa_path_rec_get - Start a Path get query + * @client:client object used to track the query * @device:device to send query on * @port_num: port number to send query on * @rec:Path Record to send in query @@ -578,7 +595,8 @@ static void ib_sa_path_rec_release(struc * error code. Otherwise it is a query ID that can be used to cancel * the query. */ -int ib_sa_path_rec_get(struct ib_device *device, u8 port_num, +int ib_sa_path_rec_get(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, struct ib_sa_path_rec *rec, ib_sa_comp_mask comp_mask, int timeout_ms, gfp_t gfp_mask, @@ -619,6 +637,7 @@ int ib_sa_path_rec_get(struct ib_device mad = query->sa_query.mad_buf->mad; init_mad(mad, agent); + ib_sa_client_get(&query->sa_query, client); query->sa_query.callback = callback ? ib_sa_path_rec_callback : NULL; query->sa_query.release = ib_sa_path_rec_release; query->sa_query.port = port; @@ -638,6 +657,7 @@ int ib_sa_path_rec_get(struct ib_device err2: *sa_query = NULL; + ib_sa_client_put(&query->sa_query); ib_free_send_mad(query->sa_query.mad_buf); err1: @@ -661,6 +681,7 @@ static void ib_sa_service_rec_callback(s query->callback(status, &rec, query->context); } else query->callback(status, NULL, query->context); + ib_sa_client_put(sa_query); } static void ib_sa_service_rec_release(struct ib_sa_query *sa_query) @@ -670,6 +691,7 @@ static void ib_sa_service_rec_release(st /** * ib_sa_service_rec_query - Start Service Record operation + * @client:client object used to track the query * @device:device to send request on * @port_num: port number to send request on * @method:SA method - should be get, set, or delete @@ -694,7 +716,8 @@ static void ib_sa_service_rec_release(st * error code. Otherwise it is a request ID that can be used to cancel * the query. */ -int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, u8 method, +int ib_sa_service_rec_query(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, u8 method, struct ib_sa_service_rec *rec, ib_sa_comp_mask comp_mask, int timeout_ms, gfp_t gfp_mask, @@ -740,6 +763,7 @@ int ib_sa_service_rec_query(struct ib_de mad = query->sa_query.mad_buf->mad; init_mad(mad, agent); + ib_sa_client_get(&query->sa_query, client); query->sa_query.callback = callback ? ib_sa_service_rec_callback : NULL; query->sa_query.release = ib_sa_service_rec_release; query->sa_query.port = port; @@ -760,6 +784,7 @@ int ib_sa_service_rec_query(struct ib_de err2: *sa_query = NULL; + ib_sa_client_put(&query->sa_query); ib_free_send_mad(query->sa_query.mad_buf); err1: @@ -783,6 +808,7 @@ static void ib_sa_mcmember_rec_callback( query->callback(status, &rec, query->context); } else query->callback(status, NULL, query->context); + ib_sa_client_put(sa_query); } static void ib_sa_mcmember_rec_release(struct ib_sa_query *sa_query) @@ -790,7 +816,8 @@ static void ib_sa_mcmember_rec_release(s kfree(container_of(sa_query, struct ib_sa_mcmember_query, sa_query)); } -int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num, +int ib_sa_mcmember_rec_query(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, u8 method, struct ib_sa_mcmember_rec *rec, ib_sa_comp_mask comp_mask, @@ -832,6 +859,7 @@ int ib_sa_mcmember_rec_query(struct ib_d mad = query->sa_query.mad_buf->mad; init_mad(mad, agent); + ib_sa_client_get(&query->sa_query, client); query->sa_query.callback = callback ? ib_sa_mcmember_rec_callback : NULL; query->sa_query.release = ib_sa_mcmember_rec_release; query->sa_query.port = port; @@ -852,6 +880,7 @@ int ib_sa_mcmember_rec_query(struct ib_d err2: *sa_query = NULL; + ib_sa_client_put(&query->sa_query); ib_free_send_mad(query->sa_query.mad_buf); err1: @@ -881,6 +910,7 @@ static void send_handler(struct ib_mad_a query->callback(query, -EIO, NULL); break; } + ib_sa_client_put(query); spin_lock_irqsave(&idr_lock, flags); idr_remove(&query_idr, query->id); @@ -909,7 +939,7 @@ static void recv_handler(struct ib_mad_a else query->callback(query, -EIO, NULL); } - + ib_sa_client_put(query); ib_free_recv_mad(mad_recv_wc); } diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 474aa21..28a9f0f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -390,4 +390,5 @@ #define IPOIB_GID_RAW_ARG(gid) ((u8 *)(g #define IPOIB_GID_ARG(gid) IPOIB_GID_RAW_ARG((gid).raw) +extern struct ib_sa_client ipoib_sa_client; #endif /* _IPOIB_H */ diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index cf71d2a..ca10724 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -91,6 +91,10 @@ static struct ib_client ipoib_client = { .remove = ipoib_remove_one }; +struct ib_sa_client ipoib_sa_client = { + .name = "ipoib" +}; + int ipoib_open(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -459,7 +463,7 @@ static int path_rec_start(struct net_dev init_completion(&path->done); path->query_id = - ib_sa_path_rec_get(priv->ca, priv->port, + ib_sa_path_rec_get(&ipoib_sa_client, priv->ca, priv->port, &path->pathrec, IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | @@ -1185,6 +1189,8 @@ static int __init ipoib_init_module(void if (ret) goto err_wq; + ib_sa_register_client(&ipoib_sa_client); + return 0; err_wq: @@ -1198,6 +1204,7 @@ err_fs: static void __exit ipoib_cleanup_module(void) { + ib_sa_unregister_client(&ipoib_sa_client); ib_unregister_client(&ipoib_client); ipoib_unregister_debugfs(); destroy_workqueue(ipoib_workqueue); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index b5e6a7b..f688323 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -360,7 +360,7 @@ #endif init_completion(&mcast->done); - ret = ib_sa_mcmember_rec_set(priv->ca, priv->port, &rec, + ret = ib_sa_mcmember_rec_set(&ipoib_sa_client, priv->ca, priv->port, &rec, IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | IB_SA_MCMEMBER_REC_PKEY | @@ -484,8 +484,8 @@ static void ipoib_mcast_join(struct net_ init_completion(&mcast->done); - ret = ib_sa_mcmember_rec_set(priv->ca, priv->port, &rec, comp_mask, - mcast->backoff * 1000, GFP_ATOMIC, + ret = ib_sa_mcmember_rec_set(&ipoib_sa_client, priv->ca, priv->port, &rec, + comp_mask, mcast->backoff * 1000, GFP_ATOMIC, ipoib_mcast_join_complete, mcast, &mcast->query); @@ -680,7 +680,7 @@ static int ipoib_mcast_leave(struct net_ * Just make one shot at leaving and don't wait for a reply; * if we fail, too bad. */ - ret = ib_sa_mcmember_rec_delete(priv->ca, priv->port, &rec, + ret = ib_sa_mcmember_rec_delete(&ipoib_sa_client, priv->ca, priv->port, &rec, IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID | IB_SA_MCMEMBER_REC_PKEY | diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 8f472e7..0856d78 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -88,6 +88,10 @@ static struct ib_client srp_client = { .remove = srp_remove_one }; +static struct ib_sa_client srp_sa_client = { + .name = "srp" +}; + static inline struct srp_target_port *host_to_target(struct Scsi_Host *host) { return (struct srp_target_port *) host->hostdata; @@ -259,7 +263,8 @@ static int srp_lookup_path(struct srp_ta init_completion(&target->done); - target->path_query_id = ib_sa_path_rec_get(target->srp_host->dev->dev, + target->path_query_id = ib_sa_path_rec_get(&srp_sa_client, + target->srp_host->dev->dev, target->srp_host->port, &target->path, IB_SA_PATH_REC_DGID | diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index c99e442..084baf4 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h @@ -37,6 +37,8 @@ #ifndef IB_SA_H #define IB_SA_H #include <linux/compiler.h> +#include <linux/completion.h> +#include <asm/atomic.h> #include <rdma/ib_verbs.h> #include <rdma/ib_mad.h> @@ -250,11 +252,18 @@ struct ib_sa_service_rec { u64 data64[2]; }; +struct ib_sa_client { + char *name; + atomic_t users; + struct completion completion; +}; + struct ib_sa_query; void ib_sa_cancel_query(int id, struct ib_sa_query *query); -int ib_sa_path_rec_get(struct ib_device *device, u8 port_num, +int ib_sa_path_rec_get(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, struct ib_sa_path_rec *rec, ib_sa_comp_mask comp_mask, int timeout_ms, gfp_t gfp_mask, @@ -264,7 +273,8 @@ int ib_sa_path_rec_get(struct ib_device void *context, struct ib_sa_query **query); -int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num, +int ib_sa_mcmember_rec_query(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, u8 method, struct ib_sa_mcmember_rec *rec, ib_sa_comp_mask comp_mask, @@ -275,7 +285,8 @@ int ib_sa_mcmember_rec_query(struct ib_d void *context, struct ib_sa_query **query); -int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, +int ib_sa_service_rec_query(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, u8 method, struct ib_sa_service_rec *rec, ib_sa_comp_mask comp_mask, @@ -288,6 +299,7 @@ int ib_sa_service_rec_query(struct ib_de /** * ib_sa_mcmember_rec_set - Start an MCMember set query + * @client:client object used to track the query * @device:device to send query on * @port_num: port number to send query on * @rec:MCMember Record to send in query @@ -311,7 +323,8 @@ int ib_sa_service_rec_query(struct ib_de * cancel the query. */ static inline int -ib_sa_mcmember_rec_set(struct ib_device *device, u8 port_num, +ib_sa_mcmember_rec_set(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, struct ib_sa_mcmember_rec *rec, ib_sa_comp_mask comp_mask, int timeout_ms, gfp_t gfp_mask, @@ -321,7 +334,7 @@ ib_sa_mcmember_rec_set(struct ib_device void *context, struct ib_sa_query **query) { - return ib_sa_mcmember_rec_query(device, port_num, + return ib_sa_mcmember_rec_query(client, device, port_num, IB_MGMT_METHOD_SET, rec, comp_mask, timeout_ms, gfp_mask, callback, @@ -330,6 +343,7 @@ ib_sa_mcmember_rec_set(struct ib_device /** * ib_sa_mcmember_rec_delete - Start an MCMember delete query + * @client:client object used to track the query * @device:device to send query on * @port_num: port number to send query on * @rec:MCMember Record to send in query @@ -353,7 +367,8 @@ ib_sa_mcmember_rec_set(struct ib_device * cancel the query. */ static inline int -ib_sa_mcmember_rec_delete(struct ib_device *device, u8 port_num, +ib_sa_mcmember_rec_delete(struct ib_sa_client *client, + struct ib_device *device, u8 port_num, struct ib_sa_mcmember_rec *rec, ib_sa_comp_mask comp_mask, int timeout_ms, gfp_t gfp_mask, @@ -363,7 +378,7 @@ ib_sa_mcmember_rec_delete(struct ib_devi void *context, struct ib_sa_query **query) { - return ib_sa_mcmember_rec_query(device, port_num, + return ib_sa_mcmember_rec_query(client, device, port_num, IB_SA_METHOD_DELETE, rec, comp_mask, timeout_ms, gfp_mask, callback, @@ -378,4 +393,25 @@ int ib_init_ah_from_path(struct ib_devic struct ib_sa_path_rec *rec, struct ib_ah_attr *ah_attr); +/** + * ib_sa_register_client - register SA client object + * @client:client object used to track queries + */ +static inline void ib_sa_register_client(struct ib_sa_client *client) +{ + atomic_set(&client->users, 1); + init_completion(&client->completion); +} + +/** + * ib_sa_unregister_client - unregister SA client object + * @client:client object used to track queries + */ +static inline void ib_sa_unregister_client(struct ib_sa_client *client) +{ + if (atomic_dec_and_test(&client->users)) + complete(&client->completion); + wait_for_completion(&client->completion); +} + #endif /* IB_SA_H */ diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h -- MST _______________________________________________ openib-general mailing list openib-general@openib.org http://openib.org/mailman/listinfo/openib-general To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general