Commit 34d7d523 authored by Vinit Agnihotri's avatar Vinit Agnihotri Committed by Sasha Levin

IB/qib: Support creating qps with GFP_NOIO flag

[ Upstream commit fbbeb863 ]

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.

Cc: <stable@vger.kernel.org> # 3.16+
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 avatarSasha Levin <sasha.levin@oracle.com>
parent dfaff0ef
...@@ -100,9 +100,10 @@ static u32 credit_table[31] = { ...@@ -100,9 +100,10 @@ static u32 credit_table[31] = {
32768 /* 1E */ 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. * 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) ...@@ -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. * zero/one for QP type IB_QPT_SMI/IB_QPT_GSI.
*/ */
static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt, 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; u32 i, offset, max_scan, qpn;
struct qpn_map *map; struct qpn_map *map;
...@@ -151,7 +152,7 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt, ...@@ -151,7 +152,7 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt,
max_scan = qpt->nmaps - !offset; max_scan = qpt->nmaps - !offset;
for (i = 0;;) { for (i = 0;;) {
if (unlikely(!map->page)) { if (unlikely(!map->page)) {
get_map_page(qpt, map); get_map_page(qpt, map, gfp);
if (unlikely(!map->page)) if (unlikely(!map->page))
break; break;
} }
...@@ -983,13 +984,21 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd, ...@@ -983,13 +984,21 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
size_t sz; size_t sz;
size_t sg_list_sz; size_t sg_list_sz;
struct ib_qp *ret; struct ib_qp *ret;
gfp_t gfp;
if (init_attr->cap.max_send_sge > ib_qib_max_sges || if (init_attr->cap.max_send_sge > ib_qib_max_sges ||
init_attr->cap.max_send_wr > ib_qib_max_qp_wrs || init_attr->cap.max_send_wr > ib_qib_max_qp_wrs ||
init_attr->create_flags) { init_attr->create_flags & ~(IB_QP_CREATE_USE_GFP_NOIO))
ret = ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
goto bail;
} /* 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. */ /* Check receive queue parameters if no SRQ is specified. */
if (!init_attr->srq) { if (!init_attr->srq) {
...@@ -1021,7 +1030,8 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd, ...@@ -1021,7 +1030,8 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
sz = sizeof(struct qib_sge) * sz = sizeof(struct qib_sge) *
init_attr->cap.max_send_sge + init_attr->cap.max_send_sge +
sizeof(struct qib_swqe); 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) { if (swq == NULL) {
ret = ERR_PTR(-ENOMEM); ret = ERR_PTR(-ENOMEM);
goto bail; goto bail;
...@@ -1037,13 +1047,13 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd, ...@@ -1037,13 +1047,13 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
} else if (init_attr->cap.max_recv_sge > 1) } else if (init_attr->cap.max_recv_sge > 1)
sg_list_sz = sizeof(*qp->r_sg_list) * sg_list_sz = sizeof(*qp->r_sg_list) *
(init_attr->cap.max_recv_sge - 1); (init_attr->cap.max_recv_sge - 1);
qp = kzalloc(sz + sg_list_sz, GFP_KERNEL); qp = kzalloc(sz + sg_list_sz, gfp);
if (!qp) { if (!qp) {
ret = ERR_PTR(-ENOMEM); ret = ERR_PTR(-ENOMEM);
goto bail_swq; goto bail_swq;
} }
RCU_INIT_POINTER(qp->next, NULL); 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) { if (!qp->s_hdr) {
ret = ERR_PTR(-ENOMEM); ret = ERR_PTR(-ENOMEM);
goto bail_qp; goto bail_qp;
...@@ -1058,8 +1068,16 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd, ...@@ -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; qp->r_rq.max_sge = init_attr->cap.max_recv_sge;
sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) + sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) +
sizeof(struct qib_rwqe); sizeof(struct qib_rwqe);
qp->r_rq.wq = vmalloc_user(sizeof(struct qib_rwq) + if (gfp != GFP_NOIO)
qp->r_rq.size * sz); 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) { if (!qp->r_rq.wq) {
ret = ERR_PTR(-ENOMEM); ret = ERR_PTR(-ENOMEM);
goto bail_qp; goto bail_qp;
...@@ -1090,7 +1108,7 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd, ...@@ -1090,7 +1108,7 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd,
dev = to_idev(ibpd->device); dev = to_idev(ibpd->device);
dd = dd_from_dev(dev); dd = dd_from_dev(dev);
err = alloc_qpn(dd, &dev->qpn_table, init_attr->qp_type, err = alloc_qpn(dd, &dev->qpn_table, init_attr->qp_type,
init_attr->port_num); init_attr->port_num, gfp);
if (err < 0) { if (err < 0) {
ret = ERR_PTR(err); ret = ERR_PTR(err);
vfree(qp->r_rq.wq); 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