History

RDMA/mlx5: Use SRCU properly in ODP prefetch

When working with SRCU protected xarrays the xarray itself should be the SRCU 'update' point. Instead prefetch is using live as the SRCU update point and this prevents switching the locking design to use the xarray instead. To solve this the prefetch must only read from the xarray once, and hold on to the actual MR pointer for the duration of the async operation. Incrementing num_pending_prefetch delays destruction of the MR, so it is suitable. Prefetch calls directly to the pagefault_mr using the MR pointer and only does a single xarray lookup. All the testing if a MR is prefetchable or not is now done only in the prefetch code and removed from the pagefault critical path.

Jason Gunthorpe committed 7 years ago

Commit fb985e21 parent d6d5df11 file · +121 −141Browse files

Unified · Split

drivers/infiniband/hw/mlx5/odp.c+121−141
@@ -606,16 +606,13 @@ void mlx5_ib_free_implicit_mr(struct mlx5_ib_mr *imr) · 605 unmodified lines
606606 wait_event(imr->q_leaf_free, !atomic_read(&imr->num_leaf_free));
607607 }
608608
609−#define MLX5_PF_FLAGS_PREFETCH BIT(0)
610609 #define MLX5_PF_FLAGS_DOWNGRADE BIT(1)
611−static int pagefault_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr,
612− u64 io_virt, size_t bcnt, u32 *bytes_mapped,
613− u32 flags)
610+static int pagefault_mr(struct mlx5_ib_mr *mr, u64 io_virt, size_t bcnt,
611+ u32 *bytes_mapped, u32 flags)
614612 {
615613 int npages = 0, current_seq, page_shift, ret, np;
616614 struct ib_umem_odp *odp_mr = to_ib_umem_odp(mr->umem);
617615 bool downgrade = flags & MLX5_PF_FLAGS_DOWNGRADE;
618− bool prefetch = flags & MLX5_PF_FLAGS_PREFETCH;
619616 u64 access_mask;
620617 u64 start_idx, page_mask;
621618 struct ib_umem_odp *odp;
@@ -639,14 +636,6 @@ next_mr: · 17 unmodified lines
639636 start_idx = (io_virt - (mr->mmkey.iova & page_mask)) >> page_shift;
640637 access_mask = ODP_READ_ALLOWED_BIT;
641638
642− if (prefetch && !downgrade && !odp->umem.writable) {
643− /* prefetch with write-access must
644− * be supported by the MR
645− */
646− ret = -EINVAL;
647− goto out;
648− }
649−
650639 if (odp->umem.writable && !downgrade)
651640 access_mask |= ODP_WRITE_ALLOWED_BIT;
652641
@@ -681,7 +670,8 @@ next_mr: · 28 unmodified lines
681670
682671 if (ret < 0) {
683672 if (ret != -EAGAIN)
684− mlx5_ib_err(dev, "Failed to update mkey page tables\n");
673+ mlx5_ib_err(mr->dev,
674+ "Failed to update mkey page tables\n");
685675 goto out;
686676 }
687677
@@ -700,8 +690,10 @@ next_mr: · 12 unmodified lines
700690 io_virt += size;
701691 next = odp_next(odp);
702692 if (unlikely(!next || ib_umem_start(next) != io_virt)) {
703− mlx5_ib_dbg(dev, "next implicit leaf removed at 0x%llx. got %p\n",
704− io_virt, next);
693+ mlx5_ib_dbg(
694+ mr->dev,
695+ "next implicit leaf removed at 0x%llx. got %p\n",
696+ io_virt, next);
705697 return -EAGAIN;
706698 }
707699 odp = next;
@@ -718,7 +710,7 @@ out: · 10 unmodified lines
718710 if (!wait_for_completion_timeout(&odp->notifier_completion,
719711 timeout)) {
720712 mlx5_ib_warn(
721− dev,
713+ mr->dev,
722714 "timeout waiting for mmu notifier. seq %d against %d. notifiers_count=%d\n",
723715 current_seq, odp->notifiers_seq,
724716 odp->notifiers_count);
@@ -775,10 +767,9 @@ static int pagefault_single_data_segment(struct mlx5_ib_dev *dev, · 50 unmodified lines
775767 struct ib_pd *pd, u32 key,
776768 u64 io_virt, size_t bcnt,
777769 u32 *bytes_committed,
778− u32 *bytes_mapped, u32 flags)
770+ u32 *bytes_mapped)
779771 {
780772 int npages = 0, srcu_key, ret, i, outlen, cur_outlen = 0, depth = 0;
781− bool prefetch = flags & MLX5_PF_FLAGS_PREFETCH;
782773 struct pf_frame *head = NULL, *frame;
783774 struct mlx5_core_mkey *mmkey;
784775 struct mlx5_ib_mr *mr;
@@ -800,12 +791,6 @@ next_mr: · 15 unmodified lines
800791 goto srcu_unlock;
801792 }
802793
803− if (prefetch && mmkey->type != MLX5_MKEY_MR) {
804− mlx5_ib_dbg(dev, "prefetch is allowed only for MR\n");
805− ret = -EINVAL;
806− goto srcu_unlock;
807− }
808−
809794 switch (mmkey->type) {
810795 case MLX5_MKEY_MR:
811796 mr = container_of(mmkey, struct mlx5_ib_mr, mmkey);
@@ -815,17 +800,6 @@ next_mr: · 3 unmodified lines
815800 goto srcu_unlock;
816801 }
817802
818− if (prefetch) {
819− if (!is_odp_mr(mr) ||
820− mr->ibmr.pd != pd) {
821− mlx5_ib_dbg(dev, "Invalid prefetch request: %s\n",
822− is_odp_mr(mr) ? "MR is not ODP" :
823− "PD is not of the MR");
824− ret = -EINVAL;
825− goto srcu_unlock;
826− }
827− }
828−
829803 if (!is_odp_mr(mr)) {
830804 mlx5_ib_dbg(dev, "skipping non ODP MR (lkey=0x%06x) in page fault handler.\n",
831805 key);
@@ -835,7 +809,7 @@ next_mr: · 3 unmodified lines
835809 goto srcu_unlock;
836810 }
837811
838− ret = pagefault_mr(dev, mr, io_virt, bcnt, bytes_mapped, flags);
812+ ret = pagefault_mr(mr, io_virt, bcnt, bytes_mapped, 0);
839813 if (ret < 0)
840814 goto srcu_unlock;
841815
@@ -1009,7 +983,7 @@ static int pagefault_data_segments(struct mlx5_ib_dev *dev, · 167 unmodified lines
1009983 ret = pagefault_single_data_segment(dev, NULL, key,
1010984 io_virt, bcnt,
1011985 &pfault->bytes_committed,
1012− bytes_mapped, 0);
986+ bytes_mapped);
1013987 if (ret < 0)
1014988 break;
1015989 npages += ret;
@@ -1292,8 +1266,7 @@ static void mlx5_ib_mr_rdma_pfault_handler(struct mlx5_ib_dev *dev, · 276 unmodified lines
12921266 }
12931267
12941268 ret = pagefault_single_data_segment(dev, NULL, rkey, address, length,
1295− &pfault->bytes_committed, NULL,
1296− 0);
1269+ &pfault->bytes_committed, NULL);
12971270 if (ret == -EAGAIN) {
12981271 /* We're racing with an invalidation, don't prefetch */
12991272 prefetch_activated = 0;
@@ -1320,8 +1293,7 @@ static void mlx5_ib_mr_rdma_pfault_handler(struct mlx5_ib_dev *dev, · 20 unmodified lines
13201293
13211294 ret = pagefault_single_data_segment(dev, NULL, rkey, address,
13221295 prefetch_len,
1323− &bytes_committed, NULL,
1324− 0);
1296+ &bytes_committed, NULL);
13251297 if (ret < 0 && ret != -EAGAIN) {
13261298 mlx5_ib_dbg(dev, "Prefetch failed. ret: %d, QP 0x%x, address: 0x%.16llx, length = 0x%.16x\n",
13271299 ret, pfault->token, address, prefetch_len);
@@ -1624,114 +1596,138 @@ int mlx5_ib_odp_init(void) · 296 unmodified lines
16241596
16251597 struct prefetch_mr_work {
16261598 struct work_struct work;
1627− struct ib_pd *pd;
16281599 u32 pf_flags;
16291600 u32 num_sge;
1630− struct ib_sge sg_list[0];
1601+ struct {
1602+ u64 io_virt;
1603+ struct mlx5_ib_mr *mr;
1604+ size_t length;
1605+ } frags[];
16311606 };
16321607
1633−static void num_pending_prefetch_dec(struct mlx5_ib_dev *dev,
1634− struct ib_sge *sg_list, u32 num_sge,
1635− u32 from)
1608+static void destroy_prefetch_work(struct prefetch_mr_work *work)
16361609 {
16371610 u32 i;
1638− int srcu_key;
1639−
1640− srcu_key = srcu_read_lock(&dev->mr_srcu);
16411611
1642− for (i = from; i < num_sge; ++i) {
1643− struct mlx5_core_mkey *mmkey;
1644− struct mlx5_ib_mr *mr;
1645−
1646− mmkey = xa_load(&dev->mdev->priv.mkey_table,
1647− mlx5_base_mkey(sg_list[i].lkey));
1648− mr = container_of(mmkey, struct mlx5_ib_mr, mmkey);
1649− atomic_dec(&mr->num_pending_prefetch);
1650− }
1651−
1652− srcu_read_unlock(&dev->mr_srcu, srcu_key);
1612+ for (i = 0; i < work->num_sge; ++i)
1613+ atomic_dec(&work->frags[i].mr->num_pending_prefetch);
1614+ kvfree(work);
16531615 }
16541616
1655−static bool num_pending_prefetch_inc(struct ib_pd *pd,
1656− struct ib_sge *sg_list, u32 num_sge)
1617+static struct mlx5_ib_mr *
1618+get_prefetchable_mr(struct ib_pd *pd, enum ib_uverbs_advise_mr_advice advice,
1619+ u32 lkey)
16571620 {
16581621 struct mlx5_ib_dev *dev = to_mdev(pd->device);
1659− bool ret = true;
1660− u32 i;
1622+ struct mlx5_core_mkey *mmkey;
1623+ struct ib_umem_odp *odp;
1624+ struct mlx5_ib_mr *mr;
16611625
1662− for (i = 0; i < num_sge; ++i) {
1663− struct mlx5_core_mkey *mmkey;
1664− struct mlx5_ib_mr *mr;
1626+ lockdep_assert_held(&dev->mr_srcu);
16651627
1666− mmkey = xa_load(&dev->mdev->priv.mkey_table,
1667− mlx5_base_mkey(sg_list[i].lkey));
1668− if (!mmkey || mmkey->key != sg_list[i].lkey) {
1669− ret = false;
1670− break;
1671− }
1628+ mmkey = xa_load(&dev->mdev->priv.mkey_table, mlx5_base_mkey(lkey));
1629+ if (!mmkey || mmkey->key != lkey || mmkey->type != MLX5_MKEY_MR)
1630+ return NULL;
16721631
1673− if (mmkey->type != MLX5_MKEY_MR) {
1674− ret = false;
1675− break;
1676− }
1632+ mr = container_of(mmkey, struct mlx5_ib_mr, mmkey);
16771633
1678− mr = container_of(mmkey, struct mlx5_ib_mr, mmkey);
1634+ if (!smp_load_acquire(&mr->live))
1635+ return NULL;
16791636
1680− if (!smp_load_acquire(&mr->live)) {
1681− ret = false;
1682− break;
1683− }
1637+ if (mr->ibmr.pd != pd || !is_odp_mr(mr))
1638+ return NULL;
16841639
1685− if (mr->ibmr.pd != pd) {
1686− ret = false;
1687− break;
1688− }
1640+ /*
1641+ * Implicit child MRs are internal and userspace should not refer to
1642+ * them.
1643+ */
1644+ if (mr->parent)
1645+ return NULL;
16891646
1690− atomic_inc(&mr->num_pending_prefetch);
1691− }
1647+ odp = to_ib_umem_odp(mr->umem);
16921648
1693− if (!ret)
1694− num_pending_prefetch_dec(dev, sg_list, i, 0);
1649+ /* prefetch with write-access must be supported by the MR */
1650+ if (advice == IB_UVERBS_ADVISE_MR_ADVICE_PREFETCH_WRITE &&
1651+ !odp->umem.writable)
1652+ return NULL;
16951653
1696− return ret;
1654+ return mr;
16971655 }
16981656
1699−static int mlx5_ib_prefetch_sg_list(struct ib_pd *pd, u32 pf_flags,
1700− struct ib_sge *sg_list, u32 num_sge)
1657+static void mlx5_ib_prefetch_mr_work(struct work_struct *w)
17011658 {
1659+ struct prefetch_mr_work *work =
1660+ container_of(w, struct prefetch_mr_work, work);
1661+ u32 bytes_mapped = 0;
17021662 u32 i;
1703− int ret = 0;
1704− struct mlx5_ib_dev *dev = to_mdev(pd->device);
1663+
1664+ for (i = 0; i < work->num_sge; ++i)
1665+ pagefault_mr(work->frags[i].mr, work->frags[i].io_virt,
1666+ work->frags[i].length, &bytes_mapped,
1667+ work->pf_flags);
1668+
1669+ destroy_prefetch_work(work);
1670+}
1671+
1672+static bool init_prefetch_work(struct ib_pd *pd,
1673+ enum ib_uverbs_advise_mr_advice advice,
1674+ u32 pf_flags, struct prefetch_mr_work *work,
1675+ struct ib_sge *sg_list, u32 num_sge)
1676+{
1677+ u32 i;
1678+
1679+ INIT_WORK(&work->work, mlx5_ib_prefetch_mr_work);
1680+ work->pf_flags = pf_flags;
17051681
17061682 for (i = 0; i < num_sge; ++i) {
1707− struct ib_sge *sg = &sg_list[i];
1708− int bytes_committed = 0;
1683+ work->frags[i].io_virt = sg_list[i].addr;
1684+ work->frags[i].length = sg_list[i].length;
1685+ work->frags[i].mr =
1686+ get_prefetchable_mr(pd, advice, sg_list[i].lkey);
1687+ if (!work->frags[i].mr) {
1688+ work->num_sge = i - 1;
1689+ if (i)
1690+ destroy_prefetch_work(work);
1691+ return false;
1692+ }
17091693
1710− ret = pagefault_single_data_segment(dev, pd, sg->lkey, sg->addr,
1711− sg->length,
1712− &bytes_committed, NULL,
1713− pf_flags);
1714− if (ret < 0)
1715− break;
1694+ /* Keep the MR pointer will valid outside the SRCU */
1695+ atomic_inc(&work->frags[i].mr->num_pending_prefetch);
17161696 }
1717−
1718− return ret < 0 ? ret : 0;
1697+ work->num_sge = num_sge;
1698+ return true;
17191699 }
17201700
1721−static void mlx5_ib_prefetch_mr_work(struct work_struct *work)
1701+static int mlx5_ib_prefetch_sg_list(struct ib_pd *pd,
1702+ enum ib_uverbs_advise_mr_advice advice,
1703+ u32 pf_flags, struct ib_sge *sg_list,
1704+ u32 num_sge)
17221705 {
1723− struct prefetch_mr_work *w =
1724− container_of(work, struct prefetch_mr_work, work);
1706+ struct mlx5_ib_dev *dev = to_mdev(pd->device);
1707+ u32 bytes_mapped = 0;
1708+ int srcu_key;
1709+ int ret = 0;
1710+ u32 i;
17251711
1726− if (ib_device_try_get(w->pd->device)) {
1727− mlx5_ib_prefetch_sg_list(w->pd, w->pf_flags, w->sg_list,
1728− w->num_sge);
1729− ib_device_put(w->pd->device);
1712+ srcu_key = srcu_read_lock(&dev->mr_srcu);
1713+ for (i = 0; i < num_sge; ++i) {
1714+ struct mlx5_ib_mr *mr;
1715+
1716+ mr = get_prefetchable_mr(pd, advice, sg_list[i].lkey);
1717+ if (!mr) {
1718+ ret = -ENOENT;
1719+ goto out;
1720+ }
1721+ ret = pagefault_mr(mr, sg_list[i].addr, sg_list[i].length,
1722+ &bytes_mapped, pf_flags);
1723+ if (ret < 0)
1724+ goto out;
17301725 }
1726+ ret = 0;
17311727
1732− num_pending_prefetch_dec(to_mdev(w->pd->device), w->sg_list,
1733− w->num_sge, 0);
1734− kvfree(w);
1728+out:
1729+ srcu_read_unlock(&dev->mr_srcu, srcu_key);
1730+ return ret;
17351731 }
17361732
17371733 int mlx5_ib_advise_mr_prefetch(struct ib_pd *pd,
@@ -1739,43 +1735,27 @@ int mlx5_ib_advise_mr_prefetch(struct ib_pd *pd, · 1 unmodified line
17391735 u32 flags, struct ib_sge *sg_list, u32 num_sge)
17401736 {
17411737 struct mlx5_ib_dev *dev = to_mdev(pd->device);
1742− u32 pf_flags = MLX5_PF_FLAGS_PREFETCH;
1738+ u32 pf_flags = 0;
17431739 struct prefetch_mr_work *work;
1744− bool valid_req;
17451740 int srcu_key;
17461741
17471742 if (advice == IB_UVERBS_ADVISE_MR_ADVICE_PREFETCH)
17481743 pf_flags |= MLX5_PF_FLAGS_DOWNGRADE;
17491744
17501745 if (flags & IB_UVERBS_ADVISE_MR_FLAG_FLUSH)
1751− return mlx5_ib_prefetch_sg_list(pd, pf_flags, sg_list,
1746+ return mlx5_ib_prefetch_sg_list(pd, advice, pf_flags, sg_list,
17521747 num_sge);
17531748
1754− work = kvzalloc(struct_size(work, sg_list, num_sge), GFP_KERNEL);
1749+ work = kvzalloc(struct_size(work, frags, num_sge), GFP_KERNEL);
17551750 if (!work)
17561751 return -ENOMEM;
17571752
1758− memcpy(work->sg_list, sg_list, num_sge * sizeof(struct ib_sge));
1759−
1760− /* It is guaranteed that the pd when work is executed is the pd when
1761− * work was queued since pd can't be destroyed while it holds MRs and
1762− * destroying a MR leads to flushing the workquque
1763− */
1764− work->pd = pd;
1765− work->pf_flags = pf_flags;
1766− work->num_sge = num_sge;
1767−
1768− INIT_WORK(&work->work, mlx5_ib_prefetch_mr_work);
1769−
17701753 srcu_key = srcu_read_lock(&dev->mr_srcu);
1771−
1772− valid_req = num_pending_prefetch_inc(pd, sg_list, num_sge);
1773− if (valid_req)
1774− queue_work(system_unbound_wq, &work->work);
1775− else
1776− kvfree(work);
1777−
1754+ if (!init_prefetch_work(pd, advice, pf_flags, work, sg_list, num_sge)) {
1755+ srcu_read_unlock(&dev->mr_srcu, srcu_key);
1756+ return -EINVAL;
1757+ }
1758+ queue_work(system_unbound_wq, &work->work);
17781759 srcu_read_unlock(&dev->mr_srcu, srcu_key);
1779−
1780− return valid_req ? 0 : -EINVAL;
1760+ return 0;
17811761 }

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t