diff mbox

[v2,rdma-next,7/9] RDMA/nldev: provide detailed MR information

Message ID 74dfc0aa2480eda16dbd21c513507294ef29f8b3.1519067702.git.swise@opengridcomputing.com (mailing list archive)
State Superseded
Headers show

Commit Message

Steve Wise Feb. 19, 2018, 4:22 p.m. UTC
Implement the RDMA nldev netlink interface for dumping detailed
MR information.

Signed-off-by: Steve Wise <swise@opengridcomputing.com>
---
 drivers/infiniband/core/nldev.c      | 174 +++++++++++++++++++++++++++++++++++
 drivers/infiniband/core/restrack.c   |  36 +++++---
 drivers/infiniband/core/uverbs_cmd.c |   2 +
 drivers/infiniband/core/verbs.c      |   3 +
 include/rdma/ib_verbs.h              |   5 +
 include/rdma/restrack.h              |   4 +
 include/uapi/rdma/rdma_netlink.h     |  10 ++
 7 files changed, 221 insertions(+), 13 deletions(-)

Comments

Jason Gunthorpe Feb. 19, 2018, 11:02 p.m. UTC | #1
On Mon, Feb 19, 2018 at 08:22:11AM -0800, Steve Wise wrote:

> +	RDMA_NLDEV_ATTR_RES_MR,			/* nested table */
> +	RDMA_NLDEV_ATTR_RES_MR_ENTRY,		/* nested table */
> +	RDMA_NLDEV_ATTR_RES_RKEY,		/* u32 */
> +	RDMA_NLDEV_ATTR_RES_LKEY,		/* u32 */

What about stag?

Wondering if keys should not be disclosed for security?

> +	RDMA_NLDEV_ATTR_RES_IOVA,		/* u64 */

What is this supposed to be ?

We are talking about some MRs now with very complicated layouts, and
support those in the kernel too.

We already can't leak a kernel pointer here.. Not sure we should even
talk about pointers here at all..

> +	RDMA_NLDEV_ATTR_RES_MRLEN,		/* u64 */
> +	RDMA_NLDEV_ATTR_RES_PGSIZE,		/* u32 */

Why pgsize?

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Steve Wise Feb. 19, 2018, 11:17 p.m. UTC | #2
> -----Original Message-----
> From: Jason Gunthorpe [mailto:jgg@ziepe.ca]
> Sent: Monday, February 19, 2018 5:03 PM
> To: Steve Wise
> Cc: dledford@redhat.com; leon@kernel.org; yishaih@mellanox.com; linux-
> rdma@vger.kernel.org
> Subject: Re: [PATCH v2 rdma-next 7/9] RDMA/nldev: provide detailed MR
> information
> 
> On Mon, Feb 19, 2018 at 08:22:11AM -0800, Steve Wise wrote:
> 
> > +	RDMA_NLDEV_ATTR_RES_MR,			/* nested table */
> > +	RDMA_NLDEV_ATTR_RES_MR_ENTRY,		/* nested table */
> > +	RDMA_NLDEV_ATTR_RES_RKEY,		/* u32 */
> > +	RDMA_NLDEV_ATTR_RES_LKEY,		/* u32 */
> 
> What about stag?

It's the same thing, really.  And the API to rdma applications uses
rkey/lkey, not stag.

> 
> Wondering if keys should not be disclosed for security?
> 
> > +	RDMA_NLDEV_ATTR_RES_IOVA,		/* u64 */
> 
> What is this supposed to be ?
> 

It is the address or 64b value used in ib_sge.addr field of SGEs.  mr.iova
defines the beginning address of the MR.
 
> We are talking about some MRs now with very complicated layouts, and
> support those in the kernel too.
> 
> We already can't leak a kernel pointer here.. Not sure we should even
> talk about pointers here at all..

It is part of what an application provides to register a MR.  It will help
in debugging an application to verify that the MR registered has the correct
iova. 

> 
> > +	RDMA_NLDEV_ATTR_RES_MRLEN,		/* u64 */
> > +	RDMA_NLDEV_ATTR_RES_PGSIZE,		/* u32 */
> 
> Why pgsize?

Why dump it?  Because the page size of a MR isn't necessarily the host page
size.  

Steve.

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jason Gunthorpe Feb. 19, 2018, 11:36 p.m. UTC | #3
On Mon, Feb 19, 2018 at 05:17:29PM -0600, Steve Wise wrote:

