diff options
author | Michael J. Ruhl <michael.j.ruhl@intel.com> | 2017-05-04 05:15:15 -0700 |
---|---|---|
committer | Doug Ledford <dledford@redhat.com> | 2017-05-04 19:31:46 -0400 |
commit | 8737ce95c463c6d8c4307ab3d6858cbf71cd4fc8 (patch) | |
tree | 1afce2cd49297cb1211ebc09f4131806dc036eb3 /drivers/infiniband/hw/hfi1/file_ops.c | |
parent | 9b60d2cbe07486658a32d4ed2fff7085c44bae7a (diff) | |
download | linux-8737ce95c463c6d8c4307ab3d6858cbf71cd4fc8.tar.bz2 |
IB/hfi1: Fix an assign/ordering issue with shared context IDs
The current algorithm for generating sub-context IDs is FILO. If the
contexts are not closed in that order, the uniqueness of the ID will be
compromised. I.e. logging the creation/deletion of context IDs with an
application that assigns and closes in a FIFO order reveals:
cache_id: assign: uctxt: 3 sub_ctxt: 0
cache_id: assign: uctxt: 3 sub_ctxt: 1
cache_id: assign: uctxt: 3 sub_ctxt: 2
cache_id: close: uctxt: 3 sub_ctxt: 0
cache_id: assign: uctxt: 3 sub_ctxt: 2 <<<
The sub_ctxt ID 2 is reused incorrectly.
Update the sub-context ID assign algorithm to use a bitmask of in_use
contexts. The new algorithm will allow the contexts to be closed in any
order, and will only re-use unused contexts.
Size subctxt and subctxt_cnt to match the user API size.
Reviewed-by: Mike Marciniszyn <mike.marciniszyn@intel.com>
Signed-off-by: Michael J. Ruhl <michael.j.ruhl@intel.com>
Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
Diffstat (limited to 'drivers/infiniband/hw/hfi1/file_ops.c')
-rw-r--r-- | drivers/infiniband/hw/hfi1/file_ops.c | 51 |
1 files changed, 31 insertions, 20 deletions
diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index 467f876551ba..9c177ef79db5 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -49,6 +49,7 @@ #include <linux/vmalloc.h> #include <linux/io.h> #include <linux/sched/mm.h> +#include <linux/bitmap.h> #include <rdma/ib.h> @@ -95,11 +96,10 @@ static int allocate_ctxt(struct hfi1_filedata *fd, struct hfi1_devdata *dd, struct hfi1_user_info *uinfo); static unsigned int poll_urgent(struct file *fp, struct poll_table_struct *pt); static unsigned int poll_next(struct file *fp, struct poll_table_struct *pt); -static int user_event_ack(struct hfi1_ctxtdata *uctxt, int subctxt, +static int user_event_ack(struct hfi1_ctxtdata *uctxt, u16 subctxt, unsigned long events); -static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, unsigned subctxt, - u16 pkey); -static int manage_rcvq(struct hfi1_ctxtdata *uctxt, unsigned subctxt, +static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, u16 subctxt, u16 pkey); +static int manage_rcvq(struct hfi1_ctxtdata *uctxt, u16 subctxt, int start_stop); static int vma_fault(struct vm_fault *vmf); static long hfi1_file_ioctl(struct file *fp, unsigned int cmd, @@ -773,8 +773,8 @@ static int hfi1_file_close(struct inode *inode, struct file *fp) HFI1_MAX_SHARED_CTXTS) + fdata->subctxt; *ev = 0; - if (--uctxt->cnt) { - uctxt->active_slaves &= ~(1 << fdata->subctxt); + __clear_bit(fdata->subctxt, uctxt->in_use_ctxts); + if (!bitmap_empty(uctxt->in_use_ctxts, HFI1_MAX_SHARED_CTXTS)) { mutex_unlock(&hfi1_mutex); goto done; } @@ -868,7 +868,7 @@ static int assign_ctxt(struct hfi1_filedata *fd, struct hfi1_user_info *uinfo) } /* - * Allocate a base context f context sharing is not required or we + * Allocate a base context if context sharing is not required or we * couldn't find a sub context. */ if (!ret) @@ -905,17 +905,24 @@ static int assign_ctxt(struct hfi1_filedata *fd, struct hfi1_user_info *uinfo) return ret; } +/* + * The hfi1_mutex must be held when this function is called. It is + * necessary to ensure serialized access to the bitmask in_use_ctxts. + */ static int find_sub_ctxt(struct hfi1_filedata *fd, const struct hfi1_user_info *uinfo) { int i; struct hfi1_devdata *dd = fd->dd; + u16 subctxt; for (i = dd->first_dyn_alloc_ctxt; i < dd->num_rcv_contexts; i++) { struct hfi1_ctxtdata *uctxt = dd->rcd[i]; /* Skip ctxts which are not yet open */ - if (!uctxt || !uctxt->cnt) + if (!uctxt || + bitmap_empty(uctxt->in_use_ctxts, + HFI1_MAX_SHARED_CTXTS)) continue; /* Skip dynamically allocted kernel contexts */ @@ -931,13 +938,19 @@ static int find_sub_ctxt(struct hfi1_filedata *fd, continue; /* Verify the sharing process matches the master */ - if (uctxt->userversion != uinfo->userversion || - uctxt->cnt >= uctxt->subctxt_cnt) { + if (uctxt->userversion != uinfo->userversion) return -EINVAL; - } + + /* Find an unused context */ + subctxt = find_first_zero_bit(uctxt->in_use_ctxts, + HFI1_MAX_SHARED_CTXTS); + if (subctxt >= uctxt->subctxt_cnt) + return -EINVAL; + fd->uctxt = uctxt; - fd->subctxt = uctxt->cnt++; - uctxt->active_slaves |= 1 << fd->subctxt; + fd->subctxt = subctxt; + __set_bit(fd->subctxt, uctxt->in_use_ctxts); + return 1; } @@ -1055,7 +1068,7 @@ ctxdata_free: static int init_subctxts(struct hfi1_ctxtdata *uctxt, const struct hfi1_user_info *uinfo) { - unsigned num_subctxts; + u16 num_subctxts; num_subctxts = uinfo->subctxt_cnt; if (num_subctxts > HFI1_MAX_SHARED_CTXTS) @@ -1063,7 +1076,6 @@ static int init_subctxts(struct hfi1_ctxtdata *uctxt, uctxt->subctxt_cnt = uinfo->subctxt_cnt; uctxt->subctxt_id = uinfo->subctxt_id; - uctxt->active_slaves = 1; uctxt->redirect_seq_cnt = 1; set_bit(HFI1_CTXT_BASE_UNINIT, &uctxt->event_flags); @@ -1073,7 +1085,7 @@ static int init_subctxts(struct hfi1_ctxtdata *uctxt, static int setup_subctxt(struct hfi1_ctxtdata *uctxt) { int ret = 0; - unsigned num_subctxts = uctxt->subctxt_cnt; + u16 num_subctxts = uctxt->subctxt_cnt; uctxt->subctxt_uregbase = vmalloc_user(PAGE_SIZE); if (!uctxt->subctxt_uregbase) @@ -1425,7 +1437,7 @@ done: * overflow conditions. start_stop==1 re-enables, to be used to * re-init the software copy of the head register */ -static int manage_rcvq(struct hfi1_ctxtdata *uctxt, unsigned subctxt, +static int manage_rcvq(struct hfi1_ctxtdata *uctxt, u16 subctxt, int start_stop) { struct hfi1_devdata *dd = uctxt->dd; @@ -1460,7 +1472,7 @@ bail: * User process then performs actions appropriate to bit having been * set, if desired, and checks again in future. */ -static int user_event_ack(struct hfi1_ctxtdata *uctxt, int subctxt, +static int user_event_ack(struct hfi1_ctxtdata *uctxt, u16 subctxt, unsigned long events) { int i; @@ -1481,8 +1493,7 @@ static int user_event_ack(struct hfi1_ctxtdata *uctxt, int subctxt, return 0; } -static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, unsigned subctxt, - u16 pkey) +static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, u16 subctxt, u16 pkey) { int ret = -ENOENT, i, intable = 0; struct hfi1_pportdata *ppd = uctxt->ppd; |