Commit 0e64e5b3 authored by Jason Gunthorpe's avatar Jason Gunthorpe
Browse files

Merge branch 'odp_rework' into hmm.git

This branch is shared with the rdma.git for dependencies in following
patches:

====================
In order to hoist the interval tree code out of the drivers and into the
mmu_notifiers it is necessary for the drivers to not use the interval tree
for other things.

This series replaces the interval tree with an xarray and along the way
re-aligns all the locking to use a sensible SRCU model where the 'update'
step is done by modifying an xarray.

The result is overall much simpler and with less locking in the critical
path. Many functions were reworked for clarity and small details like
using 'imr' to refer to the implicit MR make the entire code flow here
more readable.

This also squashes at least two race bugs on its own, and quite possibily
more that haven't been identified.
====================

* branch 'odp_rework':
  RDMA/odp: Remove broken debugging call to invalidate_range
  RDMA/mlx5: Do not race with mlx5_ib_invalidate_range during create and destroy
  RDMA/mlx5: Do not store implicit children in the odp_mkeys xarray
  RDMA/mlx5: Rework implicit ODP destroy
  RDMA/mlx5: Avoid double lookups on the pagefault path
  RDMA/mlx5: Reduce locking in implicit_mr_get_data()
  RDMA/mlx5: Use an xarray for the children of an implicit ODP
  RDMA/mlx5: Split implicit handling from pagefault_mr
  RDMA/mlx5: Set the HW IOVA of the child MRs to their place in the tree
  RDMA/mlx5: Lift implicit_mr_alloc() into the two routines that call it
  RDMA/mlx5: Rework implicit_mr_get_data
  RDMA/mlx5: Delete struct mlx5_priv->mkey_table
  RDMA/mlx5: Use a dedicated mkey xarray for ODP
  RDMA/mlx5: Split sig_err MR data into its own xarray
  RDMA/mlx5: Use SRCU properly in ODP prefetch
parents ac541f25 46870b23
Loading
Loading
Loading
Loading
+19 −19
Original line number Diff line number Diff line
@@ -508,7 +508,6 @@ static int ib_umem_odp_map_dma_single_page(
{
	struct ib_device *dev = umem_odp->umem.ibdev;
	dma_addr_t dma_addr;
	int remove_existing_mapping = 0;
	int ret = 0;

	/*
@@ -534,28 +533,29 @@ static int ib_umem_odp_map_dma_single_page(
	} else if (umem_odp->page_list[page_index] == page) {
		umem_odp->dma_list[page_index] |= access_mask;
	} else {
		pr_err("error: got different pages in IB device and from get_user_pages. IB device page: %p, gup page: %p\n",
		/*
		 * This is a race here where we could have done:
		 *
		 *         CPU0                             CPU1
		 *   get_user_pages()
		 *                                       invalidate()
		 *                                       page_fault()
		 *   mutex_lock(umem_mutex)
		 *    page from GUP != page in ODP
		 *
		 * It should be prevented by the retry test above as reading
		 * the seq number should be reliable under the
		 * umem_mutex. Thus something is really not working right if
		 * things get here.
		 */
		WARN(true,
		     "Got different pages in IB device and from get_user_pages. IB device page: %p, gup page: %p\n",
		     umem_odp->page_list[page_index], page);
		/* Better remove the mapping now, to prevent any further
		 * damage. */
		remove_existing_mapping = 1;
		ret = -EAGAIN;
	}

out:
	put_user_page(page);

	if (remove_existing_mapping) {
		ib_umem_notifier_start_account(umem_odp);
		dev->ops.invalidate_range(
			umem_odp,
			ib_umem_start(umem_odp) +
				(page_index << umem_odp->page_shift),
			ib_umem_start(umem_odp) +
				((page_index + 1) << umem_odp->page_shift));
		ib_umem_notifier_end_account(umem_odp);
		ret = -EAGAIN;
	}

	return ret;
}