> > Wondering if keys should not be disclosed for security?
> > 
> > > +	RDMA_NLDEV_ATTR_RES_IOVA,		/* u64 */
> > 
> > What is this supposed to be ?
> > 
> 
> It is the address or 64b value used in ib_sge.addr field of SGEs.  mr.iova
> defines the beginning address of the MR.

But kernel MRs can be fragmented, and we will have fragmented user MRs
soon too I think.

> > We are talking about some MRs now with very complicated layouts, and
> > support those in the kernel too.
> > 
> > We already can't leak a kernel pointer here.. Not sure we should even
> > talk about pointers here at all..
> 
> It is part of what an application provides to register a MR.  It will help
> in debugging an application to verify that the MR registered has the correct
> iova. 

Still, worried about security, exposing pointers is frowned on these
days.

Certainly no for any kernel MR.

> > > +	RDMA_NLDEV_ATTR_RES_MRLEN,		/* u64 */
> > > +	RDMA_NLDEV_ATTR_RES_PGSIZE,		/* u32 */
> > 
> > Why pgsize?
> 
> Why dump it?  Because the page size of a MR isn't necessarily the host page
> size.  

But the page size can be variable inside a MR, seems like a weird
thing to report.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Steve Wise Feb. 19, 2018, 11:46 p.m. UTC | #4
> 
> On Mon, Feb 19, 2018 at 05:17:29PM -0600, Steve Wise wrote:
> 
> > > Wondering if keys should not be disclosed for security?
> > >
> > > > +	RDMA_NLDEV_ATTR_RES_IOVA,		/* u64 */
> > >
> > > What is this supposed to be ?
> > >
> >
> > It is the address or 64b value used in ib_sge.addr field of SGEs.
mr.iova
> > defines the beginning address of the MR.
> 
> But kernel MRs can be fragmented, and we will have fragmented user MRs
> soon too I think.

From the perspective of the peer application targeting specific areas in the
MR, it is linear and contiguous, from mr.ivoa to mr.iova+mr.length-1.  The
pages backing that mr are not necessarily contiguous.

> 
> > > We are talking about some MRs now with very complicated layouts, and
> > > support those in the kernel too.
> > >
> > > We already can't leak a kernel pointer here.. Not sure we should even
> > > talk about pointers here at all..
> >
> > It is part of what an application provides to register a MR.  It will
help
> > in debugging an application to verify that the MR registered has the
correct
> > iova.
> 
> Still, worried about security, exposing pointers is frowned on these
> days.
> 

I can remove IOVA, if that is your recommendation.

> Certainly no for any kernel MR.
> 
> > > > +	RDMA_NLDEV_ATTR_RES_MRLEN,		/* u64 */
> > > > +	RDMA_NLDEV_ATTR_RES_PGSIZE,		/* u32 */
> > >
> > > Why pgsize?
> >
> > Why dump it?  Because the page size of a MR isn't necessarily the host
> page
> > size.
> 
> But the page size can be variable inside a MR, seems like a weird
> thing to report.

I don't understand.  Each MR has a page_size that represents the size of
each of the entries in the page list that composes the MR.   Perhaps you're
thinking about some block-list MR or some newer variant that I'm not
familiar with?  All pages in a user MR have the same page size.  Ditto for
REG_MRs, or at least the ones I'm familiar with (cxgb4 supported).

What do you think _should_ be displayed for each MR that is not
provider-specific (we'll address provider-specific stuff in a subsequent
patch series)?  The attribute list I have included is mainly driven off of
each structure in the kernel.  In this case struct ib_mr.

Steve

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Leon Romanovsky Feb. 20, 2018, 5:51 a.m. UTC | #5
On Mon, Feb 19, 2018 at 05:46:43PM -0600, Steve Wise wrote:
> >
> > On Mon, Feb 19, 2018 at 05:17:29PM -0600, Steve Wise wrote:
> >
> > > > Wondering if keys should not be disclosed for security?
> > > >
> > > > > +	RDMA_NLDEV_ATTR_RES_IOVA,		/* u64 */
> > > >
> > > > What is this supposed to be ?
> > > >
> > >
> > > It is the address or 64b value used in ib_sge.addr field of SGEs.
> mr.iova
> > > defines the beginning address of the MR.
> >
> > But kernel MRs can be fragmented, and we will have fragmented user MRs
> > soon too I think.
>
> From the perspective of the peer application targeting specific areas in the
> MR, it is linear and contiguous, from mr.ivoa to mr.iova+mr.length-1.  The
> pages backing that mr are not necessarily contiguous.
>
> >
> > > > We are talking about some MRs now with very complicated layouts, and
> > > > support those in the kernel too.
> > > >
> > > > We already can't leak a kernel pointer here.. Not sure we should even
> > > > talk about pointers here at all..
> > >
> > > It is part of what an application provides to register a MR.  It will
> help
> > > in debugging an application to verify that the MR registered has the
> correct
> > > iova.
> >
> > Still, worried about security, exposing pointers is frowned on these
> > days.
> >
>
> I can remove IOVA, if that is your recommendation.

Or you can require some CAP_ADMIN privilege to return IOVA among other MR fields.

>
> > Certainly no for any kernel MR.
> >
> > > > > +	RDMA_NLDEV_ATTR_RES_MRLEN,		/* u64 */
> > > > > +	RDMA_NLDEV_ATTR_RES_PGSIZE,		/* u32 */
> > > >
> > > > Why pgsize?
> > >
> > > Why dump it?  Because the page size of a MR isn't necessarily the host
> > page
> > > size.
> >
> > But the page size can be variable inside a MR, seems like a weird
> > thing to report.
>
> I don't understand.  Each MR has a page_size that represents the size of
> each of the entries in the page list that composes the MR.   Perhaps you're
> thinking about some block-list MR or some newer variant that I'm not
> familiar with?  All pages in a user MR have the same page size.  Ditto for
> REG_MRs, or at least the ones I'm familiar with (cxgb4 supported).
>
> What do you think _should_ be displayed for each MR that is not
> provider-specific (we'll address provider-specific stuff in a subsequent
> patch series)?  The attribute list I have included is mainly driven off of
> each structure in the kernel.  In this case struct ib_mr.
>
> Steve
>
Steve Wise Feb. 21, 2018, 5:02 p.m. UTC | #6
> 
> On Mon, Feb 19, 2018 at 05:46:43PM -0600, Steve Wise wrote:
> > >
> > > On Mon, Feb 19, 2018 at 05:17:29PM -0600, Steve Wise wrote:
> > >
> > > > > Wondering if keys should not be disclosed for security?
> > > > >
> > > > > > +	RDMA_NLDEV_ATTR_RES_IOVA,		/* u64 */
> > > > >
> > > > > What is this supposed to be ?
> > > > >
> > > >
> > > > It is the address or 64b value used in ib_sge.addr field of SGEs.
> > mr.iova
> > > > defines the beginning address of the MR.
> > >
> > > But kernel MRs can be fragmented, and we will have fragmented user
> MRs
> > > soon too I think.
> >
> > From the perspective of the peer application targeting specific areas in
the
> > MR, it is linear and contiguous, from mr.ivoa to mr.iova+mr.length-1.
The
> > pages backing that mr are not necessarily contiguous.
> >
> > >
> > > > > We are talking about some MRs now with very complicated layouts,
> and
> > > > > support those in the kernel too.
> > > > >
> > > > > We already can't leak a kernel pointer here.. Not sure we should
even
> > > > > talk about pointers here at all..
> > > >
> > > > It is part of what an application provides to register a MR.  It
will
> > help
> > > > in debugging an application to verify that the MR registered has the
> > correct
> > > > iova.
> > >
> > > Still, worried about security, exposing pointers is frowned on these
> > > days.
> > >
> >
> > I can remove IOVA, if that is your recommendation.
> 
> Or you can require some CAP_ADMIN privilege to return IOVA among other
> MR fields.

I like this idea.

Steve. 

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c
index 32eda39..ace272b 100644
--- a/drivers/infiniband/core/nldev.c
+++ b/drivers/infiniband/core/nldev.c
@@ -94,6 +94,13 @@ 
 	[RDMA_NLDEV_ATTR_RES_CQE]		= { .type = NLA_U32 },
 	[RDMA_NLDEV_ATTR_RES_USECNT]		= { .type = NLA_U64 },
 	[RDMA_NLDEV_ATTR_RES_POLL_CTX]		= { .type = NLA_U8 },
+	[RDMA_NLDEV_ATTR_RES_MR]		= { .type = NLA_NESTED },
+	[RDMA_NLDEV_ATTR_RES_MR_ENTRY]		= { .type = NLA_NESTED },
+	[RDMA_NLDEV_ATTR_RES_RKEY]		= { .type = NLA_U32 },
+	[RDMA_NLDEV_ATTR_RES_LKEY]		= { .type = NLA_U32 },
+	[RDMA_NLDEV_ATTR_RES_IOVA]		= { .type = NLA_U64 },
+	[RDMA_NLDEV_ATTR_RES_MRLEN]		= { .type = NLA_U64 },
+	[RDMA_NLDEV_ATTR_RES_PGSIZE]		= { .type = NLA_U32 },
 };
 
 static int fill_nldev_handle(struct sk_buff *msg, struct ib_device *device)
@@ -206,6 +213,7 @@  static int fill_res_info(struct sk_buff *msg, struct ib_device *device)
 		[RDMA_RESTRACK_CQ] = "cq",
 		[RDMA_RESTRACK_QP] = "qp",
 		[RDMA_RESTRACK_CM_ID] = "cm_id",
+		[RDMA_RESTRACK_MR] = "mr",
 	};
 
 	struct rdma_restrack_root *res = &device->res;
@@ -445,6 +453,51 @@  static int fill_res_cq_entry(struct sk_buff *msg,
 	return -EMSGSIZE;
 }
 
