diff options
author | Or Gerlitz <ogerlitz@mellanox.com> | 2014-05-11 08:15:11 -0400 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2014-06-02 17:58:11 -0400 |
commit | 09b93088d75009807b72293f26e2634430ce5ba9 (patch) | |
tree | 78337f035d708879589063e779c5fa3a42183c2e /drivers/infiniband | |
parent | 60093dc0c8b6407bc7494cbcb3e84322cc6782c8 (diff) |
IB: Add a QP creation flag to use GFP_NOIO allocations
This addresses a problem where NFS client writes over IPoIB connected
mode may deadlock on memory allocation/writeback.
The problem is not directly memory reclamation. There is an indirect
dependency between network filesystems writing back pages and
ipoib_cm_tx_init() due to how a kworker is used. Page reclaim cannot
make forward progress until ipoib_cm_tx_init() succeeds and it is
stuck in page reclaim itself waiting for network transmission.
Ordinarily this situation may be avoided by having the caller use
GFP_NOFS but ipoib_cm_tx_init() does not have that information.
To address this, take a general approach and add a new QP creation
flag that tells the low-level hardware driver to use GFP_NOIO for the
memory allocations related to the new QP.
Use the new flag in the ipoib connected mode path, and if the driver
doesn't support it, re-issue the QP creation without the flag.
Signed-off-by: Mel Gorman <mgorman@suse.de>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_cm.c | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 1377f85911c2..933efcea0d03 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c | |||
@@ -1030,10 +1030,20 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_ | |||
1030 | .cap.max_send_sge = 1, | 1030 | .cap.max_send_sge = 1, |
1031 | .sq_sig_type = IB_SIGNAL_ALL_WR, | 1031 | .sq_sig_type = IB_SIGNAL_ALL_WR, |
1032 | .qp_type = IB_QPT_RC, | 1032 | .qp_type = IB_QPT_RC, |
1033 | .qp_context = tx | 1033 | .qp_context = tx, |
1034 | .create_flags = IB_QP_CREATE_USE_GFP_NOIO | ||
1034 | }; | 1035 | }; |
1035 | 1036 | ||
1036 | return ib_create_qp(priv->pd, &attr); | 1037 | struct ib_qp *tx_qp; |
1038 | |||
1039 | tx_qp = ib_create_qp(priv->pd, &attr); | ||
1040 | if (PTR_ERR(tx_qp) == -EINVAL) { | ||
1041 | ipoib_warn(priv, "can't use GFP_NOIO for QPs on device %s, using GFP_KERNEL\n", | ||
1042 | priv->ca->name); | ||
1043 | attr.create_flags &= ~IB_QP_CREATE_USE_GFP_NOIO; | ||
1044 | tx_qp = ib_create_qp(priv->pd, &attr); | ||
1045 | } | ||
1046 | return tx_qp; | ||
1037 | } | 1047 | } |
1038 | 1048 | ||
1039 | static int ipoib_cm_send_req(struct net_device *dev, | 1049 | static int ipoib_cm_send_req(struct net_device *dev, |
@@ -1104,12 +1114,14 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn, | |||
1104 | struct ipoib_dev_priv *priv = netdev_priv(p->dev); | 1114 | struct ipoib_dev_priv *priv = netdev_priv(p->dev); |
1105 | int ret; | 1115 | int ret; |
1106 | 1116 | ||
1107 | p->tx_ring = vzalloc(ipoib_sendq_size * sizeof *p->tx_ring); | 1117 | p->tx_ring = __vmalloc(ipoib_sendq_size * sizeof *p->tx_ring, |
1118 | GFP_NOIO, PAGE_KERNEL); | ||
1108 | if (!p->tx_ring) { | 1119 | if (!p->tx_ring) { |
1109 | ipoib_warn(priv, "failed to allocate tx ring\n"); | 1120 | ipoib_warn(priv, "failed to allocate tx ring\n"); |
1110 | ret = -ENOMEM; | 1121 | ret = -ENOMEM; |
1111 | goto err_tx; | 1122 | goto err_tx; |
1112 | } | 1123 | } |
1124 | memset(p->tx_ring, 0, ipoib_sendq_size * sizeof *p->tx_ring); | ||
1113 | 1125 | ||
1114 | p->qp = ipoib_cm_create_tx_qp(p->dev, p); | 1126 | p->qp = ipoib_cm_create_tx_qp(p->dev, p); |
1115 | if (IS_ERR(p->qp)) { | 1127 | if (IS_ERR(p->qp)) { |