Skip to content

Commit

Permalink
[PATCH] IB: userspace SRQ support
Browse files Browse the repository at this point in the history
Add SRQ support to userspace verbs module.  This adds several commands
and associated structures, but it's OK to do this without bumping the
ABI version because the commands are added at the end of the list so
they don't change the existing numbering.  There are two cases to
worry about:

1. New kernel, old userspace.  This is OK because old userspace simply
   won't try to use the new SRQ commands.  None of the old commands are
   changed.

2. Old kernel, new userspace.  This works perfectly as long as
   userspace doesn't try to use SRQ commands.  If userspace tries to
   use SRQ commands, it will get EINVAL, which is perfectly
   reasonable: the kernel doesn't support SRQs, so we couldn't do any
   better.

Signed-off-by: Roland Dreier <rolandd@cisco.com>
  • Loading branch information
Roland Dreier authored and Roland Dreier committed Aug 27, 2005
1 parent d41fcc6 commit f520ba5
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 4 deletions.
5 changes: 5 additions & 0 deletions drivers/infiniband/core/uverbs.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,12 @@ extern struct idr ib_uverbs_mw_idr;
extern struct idr ib_uverbs_ah_idr;
extern struct idr ib_uverbs_cq_idr;
extern struct idr ib_uverbs_qp_idr;
extern struct idr ib_uverbs_srq_idr;

void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context);
void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr);
void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr);
void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr);

int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
void *addr, size_t size, int write);
Expand Down Expand Up @@ -131,5 +133,8 @@ IB_UVERBS_DECLARE_CMD(modify_qp);
IB_UVERBS_DECLARE_CMD(destroy_qp);
IB_UVERBS_DECLARE_CMD(attach_mcast);
IB_UVERBS_DECLARE_CMD(detach_mcast);
IB_UVERBS_DECLARE_CMD(create_srq);
IB_UVERBS_DECLARE_CMD(modify_srq);
IB_UVERBS_DECLARE_CMD(destroy_srq);

#endif /* UVERBS_H */
182 changes: 180 additions & 2 deletions drivers/infiniband/core/uverbs_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
struct ib_uobject *uobj;
struct ib_pd *pd;
struct ib_cq *scq, *rcq;
struct ib_srq *srq;
struct ib_qp *qp;
struct ib_qp_init_attr attr;
int ret;
Expand All @@ -747,10 +748,12 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle);
rcq = idr_find(&ib_uverbs_cq_idr, cmd.recv_cq_handle);
srq = cmd.is_srq ? idr_find(&ib_uverbs_srq_idr, cmd.srq_handle) : NULL;

if (!pd || pd->uobject->context != file->ucontext ||
!scq || scq->uobject->context != file->ucontext ||
!rcq || rcq->uobject->context != file->ucontext) {
!rcq || rcq->uobject->context != file->ucontext ||
(cmd.is_srq && (!srq || srq->uobject->context != file->ucontext))) {
ret = -EINVAL;
goto err_up;
}
Expand All @@ -759,7 +762,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
attr.qp_context = file;
attr.send_cq = scq;
attr.recv_cq = rcq;
attr.srq = NULL;
attr.srq = srq;
attr.sq_sig_type = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
attr.qp_type = cmd.qp_type;

Expand Down Expand Up @@ -1004,3 +1007,178 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,

return ret ? ret : in_len;
}

ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
const char __user *buf, int in_len,
int out_len)
{
struct ib_uverbs_create_srq cmd;
struct ib_uverbs_create_srq_resp resp;
struct ib_udata udata;
struct ib_uobject *uobj;
struct ib_pd *pd;
struct ib_srq *srq;
struct ib_srq_init_attr attr;
int ret;

if (out_len < sizeof resp)
return -ENOSPC;

if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;

INIT_UDATA(&udata, buf + sizeof cmd,
(unsigned long) cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);

uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
if (!uobj)
return -ENOMEM;

down(&ib_uverbs_idr_mutex);

pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);

if (!pd || pd->uobject->context != file->ucontext) {
ret = -EINVAL;
goto err_up;
}

attr.event_handler = ib_uverbs_srq_event_handler;
attr.srq_context = file;
attr.attr.max_wr = cmd.max_wr;
attr.attr.max_sge = cmd.max_sge;
attr.attr.srq_limit = cmd.srq_limit;

uobj->user_handle = cmd.user_handle;
uobj->context = file->ucontext;

srq = pd->device->create_srq(pd, &attr, &udata);
if (IS_ERR(srq)) {
ret = PTR_ERR(srq);
goto err_up;
}

srq->device = pd->device;
srq->pd = pd;
srq->uobject = uobj;
srq->event_handler = attr.event_handler;
srq->srq_context = attr.srq_context;
atomic_inc(&pd->usecnt);
atomic_set(&srq->usecnt, 0);

memset(&resp, 0, sizeof resp);

retry:
if (!idr_pre_get(&ib_uverbs_srq_idr, GFP_KERNEL)) {
ret = -ENOMEM;
goto err_destroy;
}

ret = idr_get_new(&ib_uverbs_srq_idr, srq, &uobj->id);

if (ret == -EAGAIN)
goto retry;
if (ret)
goto err_destroy;

resp.srq_handle = uobj->id;

spin_lock_irq(&file->ucontext->lock);
list_add_tail(&uobj->list, &file->ucontext->srq_list);
spin_unlock_irq(&file->ucontext->lock);

if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp)) {
ret = -EFAULT;
goto err_list;
}

up(&ib_uverbs_idr_mutex);

return in_len;

err_list:
spin_lock_irq(&file->ucontext->lock);
list_del(&uobj->list);
spin_unlock_irq(&file->ucontext->lock);

err_destroy:
ib_destroy_srq(srq);

err_up:
up(&ib_uverbs_idr_mutex);

kfree(uobj);
return ret;
}

ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
const char __user *buf, int in_len,
int out_len)
{
struct ib_uverbs_modify_srq cmd;
struct ib_srq *srq;
struct ib_srq_attr attr;
int ret;

if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;

down(&ib_uverbs_idr_mutex);

srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
if (!srq || srq->uobject->context != file->ucontext) {
ret = -EINVAL;
goto out;
}

attr.max_wr = cmd.max_wr;
attr.max_sge = cmd.max_sge;
attr.srq_limit = cmd.srq_limit;

ret = ib_modify_srq(srq, &attr, cmd.attr_mask);

out:
up(&ib_uverbs_idr_mutex);

return ret ? ret : in_len;
}

ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
const char __user *buf, int in_len,
int out_len)
{
struct ib_uverbs_destroy_srq cmd;
struct ib_srq *srq;
struct ib_uobject *uobj;
int ret = -EINVAL;

if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;

down(&ib_uverbs_idr_mutex);

srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
if (!srq || srq->uobject->context != file->ucontext)
goto out;

uobj = srq->uobject;

ret = ib_destroy_srq(srq);
if (ret)
goto out;

idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle);

spin_lock_irq(&file->ucontext->lock);
list_del(&uobj->list);
spin_unlock_irq(&file->ucontext->lock);

kfree(uobj);

out:
up(&ib_uverbs_idr_mutex);

return ret ? ret : in_len;
}
20 changes: 19 additions & 1 deletion drivers/infiniband/core/uverbs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ DEFINE_IDR(ib_uverbs_mw_idr);
DEFINE_IDR(ib_uverbs_ah_idr);
DEFINE_IDR(ib_uverbs_cq_idr);
DEFINE_IDR(ib_uverbs_qp_idr);
DEFINE_IDR(ib_uverbs_srq_idr);

static spinlock_t map_lock;
static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
Expand All @@ -93,6 +94,9 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
[IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp,
[IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast,
[IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast,
[IB_USER_VERBS_CMD_CREATE_SRQ] = ib_uverbs_create_srq,
[IB_USER_VERBS_CMD_MODIFY_SRQ] = ib_uverbs_modify_srq,
[IB_USER_VERBS_CMD_DESTROY_SRQ] = ib_uverbs_destroy_srq,
};

static struct vfsmount *uverbs_event_mnt;
Expand Down Expand Up @@ -127,7 +131,14 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context)
kfree(uobj);
}

/* XXX Free SRQs */
list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) {
struct ib_srq *srq = idr_find(&ib_uverbs_srq_idr, uobj->id);
idr_remove(&ib_uverbs_srq_idr, uobj->id);
ib_destroy_srq(srq);
list_del(&uobj->list);
kfree(uobj);
}

/* XXX Free MWs */

list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) {
Expand Down Expand Up @@ -346,6 +357,13 @@ void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr)
event->event);
}

void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr)
{
ib_uverbs_async_handler(context_ptr,
event->element.srq->uobject->user_handle,
event->event);
}

static void ib_uverbs_event_handler(struct ib_event_handler *handler,
struct ib_event *event)
{
Expand Down
35 changes: 34 additions & 1 deletion drivers/infiniband/include/ib_user_verbs.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,12 @@ enum {
IB_USER_VERBS_CMD_POST_SEND,
IB_USER_VERBS_CMD_POST_RECV,
IB_USER_VERBS_CMD_ATTACH_MCAST,
IB_USER_VERBS_CMD_DETACH_MCAST
IB_USER_VERBS_CMD_DETACH_MCAST,
IB_USER_VERBS_CMD_CREATE_SRQ,
IB_USER_VERBS_CMD_MODIFY_SRQ,
IB_USER_VERBS_CMD_QUERY_SRQ,
IB_USER_VERBS_CMD_DESTROY_SRQ,
IB_USER_VERBS_CMD_POST_SRQ_RECV
};

/*
Expand Down Expand Up @@ -386,4 +391,32 @@ struct ib_uverbs_detach_mcast {
__u64 driver_data[0];
};

struct ib_uverbs_create_srq {
__u64 response;
__u64 user_handle;
__u32 pd_handle;
__u32 max_wr;
__u32 max_sge;
__u32 srq_limit;
__u64 driver_data[0];
};

struct ib_uverbs_create_srq_resp {
__u32 srq_handle;
};

struct ib_uverbs_modify_srq {
__u32 srq_handle;
__u32 attr_mask;
__u32 max_wr;
__u32 max_sge;
__u32 srq_limit;
__u32 reserved;
__u64 driver_data[0];
};

struct ib_uverbs_destroy_srq {
__u32 srq_handle;
};

#endif /* IB_USER_VERBS_H */

0 comments on commit f520ba5

Please sign in to comment.