+static int fill_res_mr_entry(struct sk_buff *msg,
+			     struct ib_mr *mr)
+{
+	struct rdma_restrack_entry *res = &mr->res;
+	struct nlattr *entry_attr;
+
+	entry_attr = nla_nest_start(msg, RDMA_NLDEV_ATTR_RES_MR_ENTRY);
+	if (!entry_attr)
+		goto out;
+
+	if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_RKEY, mr->rkey))
+		goto err;
+	if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_LKEY, mr->lkey))
+		goto err;
+	if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_RES_IOVA, mr->iova, 0))
+		goto err;
+	if (nla_put_u64_64bit(msg, RDMA_NLDEV_ATTR_RES_MRLEN, mr->length, 0))
+		goto err;
+	if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_PGSIZE, mr->page_size))
+		goto err;
+
+	/*
+	 * Existence of task means that it is user MR and netlink
+	 * user is invited to go and read /proc/PID/comm to get name
+	 * of the task file and res->task_com should be NULL.
+	 */
+	if (rdma_is_kernel_res(res)) {
+		if (nla_put_string(msg, RDMA_NLDEV_ATTR_RES_KERN_NAME,
+				   res->kern_name))
+			goto err;
+	} else {
+		if (nla_put_u32(msg, RDMA_NLDEV_ATTR_RES_PID,
+				task_pid_vnr(res->task)))
+			goto err;
+	}
+
+	nla_nest_end(msg, entry_attr);
+	return 0;
+
+err:
+	nla_nest_cancel(msg, entry_attr);
+out:
+	return -EMSGSIZE;
+}
+
 static int nldev_get_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
 			  struct netlink_ext_ack *extack)
 {
@@ -1099,6 +1152,124 @@  static int nldev_res_get_cq_dumpit(struct sk_buff *skb,
 	return ret;
 }
 
+static int nldev_res_get_mr_dumpit(struct sk_buff *skb,
+				   struct netlink_callback *cb)
+{
+	struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
+	struct rdma_restrack_entry *res;
+	int err, ret = 0, idx = 0;
+	struct nlattr *table_attr;
+	struct ib_device *device;
+	int start = cb->args[0];
+	struct ib_mr *mr = NULL;
+	struct nlmsghdr *nlh;
+	u32 index;
+
+	err = nlmsg_parse(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
+			  nldev_policy, NULL);
+	/*
+	 * Right now, we are expecting the device index to get MR information,
+	 * but it is possible to extend this code to return all devices in
+	 * one shot by checking the existence of RDMA_NLDEV_ATTR_DEV_INDEX.
+	 * if it doesn't exist, we will iterate over all devices.
+	 *
+	 * But it is not needed for now.
+	 */
+	if (err || !tb[RDMA_NLDEV_ATTR_DEV_INDEX])
+		return -EINVAL;
+
+	index = nla_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]);
+	device = ib_device_get_by_index(index);
+	if (!device)
+		return -EINVAL;
+
+	nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
+		RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_RES_MR_GET),
+		0, NLM_F_MULTI);
+
+	if (fill_nldev_handle(skb, device)) {
+		ret = -EMSGSIZE;
+		goto err;
+	}
+
+	table_attr = nla_nest_start(skb, RDMA_NLDEV_ATTR_RES_MR);
+	if (!table_attr) {
+		ret = -EMSGSIZE;
+		goto err;
+	}
+
+	down_read(&device->res.rwsem);
+	hash_for_each_possible(device->res.hash, res, node, RDMA_RESTRACK_MR) {
+		if (idx < start)
+			goto next;
+
+		if ((rdma_is_kernel_res(res) &&
+		     task_active_pid_ns(current) != &init_pid_ns) ||
+		    (!rdma_is_kernel_res(res) &&
+		     task_active_pid_ns(current) !=
+		     task_active_pid_ns(res->task)))
+			/*
+			 * 1. Kernel MRs should be visible in init namspace only
+			 * 2. Present only MRs visible in the current namespace
+			 */
+			goto next;
+
+		if (!rdma_restrack_get(res))
+			/*
+			 * Resource is under release now, but we are not
+			 * relesing lock now, so it will be released in
+			 * our next pass, once we will get ->next pointer.
+			 */
+			goto next;
+
+		mr = container_of(res, struct ib_mr, res);
+
+		up_read(&device->res.rwsem);
+		ret = fill_res_mr_entry(skb, mr);
+		down_read(&device->res.rwsem);
+		/*
+		 * Return resource back, but it won't be released till
+		 * the &device->res.rwsem will be released for write.
+		 */
+		rdma_restrack_put(res);
+
+		if (ret == -EMSGSIZE)
+			/*
+			 * There is a chance to optimize here.
+			 * It can be done by using list_prepare_entry
+			 * and list_for_each_entry_continue afterwards.
+			 */
+			break;
+		if (ret)
+			goto res_err;
+next:		idx++;
+	}
+	up_read(&device->res.rwsem);
+
+	nla_nest_end(skb, table_attr);
+	nlmsg_end(skb, nlh);
+	cb->args[0] = idx;
+
+	/*
+	 * No more MRs to fill, cancel the message and
+	 * return 0 to mark end of dumpit.
+	 */
+	if (!mr)
+		goto err;
+
+	put_device(&device->dev);
+	return skb->len;
+
+res_err:
+	nla_nest_cancel(skb, table_attr);
+	up_read(&device->res.rwsem);
+
+err:
+	nlmsg_cancel(skb, nlh);
+	put_device(&device->dev);
+	return ret;
+}
+
 static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = {
 	[RDMA_NLDEV_CMD_GET] = {
 		.doit = nldev_get_doit,
@@ -1131,6 +1302,9 @@  static int nldev_res_get_cq_dumpit(struct sk_buff *skb,
 	[RDMA_NLDEV_CMD_RES_CQ_GET] = {
 		.dump = nldev_res_get_cq_dumpit,
 	},
+	[RDMA_NLDEV_CMD_RES_MR_GET] = {
+		.dump = nldev_res_get_mr_dumpit,
+	},
 };
 
 void __init nldev_init(void)
diff --git a/drivers/infiniband/core/restrack.c b/drivers/infiniband/core/restrack.c
index a85d8f5..58b05a9 100644
--- a/drivers/infiniband/core/restrack.c
+++ b/drivers/infiniband/core/restrack.c
@@ -43,22 +43,28 @@  int rdma_restrack_count(struct rdma_restrack_root *res,
 
 static void set_kern_name(struct rdma_restrack_entry *res)
 {
-	enum rdma_restrack_type type = res->type;
-	struct ib_qp *qp;
+	struct ib_pd *pd;
 
-	if (type != RDMA_RESTRACK_QP)
-		/* Other types already have this name embedded in */
-		return;
-
-	qp = container_of(res, struct ib_qp, res);
-	if (!qp->pd) {
-		WARN_ONCE(true, "XRC QPs are not supported\n");
-		/* Survive, despite the programmer's error */
-		res->kern_name = " ";
-		return;
+	switch (res->type) {
+	case RDMA_RESTRACK_QP:
+		pd = container_of(res, struct ib_qp, res)->pd;
+		if (!pd) {
+			WARN_ONCE(true, "XRC QPs are not supported\n");
+			/* Survive, despite the programmer's error */
+			res->kern_name = " ";
+		}
+		break;
+	case RDMA_RESTRACK_MR:
+		pd = container_of(res, struct ib_mr, res)->pd;
+		break;
+	default:
+		/* Other types set kern_name directly */
+		pd = NULL;
+		break;
 	}
 
-	res->kern_name = qp->pd->res.kern_name;
+	if (pd)
+		res->kern_name = pd->res.kern_name;
 }
 
 static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
@@ -73,6 +79,8 @@  static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
 	case RDMA_RESTRACK_CM_ID:
 		return container_of(res, struct rdma_id_private,
 				    res)->id.device;
+	case RDMA_RESTRACK_MR:
+		return container_of(res, struct ib_mr, res)->device;
 	default:
 		WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
 		return NULL;
@@ -90,6 +98,8 @@  static bool res_is_user(struct rdma_restrack_entry *res)
 		return container_of(res, struct ib_qp, res)->uobject;
 	case RDMA_RESTRACK_CM_ID:
 		return !container_of(res, struct rdma_id_private, res)->caller;
+	case RDMA_RESTRACK_MR:
+		return container_of(res, struct ib_mr, res)->pd->uobject;
 	default:
 		WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
 		return false;
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 25a0e0e..99f01c4 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -693,6 +693,8 @@  ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
 	mr->pd      = pd;
 	mr->uobject = uobj;
 	atomic_inc(&pd->usecnt);
+	mr->res.type = RDMA_RESTRACK_MR;
+	rdma_restrack_add(&mr->res);
 
 	uobj->object = mr;
 
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 93025d2..d80dbe1 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -1622,6 +1622,7 @@  int ib_dereg_mr(struct ib_mr *mr)
 	struct ib_pd *pd = mr->pd;
 	int ret;
 
+	rdma_restrack_del(&mr->res);
 	ret = mr->device->dereg_mr(mr);
 	if (!ret)
 		atomic_dec(&pd->usecnt);
@@ -1658,6 +1659,8 @@  struct ib_mr *ib_alloc_mr(struct ib_pd *pd,
 		mr->uobject = NULL;
 		atomic_inc(&pd->usecnt);
 		mr->need_inval = false;
+		mr->res.type = RDMA_RESTRACK_MR;
+		rdma_restrack_add(&mr->res);
 	}
 
 	return mr;
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 73b2387..7df3274 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -1772,6 +1772,11 @@  struct ib_mr {
 		struct ib_uobject	*uobject;	/* user */
 		struct list_head	qp_entry;	/* FR */
 	};
+
+	/*
+	 * Implementation details of the RDMA core, don't use in drivers:
+	 */
+	struct rdma_restrack_entry res;
 };
 
 struct ib_mw {
diff --git a/include/rdma/restrack.h b/include/rdma/restrack.h
index bbb1a8f..2257cf5 100644
--- a/include/rdma/restrack.h
+++ b/include/rdma/restrack.h
@@ -33,6 +33,10 @@  enum rdma_restrack_type {
 	 */
 	RDMA_RESTRACK_CM_ID,
 	/**
+	 * @RDMA_RESTRACK_MR: Memory Region (MR)
+	 */
+	RDMA_RESTRACK_MR,
+	/**
 	 * @RDMA_RESTRACK_MAX: Last entry, used for array dclarations
 	 */
 	RDMA_RESTRACK_MAX
diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h
index 49fa044..d21f174 100644
--- a/include/uapi/rdma/rdma_netlink.h
+++ b/include/uapi/rdma/rdma_netlink.h
@@ -242,6 +242,8 @@  enum rdma_nldev_command {
 
 	RDMA_NLDEV_CMD_RES_CQ_GET, /* can dump */
 
+	RDMA_NLDEV_CMD_RES_MR_GET, /* can dump */
+
 	RDMA_NLDEV_NUM_OPS
 };
 
@@ -388,6 +390,14 @@  enum rdma_nldev_attr {
 	RDMA_NLDEV_ATTR_RES_USECNT,		/* u64 */
 	RDMA_NLDEV_ATTR_RES_POLL_CTX,		/* u8 */
 
+	RDMA_NLDEV_ATTR_RES_MR,			/* nested table */
+	RDMA_NLDEV_ATTR_RES_MR_ENTRY,		/* nested table */
+	RDMA_NLDEV_ATTR_RES_RKEY,		/* u32 */
+	RDMA_NLDEV_ATTR_RES_LKEY,		/* u32 */
+	RDMA_NLDEV_ATTR_RES_IOVA,		/* u64 */
+	RDMA_NLDEV_ATTR_RES_MRLEN,		/* u64 */
+	RDMA_NLDEV_ATTR_RES_PGSIZE,		/* u32 */
+
 	RDMA_NLDEV_ATTR_MAX
 };
 #endif /* _UAPI_RDMA_NETLINK_H */