const struct nldev_fill_res_entry *fe = &fill_entries[res_type];
struct nlattr *tb[RDMA_NLDEV_ATTR_MAX];
struct rdma_restrack_entry *res;
+ struct rdma_restrack_root *rt;
int err, ret = 0, idx = 0;
struct nlattr *table_attr;
struct nlattr *entry_attr;
unsigned long id;
u32 index, port = 0;
bool filled = false;
- struct xarray *xa;
err = nlmsg_parse(cb->nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1,
nldev_policy, NULL);
has_cap_net_admin = netlink_capable(cb->skb, CAP_NET_ADMIN);
- xa = &device->res->xa[res_type];
- down_read(&device->res->rwsem);
+ rt = &device->res[res_type];
+ xa_lock(&rt->xa);
/*
* FIXME: if the skip ahead is something common this loop should
* use xas_for_each & xas_pause to optimize, we can have a lot of
* objects.
*/
- xa_for_each(xa, id, res) {
+ xa_for_each(&rt->xa, id, res) {
if (idx < start)
goto next;
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;
+ xa_unlock(&rt->xa);
+
filled = true;
entry_attr = nla_nest_start(skb, fe->entry);
if (!entry_attr) {
ret = -EMSGSIZE;
rdma_restrack_put(res);
- up_read(&device->res->rwsem);
- break;
+ goto msg_full;
}
- up_read(&device->res->rwsem);
ret = fe->fill_res_func(skb, has_cap_net_admin, res, port);
- 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)
+ if (ret) {
nla_nest_cancel(skb, entry_attr);
- if (ret == -EMSGSIZE)
- break;
- if (ret == -EAGAIN)
- goto next;
- if (ret)
+ if (ret == -EMSGSIZE)
+ goto msg_full;
+ if (ret == -EAGAIN)
+ goto again;
goto res_err;
+ }
nla_nest_end(skb, entry_attr);
+again: xa_lock(&rt->xa);
next: idx++;
}
- up_read(&device->res->rwsem);
+ xa_unlock(&rt->xa);
+msg_full:
nla_nest_end(skb, table_attr);
nlmsg_end(skb, nlh);
cb->args[0] = idx;
res_err:
nla_nest_cancel(skb, table_attr);
- up_read(&device->res->rwsem);
err:
nlmsg_cancel(skb, nlh);
#include <linux/mutex.h>
#include <linux/sched/task.h>
#include <linux/pid_namespace.h>
-#include <linux/rwsem.h>
#include "cma_priv.h"
#include "restrack.h"
struct rdma_restrack_root *rt;
int i;
- dev->res = kzalloc(sizeof(*rt), GFP_KERNEL);
+ dev->res = kcalloc(RDMA_RESTRACK_MAX, sizeof(*rt), GFP_KERNEL);
if (!dev->res)
return -ENOMEM;
rt = dev->res;
- for (i = 0 ; i < RDMA_RESTRACK_MAX; i++)
- xa_init_flags(&rt->xa[i], XA_FLAGS_ALLOC);
- init_rwsem(&rt->rwsem);
+ for (i = 0; i < RDMA_RESTRACK_MAX; i++)
+ xa_init_flags(&rt[i].xa, XA_FLAGS_ALLOC);
return 0;
}
int i;
for (i = 0 ; i < RDMA_RESTRACK_MAX; i++) {
- struct xarray *xa = &dev->res->xa[i];
+ struct xarray *xa = &dev->res[i].xa;
if (!xa_empty(xa)) {
unsigned long index;
int rdma_restrack_count(struct ib_device *dev, enum rdma_restrack_type type,
struct pid_namespace *ns)
{
- struct xarray *xa = &dev->res->xa[type];
+ struct rdma_restrack_root *rt = &dev->res[type];
struct rdma_restrack_entry *e;
- unsigned long index = 0;
+ XA_STATE(xas, &rt->xa, 0);
u32 cnt = 0;
- down_read(&dev->res->rwsem);
- xa_for_each(xa, index, e) {
+ xa_lock(&rt->xa);
+ xas_for_each(&xas, e, U32_MAX) {
if (ns == &init_pid_ns ||
(!rdma_is_kernel_res(e) &&
ns == task_active_pid_ns(e->task)))
cnt++;
}
- up_read(&dev->res->rwsem);
+ xa_unlock(&rt->xa);
return cnt;
}
EXPORT_SYMBOL(rdma_restrack_count);
{
struct ib_device *dev = res_to_dev(res);
struct rdma_restrack_root *rt;
- struct xarray *xa;
int ret;
if (!dev)
return;
- rt = dev->res;
- xa = &dev->res->xa[res->type];
+ rt = &dev->res[res->type];
kref_init(&res->kref);
init_completion(&res->comp);
- ret = rt_xa_alloc_cyclic(xa, &res->id, res, &rt->next_id[res->type]);
+ ret = rt_xa_alloc_cyclic(&rt->xa, &res->id, res, &rt->next_id);
if (!ret)
res->valid = true;
}
rdma_restrack_get_byid(struct ib_device *dev,
enum rdma_restrack_type type, u32 id)
{
- struct xarray *xa = &dev->res->xa[type];
+ struct rdma_restrack_root *rt = &dev->res[type];
struct rdma_restrack_entry *res;
- down_read(&dev->res->rwsem);
- res = xa_load(xa, id);
+ xa_lock(&rt->xa);
+ res = xa_load(&rt->xa, id);
if (!res || !rdma_restrack_get(res))
res = ERR_PTR(-ENOENT);
- up_read(&dev->res->rwsem);
+ xa_unlock(&rt->xa);
return res;
}
void rdma_restrack_del(struct rdma_restrack_entry *res)
{
- struct ib_device *dev = res_to_dev(res);
- struct xarray *xa;
+ struct rdma_restrack_entry *old;
+ struct rdma_restrack_root *rt;
+ struct ib_device *dev;
if (!res->valid)
goto out;
- /*
- * All objects except CM_ID set valid device immediately
- * after new object is created, it means that for not valid
- * objects will still have "dev".
- *
- * It is not the case for CM_ID, newly created object has
- * this field set to NULL and it is set in _cma_attach_to_dev()
- * only.
- *
- * Because we don't want to add any conditions on call
- * to rdma_restrack_del(), the check below protects from
- * NULL-dereference.
- */
- if (!dev)
+ dev = res_to_dev(res);
+ if (WARN_ON(!dev))
return;
- xa = &dev->res->xa[res->type];
- down_write(&dev->res->rwsem);
- xa_erase(xa, res->id);
+ rt = &dev->res[res->type];
+
+ old = xa_erase(&rt->xa, res->id);
+ WARN_ON(old != res);
res->valid = false;
- up_write(&dev->res->rwsem);
rdma_restrack_put(res);
wait_for_completion(&res->comp);
#define _RDMA_CORE_RESTRACK_H_
#include <linux/mutex.h>
-#include <linux/rwsem.h>
/**
* struct rdma_restrack_root - main resource tracking management
* entity, per-device
*/
struct rdma_restrack_root {
- /*
- * @rwsem: Read/write lock to protect erase of entry.
- * Lists and insertions are protected by XArray internal lock.
- */
- struct rw_semaphore rwsem;
/**
- * @xa: Array of XArray structures to hold restrack entries.
- * We want to use array of XArrays because insertion is type
- * dependent. For types with xisiting unique ID (like QPN),
- * we will insert to that unique index. For other types,
- * we insert based on pointers and auto-allocate unique index.
+ * @xa: Array of XArray structure to hold restrack entries.
*/
- struct xarray xa[RDMA_RESTRACK_MAX];
+ struct xarray xa;
/**
* @next_id: Next ID to support cyclic allocation
*/
- u32 next_id[RDMA_RESTRACK_MAX];
+ u32 next_id;
};
-
int rdma_restrack_init(struct ib_device *dev);
void rdma_restrack_clean(struct ib_device *dev);
#endif /* _RDMA_CORE_RESTRACK_H_ */