Commit d1fde520 authored by Vinit Agnihotri's avatar Vinit Agnihotri Committed by Luis Henriques

IB/qib: Support creating qps with GFP_NOIO flag

commit fbbeb863 upstream.

The current code is problematic when the QP creation and ipoib is used to
support NFS and NFS desires to do IO for paging purposes. In that case, the
GFP_KERNEL allocation in qib_qp.c causes a deadlock in tight memory
situations.

This fix adds support to create queue pair with GFP_NOIO flag for connected
mode only to cleanly fail the create queue pair in those situations.
Reviewed-by: default avatarMike Marciniszyn <mike.marciniszyn@intel.com>
Signed-off-by: default avatarVinit Agnihotri <vinit.abhay.agnihotri@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent 4b5cb3f8
......@@ -100,9 +100,10 @@ static u32 credit_table[31] = {
32768 /* 1E */
};
static void get_map_page(struct qib_qpn_table *qpt, struct qpn_map *map)
static void get_map_page(struct qib_qpn_table *qpt, struct qpn_map *map,
gfp_t gfp)
{
unsigned long page = get_zeroed_page(GFP_KERNEL);
unsigned long page = get_zeroed_page(gfp);
/*
* Free the page if someone raced with us installing it.
......@@ -121,7 +122,7 @@ static void get_map_page(struct qib_qpn_table *qpt, struct qpn_map *map)
* zero/one for QP type IB_QPT_SMI/IB_QPT_GSI.
*/
static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt,
enum ib_qp_type type, u8 port)
enum ib_qp_type type, u8 port, gfp_t gfp)
{
u32 i, offset, max_scan, qpn;
struct qpn_map *map;
......@@ -151,7 +152,7 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt,
max_scan = qpt->nmaps - !offset;
for (i = 0;;) {
if (unlikely(!map->page)) {
get_map_page(qpt, map);
get_map_page(qpt, map, gfp);
if (unlikely(!map->page))
break;
}
......@@ -983,13 +984,21 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
size_t sz;
size_t sg_list_sz;
struct ib_qp *ret;
gfp_t gfp;
if (init_attr->cap.max_send_sge > ib_qib_max_sges ||
init_attr->cap.max_send_wr > ib_qib_max_qp_wrs ||
init_attr->create_flags) {
ret = ERR_PTR(-EINVAL);
goto bail;
}
init_attr->create_flags & ~(IB_QP_CREATE_USE_GFP_NOIO))
return ERR_PTR(-EINVAL);
/* GFP_NOIO is applicable in RC QPs only */
if (init_attr->create_flags & IB_QP_CREATE_USE_GFP_NOIO &&
init_attr->qp_type != IB_QPT_RC)
return ERR_PTR(-EINVAL);
gfp = init_attr->create_flags & IB_QP_CREATE_USE_GFP_NOIO ?
GFP_NOIO : GFP_KERNEL;
/* Check receive queue parameters if no SRQ is specified. */
if (!init_attr->srq) {
......@@ -1021,7 +1030,8 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
sz = sizeof(struct qib_sge) *
init_attr->cap.max_send_sge +
sizeof(struct qib_swqe);
swq = vmalloc((init_attr->cap.max_send_wr + 1) * sz);
swq = __vmalloc((init_attr->cap.max_send_wr + 1) * sz,
gfp, PAGE_KERNEL);
if (swq == NULL) {
ret = ERR_PTR(-ENOMEM);
goto bail;
......@@ -1037,13 +1047,13 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
} else if (init_attr->cap.max_recv_sge > 1)
sg_list_sz = sizeof(*qp->r_sg_list) *
(init_attr->cap.max_recv_sge - 1);
qp = kzalloc(sz + sg_list_sz, GFP_KERNEL);
qp = kzalloc(sz + sg_list_sz, gfp);
if (!qp) {
ret = ERR_PTR(-ENOMEM);
goto bail_swq;
}
RCU_INIT_POINTER(qp->next, NULL);
qp->s_hdr = kzalloc(sizeof(*qp->s_hdr), GFP_KERNEL);
qp->s_hdr = kzalloc(sizeof(*qp->s_hdr), gfp);
if (!qp->s_hdr) {
ret = ERR_PTR(-ENOMEM);
goto bail_qp;
......@@ -1058,8 +1068,16 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
qp->r_rq.max_sge = init_attr->cap.max_recv_sge;
sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) +
sizeof(struct qib_rwqe);
qp->r_rq.wq = vmalloc_user(sizeof(struct qib_rwq) +
qp->r_rq.size * sz);
if (gfp != GFP_NOIO)
qp->r_rq.wq = vmalloc_user(
sizeof(struct qib_rwq) +
qp->r_rq.size * sz);
else
qp->r_rq.wq = __vmalloc(
sizeof(struct qib_rwq) +
qp->r_rq.size * sz,
gfp, PAGE_KERNEL);
if (!qp->r_rq.wq) {
ret = ERR_PTR(-ENOMEM);
goto bail_qp;
......@@ -1090,7 +1108,7 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
dev = to_idev(ibpd->device);
dd = dd_from_dev(dev);
err = alloc_qpn(dd, &dev->qpn_table, init_attr->qp_type,
init_attr->port_num);
init_attr->port_num, gfp);
if (err < 0) {
ret = ERR_PTR(err);
vfree(qp->r_rq.wq);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment