RDMA/cma: Refactor the inbound/outbound path records process flow

Refactors based on comments [1] of the multiple path records support
patchset:
- Return failure if not able to set inbound/outbound PRs;
- Simplify the flow when receiving the PRs from netlink channel: When
  a good PR response is received, unpack it and call the path_query
  callback directly. This saves two memory allocations;
- Define RDMA_PRIMARY_PATH_MAX_REC_NUM in a proper place.

[1] https://lore.kernel.org/linux-rdma/Yyxp9E9pJtUids2o@nvidia.com/

Signed-off-by: Mark Zhang <markzhang@nvidia.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org> #srp
Link: https://lore.kernel.org/r/7610025d57342b8b6da0f19516c9612f9c3fdc37.1672819376.git.leonro@nvidia.com
Signed-off-by: Leon Romanovsky <leon@kernel.org>
This commit is contained in:
Mark Zhang 2023-01-04 10:03:41 +02:00 committed by Leon Romanovsky
parent 8d037973d4
commit ccae0447af
6 changed files with 75 additions and 133 deletions

View File

@ -2819,8 +2819,8 @@ int rdma_set_min_rnr_timer(struct rdma_cm_id *id, u8 min_rnr_timer)
} }
EXPORT_SYMBOL(rdma_set_min_rnr_timer); EXPORT_SYMBOL(rdma_set_min_rnr_timer);
static void route_set_path_rec_inbound(struct cma_work *work, static int route_set_path_rec_inbound(struct cma_work *work,
struct sa_path_rec *path_rec) struct sa_path_rec *path_rec)
{ {
struct rdma_route *route = &work->id->id.route; struct rdma_route *route = &work->id->id.route;
@ -2828,14 +2828,15 @@ static void route_set_path_rec_inbound(struct cma_work *work,
route->path_rec_inbound = route->path_rec_inbound =
kzalloc(sizeof(*route->path_rec_inbound), GFP_KERNEL); kzalloc(sizeof(*route->path_rec_inbound), GFP_KERNEL);
if (!route->path_rec_inbound) if (!route->path_rec_inbound)
return; return -ENOMEM;
} }
*route->path_rec_inbound = *path_rec; *route->path_rec_inbound = *path_rec;
return 0;
} }
static void route_set_path_rec_outbound(struct cma_work *work, static int route_set_path_rec_outbound(struct cma_work *work,
struct sa_path_rec *path_rec) struct sa_path_rec *path_rec)
{ {
struct rdma_route *route = &work->id->id.route; struct rdma_route *route = &work->id->id.route;
@ -2843,14 +2844,15 @@ static void route_set_path_rec_outbound(struct cma_work *work,
route->path_rec_outbound = route->path_rec_outbound =
kzalloc(sizeof(*route->path_rec_outbound), GFP_KERNEL); kzalloc(sizeof(*route->path_rec_outbound), GFP_KERNEL);
if (!route->path_rec_outbound) if (!route->path_rec_outbound)
return; return -ENOMEM;
} }
*route->path_rec_outbound = *path_rec; *route->path_rec_outbound = *path_rec;
return 0;
} }
static void cma_query_handler(int status, struct sa_path_rec *path_rec, static void cma_query_handler(int status, struct sa_path_rec *path_rec,
int num_prs, void *context) unsigned int num_prs, void *context)
{ {
struct cma_work *work = context; struct cma_work *work = context;
struct rdma_route *route; struct rdma_route *route;
@ -2865,13 +2867,15 @@ static void cma_query_handler(int status, struct sa_path_rec *path_rec,
if (!path_rec[i].flags || (path_rec[i].flags & IB_PATH_GMP)) if (!path_rec[i].flags || (path_rec[i].flags & IB_PATH_GMP))
*route->path_rec = path_rec[i]; *route->path_rec = path_rec[i];
else if (path_rec[i].flags & IB_PATH_INBOUND) else if (path_rec[i].flags & IB_PATH_INBOUND)
route_set_path_rec_inbound(work, &path_rec[i]); status = route_set_path_rec_inbound(work, &path_rec[i]);
else if (path_rec[i].flags & IB_PATH_OUTBOUND) else if (path_rec[i].flags & IB_PATH_OUTBOUND)
route_set_path_rec_outbound(work, &path_rec[i]); status = route_set_path_rec_outbound(work,
} &path_rec[i]);
if (!route->path_rec) { else
status = -EINVAL; status = -EINVAL;
goto fail;
if (status)
goto fail;
} }
route->num_pri_alt_paths = 1; route->num_pri_alt_paths = 1;

View File

@ -106,7 +106,7 @@ struct ib_sa_device {
struct ib_sa_query { struct ib_sa_query {
void (*callback)(struct ib_sa_query *sa_query, int status, void (*callback)(struct ib_sa_query *sa_query, int status,
int num_prs, struct ib_sa_mad *mad); struct ib_sa_mad *mad);
void (*release)(struct ib_sa_query *); void (*release)(struct ib_sa_query *);
struct ib_sa_client *client; struct ib_sa_client *client;
struct ib_sa_port *port; struct ib_sa_port *port;
@ -118,12 +118,6 @@ struct ib_sa_query {
u32 seq; /* Local svc request sequence number */ u32 seq; /* Local svc request sequence number */
unsigned long timeout; /* Local svc timeout */ unsigned long timeout; /* Local svc timeout */
u8 path_use; /* How will the pathrecord be used */ u8 path_use; /* How will the pathrecord be used */
/* A separate buffer to save pathrecords of a response, as in cases
* like IB/netlink, mulptiple pathrecords are supported, so that
* mad->data is not large enough to hold them
*/
void *resp_pr_data;
}; };
#define IB_SA_ENABLE_LOCAL_SERVICE 0x00000001 #define IB_SA_ENABLE_LOCAL_SERVICE 0x00000001
@ -132,7 +126,7 @@ struct ib_sa_query {
struct ib_sa_path_query { struct ib_sa_path_query {
void (*callback)(int status, struct sa_path_rec *rec, void (*callback)(int status, struct sa_path_rec *rec,
int num_paths, void *context); unsigned int num_paths, void *context);
void *context; void *context;
struct ib_sa_query sa_query; struct ib_sa_query sa_query;
struct sa_path_rec *conv_pr; struct sa_path_rec *conv_pr;
@ -690,6 +684,8 @@ static const struct ib_field guidinfo_rec_table[] = {
.size_bits = 512 }, .size_bits = 512 },
}; };
#define RDMA_PRIMARY_PATH_MAX_REC_NUM 3
static inline void ib_sa_disable_local_svc(struct ib_sa_query *query) static inline void ib_sa_disable_local_svc(struct ib_sa_query *query)
{ {
query->flags &= ~IB_SA_ENABLE_LOCAL_SERVICE; query->flags &= ~IB_SA_ENABLE_LOCAL_SERVICE;
@ -874,30 +870,21 @@ static void send_handler(struct ib_mad_agent *agent,
static void ib_nl_process_good_resolve_rsp(struct ib_sa_query *query, static void ib_nl_process_good_resolve_rsp(struct ib_sa_query *query,
const struct nlmsghdr *nlh) const struct nlmsghdr *nlh)
{ {
struct ib_path_rec_data *srec, *drec; struct sa_path_rec recs[RDMA_PRIMARY_PATH_MAX_REC_NUM];
struct ib_sa_path_query *path_query; struct ib_sa_path_query *path_query;
struct ib_path_rec_data *rec_data;
struct ib_mad_send_wc mad_send_wc; struct ib_mad_send_wc mad_send_wc;
const struct nlattr *head, *curr; const struct nlattr *head, *curr;
struct ib_sa_mad *mad = NULL; struct ib_sa_mad *mad = NULL;
int len, rem, num_prs = 0; int len, rem, status = -EIO;
unsigned int num_prs = 0;
u32 mask = 0; u32 mask = 0;
int status = -EIO;
if (!query->callback) if (!query->callback)
goto out; goto out;
path_query = container_of(query, struct ib_sa_path_query, sa_query); path_query = container_of(query, struct ib_sa_path_query, sa_query);
mad = query->mad_buf->mad; mad = query->mad_buf->mad;
if (!path_query->conv_pr &&
(be16_to_cpu(mad->mad_hdr.attr_id) == IB_SA_ATTR_PATH_REC)) {
/* Need a larger buffer for possible multiple PRs */
query->resp_pr_data = kvcalloc(RDMA_PRIMARY_PATH_MAX_REC_NUM,
sizeof(*drec), GFP_KERNEL);
if (!query->resp_pr_data) {
query->callback(query, -ENOMEM, 0, NULL);
return;
}
}
head = (const struct nlattr *) nlmsg_data(nlh); head = (const struct nlattr *) nlmsg_data(nlh);
len = nlmsg_len(nlh); len = nlmsg_len(nlh);
@ -917,36 +904,41 @@ static void ib_nl_process_good_resolve_rsp(struct ib_sa_query *query,
break; break;
} }
drec = (struct ib_path_rec_data *)query->resp_pr_data;
nla_for_each_attr(curr, head, len, rem) { nla_for_each_attr(curr, head, len, rem) {
if (curr->nla_type != LS_NLA_TYPE_PATH_RECORD) if (curr->nla_type != LS_NLA_TYPE_PATH_RECORD)
continue; continue;
srec = nla_data(curr); rec_data = nla_data(curr);
if ((srec->flags & mask) != mask) if ((rec_data->flags & mask) != mask)
continue; continue;
status = 0; if ((query->flags & IB_SA_QUERY_OPA) ||
if (!drec) { path_query->conv_pr) {
memcpy(mad->data, srec->path_rec, mad->mad_hdr.method |= IB_MGMT_METHOD_RESP;
sizeof(srec->path_rec)); memcpy(mad->data, rec_data->path_rec,
num_prs = 1; sizeof(rec_data->path_rec));
break; query->callback(query, 0, mad);
goto out;
} }
memcpy(drec, srec, sizeof(*drec)); status = 0;
drec++; ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table),
rec_data->path_rec, &recs[num_prs]);
recs[num_prs].flags = rec_data->flags;
recs[num_prs].rec_type = SA_PATH_REC_TYPE_IB;
sa_path_set_dmac_zero(&recs[num_prs]);
num_prs++; num_prs++;
if (num_prs >= RDMA_PRIMARY_PATH_MAX_REC_NUM) if (num_prs >= RDMA_PRIMARY_PATH_MAX_REC_NUM)
break; break;
} }
if (!status) if (!status) {
mad->mad_hdr.method |= IB_MGMT_METHOD_RESP; mad->mad_hdr.method |= IB_MGMT_METHOD_RESP;
path_query->callback(status, recs, num_prs,
query->callback(query, status, num_prs, mad); path_query->context);
kvfree(query->resp_pr_data); } else
query->resp_pr_data = NULL; query->callback(query, status, mad);
out: out:
mad_send_wc.send_buf = query->mad_buf; mad_send_wc.send_buf = query->mad_buf;
@ -1451,11 +1443,26 @@ static int opa_pr_query_possible(struct ib_sa_client *client,
return PR_IB_SUPPORTED; return PR_IB_SUPPORTED;
} }
static void ib_sa_pr_callback_single(struct ib_sa_path_query *query, static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
int status, struct ib_sa_mad *mad) int status, struct ib_sa_mad *mad)
{ {
struct ib_sa_path_query *query =
container_of(sa_query, struct ib_sa_path_query, sa_query);
struct sa_path_rec rec = {}; struct sa_path_rec rec = {};
if (!mad) {
query->callback(status, NULL, 0, query->context);
return;
}
if (sa_query->flags & IB_SA_QUERY_OPA) {
ib_unpack(opa_path_rec_table, ARRAY_SIZE(opa_path_rec_table),
mad->data, &rec);
rec.rec_type = SA_PATH_REC_TYPE_OPA;
query->callback(status, &rec, 1, query->context);
return;
}
ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table), ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table),
mad->data, &rec); mad->data, &rec);
rec.rec_type = SA_PATH_REC_TYPE_IB; rec.rec_type = SA_PATH_REC_TYPE_IB;
@ -1472,71 +1479,6 @@ static void ib_sa_pr_callback_single(struct ib_sa_path_query *query,
} }
} }
/**
* ib_sa_pr_callback_multiple() - Parse path records then do callback.
*
* In a multiple-PR case the PRs are saved in "query->resp_pr_data"
* (instead of"mad->data") and with "ib_path_rec_data" structure format,
* so that rec->flags can be set to indicate the type of PR.
* This is valid only in IB fabric.
*/
static void ib_sa_pr_callback_multiple(struct ib_sa_path_query *query,
int status, int num_prs,
struct ib_path_rec_data *rec_data)
{
struct sa_path_rec *rec;
int i;
rec = kvcalloc(num_prs, sizeof(*rec), GFP_KERNEL);
if (!rec) {
query->callback(-ENOMEM, NULL, 0, query->context);
return;
}
for (i = 0; i < num_prs; i++) {
ib_unpack(path_rec_table, ARRAY_SIZE(path_rec_table),
rec_data[i].path_rec, rec + i);
rec[i].rec_type = SA_PATH_REC_TYPE_IB;
sa_path_set_dmac_zero(rec + i);
rec[i].flags = rec_data[i].flags;
}
query->callback(status, rec, num_prs, query->context);
kvfree(rec);
}
static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
int status, int num_prs,
struct ib_sa_mad *mad)
{
struct ib_sa_path_query *query =
container_of(sa_query, struct ib_sa_path_query, sa_query);
struct sa_path_rec rec;
if (!mad || !num_prs) {
query->callback(status, NULL, 0, query->context);
return;
}
if (sa_query->flags & IB_SA_QUERY_OPA) {
if (num_prs != 1) {
query->callback(-EINVAL, NULL, 0, query->context);
return;
}
ib_unpack(opa_path_rec_table, ARRAY_SIZE(opa_path_rec_table),
mad->data, &rec);
rec.rec_type = SA_PATH_REC_TYPE_OPA;
query->callback(status, &rec, num_prs, query->context);
} else {
if (!sa_query->resp_pr_data)
ib_sa_pr_callback_single(query, status, mad);
else
ib_sa_pr_callback_multiple(query, status, num_prs,
sa_query->resp_pr_data);
}
}
static void ib_sa_path_rec_release(struct ib_sa_query *sa_query) static void ib_sa_path_rec_release(struct ib_sa_query *sa_query)
{ {
struct ib_sa_path_query *query = struct ib_sa_path_query *query =
@ -1578,7 +1520,7 @@ int ib_sa_path_rec_get(struct ib_sa_client *client,
unsigned long timeout_ms, gfp_t gfp_mask, unsigned long timeout_ms, gfp_t gfp_mask,
void (*callback)(int status, void (*callback)(int status,
struct sa_path_rec *resp, struct sa_path_rec *resp,
int num_paths, void *context), unsigned int num_paths, void *context),
void *context, void *context,
struct ib_sa_query **sa_query) struct ib_sa_query **sa_query)
{ {
@ -1677,8 +1619,7 @@ err1:
EXPORT_SYMBOL(ib_sa_path_rec_get); EXPORT_SYMBOL(ib_sa_path_rec_get);
static void ib_sa_mcmember_rec_callback(struct ib_sa_query *sa_query, static void ib_sa_mcmember_rec_callback(struct ib_sa_query *sa_query,
int status, int num_prs, int status, struct ib_sa_mad *mad)
struct ib_sa_mad *mad)
{ {
struct ib_sa_mcmember_query *query = struct ib_sa_mcmember_query *query =
container_of(sa_query, struct ib_sa_mcmember_query, sa_query); container_of(sa_query, struct ib_sa_mcmember_query, sa_query);
@ -1769,8 +1710,7 @@ err1:
/* Support GuidInfoRecord */ /* Support GuidInfoRecord */
static void ib_sa_guidinfo_rec_callback(struct ib_sa_query *sa_query, static void ib_sa_guidinfo_rec_callback(struct ib_sa_query *sa_query,
int status, int num_paths, int status, struct ib_sa_mad *mad)
struct ib_sa_mad *mad)
{ {
struct ib_sa_guidinfo_query *query = struct ib_sa_guidinfo_query *query =
container_of(sa_query, struct ib_sa_guidinfo_query, sa_query); container_of(sa_query, struct ib_sa_guidinfo_query, sa_query);
@ -1879,8 +1819,7 @@ static void ib_classportinfo_cb(void *context)
} }
static void ib_sa_classport_info_rec_callback(struct ib_sa_query *sa_query, static void ib_sa_classport_info_rec_callback(struct ib_sa_query *sa_query,
int status, int num_prs, int status, struct ib_sa_mad *mad)
struct ib_sa_mad *mad)
{ {
unsigned long flags; unsigned long flags;
struct ib_sa_classport_info_query *query = struct ib_sa_classport_info_query *query =
@ -2055,13 +1994,13 @@ static void send_handler(struct ib_mad_agent *agent,
/* No callback -- already got recv */ /* No callback -- already got recv */
break; break;
case IB_WC_RESP_TIMEOUT_ERR: case IB_WC_RESP_TIMEOUT_ERR:
query->callback(query, -ETIMEDOUT, 0, NULL); query->callback(query, -ETIMEDOUT, NULL);
break; break;
case IB_WC_WR_FLUSH_ERR: case IB_WC_WR_FLUSH_ERR:
query->callback(query, -EINTR, 0, NULL); query->callback(query, -EINTR, NULL);
break; break;
default: default:
query->callback(query, -EIO, 0, NULL); query->callback(query, -EIO, NULL);
break; break;
} }
@ -2089,10 +2028,10 @@ static void recv_handler(struct ib_mad_agent *mad_agent,
if (mad_recv_wc->wc->status == IB_WC_SUCCESS) if (mad_recv_wc->wc->status == IB_WC_SUCCESS)
query->callback(query, query->callback(query,
mad_recv_wc->recv_buf.mad->mad_hdr.status ? mad_recv_wc->recv_buf.mad->mad_hdr.status ?
-EINVAL : 0, 1, -EINVAL : 0,
(struct ib_sa_mad *) mad_recv_wc->recv_buf.mad); (struct ib_sa_mad *) mad_recv_wc->recv_buf.mad);
else else
query->callback(query, -EIO, 0, NULL); query->callback(query, -EIO, NULL);
} }
ib_free_recv_mad(mad_recv_wc); ib_free_recv_mad(mad_recv_wc);

View File

@ -742,7 +742,7 @@ void ipoib_flush_paths(struct net_device *dev)
static void path_rec_completion(int status, static void path_rec_completion(int status,
struct sa_path_rec *pathrec, struct sa_path_rec *pathrec,
int num_prs, void *path_ptr) unsigned int num_prs, void *path_ptr)
{ {
struct ipoib_path *path = path_ptr; struct ipoib_path *path = path_ptr;
struct net_device *dev = path->dev; struct net_device *dev = path->dev;

View File

@ -699,7 +699,7 @@ static void srp_free_ch_ib(struct srp_target_port *target,
static void srp_path_rec_completion(int status, static void srp_path_rec_completion(int status,
struct sa_path_rec *pathrec, struct sa_path_rec *pathrec,
int num_paths, void *ch_ptr) unsigned int num_paths, void *ch_ptr)
{ {
struct srp_rdma_ch *ch = ch_ptr; struct srp_rdma_ch *ch = ch_ptr;
struct srp_target_port *target = ch->target; struct srp_target_port *target = ch->target;

View File

@ -414,7 +414,7 @@ int ib_sa_path_rec_get(struct ib_sa_client *client, struct ib_device *device,
ib_sa_comp_mask comp_mask, unsigned long timeout_ms, ib_sa_comp_mask comp_mask, unsigned long timeout_ms,
gfp_t gfp_mask, gfp_t gfp_mask,
void (*callback)(int status, struct sa_path_rec *resp, void (*callback)(int status, struct sa_path_rec *resp,
int num_prs, void *context), unsigned int num_prs, void *context),
void *context, struct ib_sa_query **query); void *context, struct ib_sa_query **query);
struct ib_sa_multicast { struct ib_sa_multicast {

View File

@ -49,7 +49,6 @@ struct rdma_addr {
struct rdma_dev_addr dev_addr; struct rdma_dev_addr dev_addr;
}; };
#define RDMA_PRIMARY_PATH_MAX_REC_NUM 3
struct rdma_route { struct rdma_route {
struct rdma_addr addr; struct rdma_addr addr;
struct sa_path_rec *path_rec; struct sa_path_rec *path_rec;