+16 −17
Original line number Diff line number Diff line
@@ -423,9 +423,6 @@ static int mlx5_poll_one(struct mlx5_ib_cq *cq,
	struct mlx5_cqe64 *cqe64;
	struct mlx5_core_qp *mqp;
	struct mlx5_ib_wq *wq;
	struct mlx5_sig_err_cqe *sig_err_cqe;
	struct mlx5_core_mkey *mmkey;
	struct mlx5_ib_mr *mr;
	uint8_t opcode;
	uint32_t qpn;
	u16 wqe_ctr;
@@ -519,27 +516,29 @@ repoll:
			}
		}
		break;
	case MLX5_CQE_SIG_ERR:
		sig_err_cqe = (struct mlx5_sig_err_cqe *)cqe64;
	case MLX5_CQE_SIG_ERR: {
		struct mlx5_sig_err_cqe *sig_err_cqe =
			(struct mlx5_sig_err_cqe *)cqe64;
		struct mlx5_core_sig_ctx *sig;

		xa_lock(&dev->mdev->priv.mkey_table);
		mmkey = xa_load(&dev->mdev->priv.mkey_table,
		xa_lock(&dev->sig_mrs);
		sig = xa_load(&dev->sig_mrs,
				mlx5_base_mkey(be32_to_cpu(sig_err_cqe->mkey)));
		mr = to_mibmr(mmkey);
		get_sig_err_item(sig_err_cqe, &mr->sig->err_item);
		mr->sig->sig_err_exists = true;
		mr->sig->sigerr_count++;
		get_sig_err_item(sig_err_cqe, &sig->err_item);
		sig->sig_err_exists = true;
		sig->sigerr_count++;

		mlx5_ib_warn(dev, "CQN: 0x%x Got SIGERR on key: 0x%x err_type %x err_offset %llx expected %x actual %x\n",
			     cq->mcq.cqn, mr->sig->err_item.key,
			     mr->sig->err_item.err_type,
			     mr->sig->err_item.sig_err_offset,
			     mr->sig->err_item.expected,
			     mr->sig->err_item.actual);
			     cq->mcq.cqn, sig->err_item.key,
			     sig->err_item.err_type,
			     sig->err_item.sig_err_offset,
			     sig->err_item.expected,
			     sig->err_item.actual);

		xa_unlock(&dev->mdev->priv.mkey_table);
		xa_unlock(&dev->sig_mrs);
		goto repoll;
	}
	}

	return 0;
}
+4 −4
Original line number Diff line number Diff line
@@ -1265,8 +1265,8 @@ static int devx_handle_mkey_indirect(struct devx_obj *obj,
	mkey->pd = MLX5_GET(mkc, mkc, pd);
	devx_mr->ndescs = MLX5_GET(mkc, mkc, translations_octword_size);

	return xa_err(xa_store(&dev->mdev->priv.mkey_table,
			       mlx5_base_mkey(mkey->key), mkey, GFP_KERNEL));
	return xa_err(xa_store(&dev->odp_mkeys, mlx5_base_mkey(mkey->key), mkey,
			       GFP_KERNEL));
}

static int devx_handle_mkey_create(struct mlx5_ib_dev *dev,
@@ -1345,9 +1345,9 @@ static int devx_obj_cleanup(struct ib_uobject *uobject,
		 * the mmkey, we must wait for that to stop before freeing the
		 * mkey, as another allocation could get the same mkey #.
		 */
		xa_erase(&obj->ib_dev->mdev->priv.mkey_table,
		xa_erase(&obj->ib_dev->odp_mkeys,
			 mlx5_base_mkey(obj->devx_mr.mmkey.key));
		synchronize_srcu(&dev->mr_srcu);
		synchronize_srcu(&dev->odp_srcu);
	}

	if (obj->flags & DEVX_OBJ_FLAGS_DCT)
+8 −9
Original line number Diff line number Diff line
@@ -6145,11 +6145,10 @@ static struct ib_counters *mlx5_ib_create_counters(struct ib_device *device,
static void mlx5_ib_stage_init_cleanup(struct mlx5_ib_dev *dev)
{
	mlx5_ib_cleanup_multiport_master(dev);
	if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) {
		srcu_barrier(&dev->mr_srcu);
		cleanup_srcu_struct(&dev->mr_srcu);
	}
	WARN_ON(!xa_empty(&dev->odp_mkeys));
	cleanup_srcu_struct(&dev->odp_srcu);

	WARN_ON(!xa_empty(&dev->sig_mrs));
	WARN_ON(!bitmap_empty(dev->dm.memic_alloc_pages, MLX5_MAX_MEMIC_PAGES));
}

@@ -6201,15 +6200,15 @@ static int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev)
	mutex_init(&dev->cap_mask_mutex);
	INIT_LIST_HEAD(&dev->qp_list);
	spin_lock_init(&dev->reset_flow_resource_lock);
	xa_init(&dev->odp_mkeys);
	xa_init(&dev->sig_mrs);

	spin_lock_init(&dev->dm.lock);
	dev->dm.dev = mdev;

	if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) {
		err = init_srcu_struct(&dev->mr_srcu);
	err = init_srcu_struct(&dev->odp_srcu);
	if (err)
		goto err_mp;
	}

	return 0;

+17 −5
Original line number Diff line number Diff line
@@ -606,7 +606,6 @@ struct mlx5_ib_mr {
	struct mlx5_ib_dev     *dev;
	u32 out[MLX5_ST_SZ_DW(create_mkey_out)];
	struct mlx5_core_sig_ctx    *sig;
	unsigned int		live;
	void			*descs_alloc;
	int			access_flags; /* Needed for rereg MR */

@@ -618,10 +617,16 @@ struct mlx5_ib_mr {
	u64			data_iova;
	u64			pi_iova;

	atomic_t		num_leaf_free;
	wait_queue_head_t       q_leaf_free;
	/* For ODP and implicit */
	atomic_t		num_deferred_work;
	struct xarray		implicit_children;
	union {
		struct rcu_head rcu;
		struct list_head elm;
		struct work_struct work;
	} odp_destroy;

	struct mlx5_async_work  cb_work;
	atomic_t		num_pending_prefetch;
};

static inline bool is_odp_mr(struct mlx5_ib_mr *mr)
@@ -975,7 +980,9 @@ struct mlx5_ib_dev {
	 * Sleepable RCU that prevents destruction of MRs while they are still
	 * being used by a page fault handler.
	 */
	struct srcu_struct      mr_srcu;
	struct srcu_struct      odp_srcu;
	struct xarray		odp_mkeys;

	u32			null_mkey;
	struct mlx5_ib_flow_db	*flow_db;
	/* protect resources needed as part of reset flow */
@@ -999,6 +1006,8 @@ struct mlx5_ib_dev {
	struct mlx5_srq_table   srq_table;
	struct mlx5_async_ctx   async_ctx;
	struct mlx5_devx_event_table devx_event_table;

	struct xarray sig_mrs;
};

static inline struct mlx5_ib_cq *to_mibcq(struct mlx5_core_cq *mcq)
@@ -1162,6 +1171,7 @@ struct mlx5_ib_mr *mlx5_ib_alloc_implicit_mr(struct mlx5_ib_pd *pd,
					     struct ib_udata *udata,
					     int access_flags);
void mlx5_ib_free_implicit_mr(struct mlx5_ib_mr *mr);
void mlx5_ib_fence_odp_mr(struct mlx5_ib_mr *mr);
int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
			  u64 length, u64 virt_addr, int access_flags,
			  struct ib_pd *pd, struct ib_udata *udata);
@@ -1223,6 +1233,8 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev);

struct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev, int entry);
void mlx5_mr_cache_free(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr);
int mlx5_mr_cache_invalidate(struct mlx5_ib_mr *mr);

int mlx5_ib_check_mr_status(struct ib_mr *ibmr, u32 check_mask,
			    struct ib_mr_status *mr_status);
struct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd,
Loading