diff options
author | Michael J. Ruhl <michael.j.ruhl@intel.com> | 2017-05-04 08:15:15 -0400 |
---|---|---|
committer | Doug Ledford <dledford@redhat.com> | 2017-05-04 19:31:46 -0400 |
commit | 8737ce95c463c6d8c4307ab3d6858cbf71cd4fc8 (patch) | |
tree | 1afce2cd49297cb1211ebc09f4131806dc036eb3 | |
parent | 9b60d2cbe07486658a32d4ed2fff7085c44bae7a (diff) |
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>
-rw-r--r-- | drivers/infiniband/hw/hfi1/driver.c | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/hfi1/file_ops.c | 51 | ||||
-rw-r--r-- | drivers/infiniband/hw/hfi1/hfi.h | 8 | ||||
-rw-r--r-- | drivers/infiniband/hw/hfi1/init.c | 3 | ||||
-rw-r--r-- | drivers/infiniband/hw/hfi1/intr.c | 3 | ||||
-rw-r--r-- | drivers/infiniband/hw/hfi1/user_sdma.h | 2 |
6 files changed, 41 insertions, 28 deletions
diff --git a/drivers/infiniband/hw/hfi1/driver.c b/drivers/infiniband/hw/hfi1/driver.c index 566d152e36f2..a50870e455a3 100644 --- a/drivers/infiniband/hw/hfi1/driver.c +++ b/drivers/infiniband/hw/hfi1/driver.c | |||
@@ -1289,7 +1289,7 @@ int hfi1_reset_device(int unit) | |||
1289 | if (dd->rcd) | 1289 | if (dd->rcd) |
1290 | for (i = dd->first_dyn_alloc_ctxt; | 1290 | for (i = dd->first_dyn_alloc_ctxt; |
1291 | i < dd->num_rcv_contexts; i++) { | 1291 | i < dd->num_rcv_contexts; i++) { |
1292 | if (!dd->rcd[i] || !dd->rcd[i]->cnt) | 1292 | if (!dd->rcd[i]) |
1293 | continue; | 1293 | continue; |
1294 | spin_unlock_irqrestore(&dd->uctxt_lock, flags); | 1294 | spin_unlock_irqrestore(&dd->uctxt_lock, flags); |
1295 | ret = -EBUSY; | 1295 | ret = -EBUSY; |
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 @@ | |||
49 | #include <linux/vmalloc.h> | 49 | #include <linux/vmalloc.h> |
50 | #include <linux/io.h> | 50 | #include <linux/io.h> |
51 | #include <linux/sched/mm.h> | 51 | #include <linux/sched/mm.h> |
52 | #include <linux/bitmap.h> | ||
52 | 53 | ||
53 | #include <rdma/ib.h> | 54 | #include <rdma/ib.h> |
54 | 55 | ||
@@ -95,11 +96,10 @@ static int allocate_ctxt(struct hfi1_filedata *fd, struct hfi1_devdata *dd, | |||
95 | struct hfi1_user_info *uinfo); | 96 | struct hfi1_user_info *uinfo); |
96 | static unsigned int poll_urgent(struct file *fp, struct poll_table_struct *pt); | 97 | static unsigned int poll_urgent(struct file *fp, struct poll_table_struct *pt); |
97 | static unsigned int poll_next(struct file *fp, struct poll_table_struct *pt); | 98 | static unsigned int poll_next(struct file *fp, struct poll_table_struct *pt); |
98 | static int user_event_ack(struct hfi1_ctxtdata *uctxt, int subctxt, | 99 | static int user_event_ack(struct hfi1_ctxtdata *uctxt, u16 subctxt, |
99 | unsigned long events); | 100 | unsigned long events); |
100 | static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, unsigned subctxt, | 101 | static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, u16 subctxt, u16 pkey); |
101 | u16 pkey); | 102 | static int manage_rcvq(struct hfi1_ctxtdata *uctxt, u16 subctxt, |
102 | static int manage_rcvq(struct hfi1_ctxtdata *uctxt, unsigned subctxt, | ||
103 | int start_stop); | 103 | int start_stop); |
104 | static int vma_fault(struct vm_fault *vmf); | 104 | static int vma_fault(struct vm_fault *vmf); |
105 | static long hfi1_file_ioctl(struct file *fp, unsigned int cmd, | 105 | 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) | |||
773 | HFI1_MAX_SHARED_CTXTS) + fdata->subctxt; | 773 | HFI1_MAX_SHARED_CTXTS) + fdata->subctxt; |
774 | *ev = 0; | 774 | *ev = 0; |
775 | 775 | ||
776 | if (--uctxt->cnt) { | 776 | __clear_bit(fdata->subctxt, uctxt->in_use_ctxts); |
777 | uctxt->active_slaves &= ~(1 << fdata->subctxt); | 777 | if (!bitmap_empty(uctxt->in_use_ctxts, HFI1_MAX_SHARED_CTXTS)) { |
778 | mutex_unlock(&hfi1_mutex); | 778 | mutex_unlock(&hfi1_mutex); |
779 | goto done; | 779 | goto done; |
780 | } | 780 | } |
@@ -868,7 +868,7 @@ static int assign_ctxt(struct hfi1_filedata *fd, struct hfi1_user_info *uinfo) | |||
868 | } | 868 | } |
869 | 869 | ||
870 | /* | 870 | /* |
871 | * Allocate a base context f context sharing is not required or we | 871 | * Allocate a base context if context sharing is not required or we |
872 | * couldn't find a sub context. | 872 | * couldn't find a sub context. |
873 | */ | 873 | */ |
874 | if (!ret) | 874 | if (!ret) |
@@ -905,17 +905,24 @@ static int assign_ctxt(struct hfi1_filedata *fd, struct hfi1_user_info *uinfo) | |||
905 | return ret; | 905 | return ret; |
906 | } | 906 | } |
907 | 907 | ||
908 | /* | ||
909 | * The hfi1_mutex must be held when this function is called. It is | ||
910 | * necessary to ensure serialized access to the bitmask in_use_ctxts. | ||
911 | */ | ||
908 | static int find_sub_ctxt(struct hfi1_filedata *fd, | 912 | static int find_sub_ctxt(struct hfi1_filedata *fd, |
909 | const struct hfi1_user_info *uinfo) | 913 | const struct hfi1_user_info *uinfo) |
910 | { | 914 | { |
911 | int i; | 915 | int i; |
912 | struct hfi1_devdata *dd = fd->dd; | 916 | struct hfi1_devdata *dd = fd->dd; |
917 | u16 subctxt; | ||
913 | 918 | ||
914 | for (i = dd->first_dyn_alloc_ctxt; i < dd->num_rcv_contexts; i++) { | 919 | for (i = dd->first_dyn_alloc_ctxt; i < dd->num_rcv_contexts; i++) { |
915 | struct hfi1_ctxtdata *uctxt = dd->rcd[i]; | 920 | struct hfi1_ctxtdata *uctxt = dd->rcd[i]; |
916 | 921 | ||
917 | /* Skip ctxts which are not yet open */ | 922 | /* Skip ctxts which are not yet open */ |
918 | if (!uctxt || !uctxt->cnt) | 923 | if (!uctxt || |
924 | bitmap_empty(uctxt->in_use_ctxts, | ||
925 | HFI1_MAX_SHARED_CTXTS)) | ||
919 | continue; | 926 | continue; |
920 | 927 | ||
921 | /* Skip dynamically allocted kernel contexts */ | 928 | /* Skip dynamically allocted kernel contexts */ |
@@ -931,13 +938,19 @@ static int find_sub_ctxt(struct hfi1_filedata *fd, | |||
931 | continue; | 938 | continue; |
932 | 939 | ||
933 | /* Verify the sharing process matches the master */ | 940 | /* Verify the sharing process matches the master */ |
934 | if (uctxt->userversion != uinfo->userversion || | 941 | if (uctxt->userversion != uinfo->userversion) |
935 | uctxt->cnt >= uctxt->subctxt_cnt) { | ||
936 | return -EINVAL; | 942 | return -EINVAL; |
937 | } | 943 | |
944 | /* Find an unused context */ | ||
945 | subctxt = find_first_zero_bit(uctxt->in_use_ctxts, | ||
946 | HFI1_MAX_SHARED_CTXTS); | ||
947 | if (subctxt >= uctxt->subctxt_cnt) | ||
948 | return -EINVAL; | ||
949 | |||
938 | fd->uctxt = uctxt; | 950 | fd->uctxt = uctxt; |
939 | fd->subctxt = uctxt->cnt++; | 951 | fd->subctxt = subctxt; |
940 | uctxt->active_slaves |= 1 << fd->subctxt; | 952 | __set_bit(fd->subctxt, uctxt->in_use_ctxts); |
953 | |||
941 | return 1; | 954 | return 1; |
942 | } | 955 | } |
943 | 956 | ||
@@ -1055,7 +1068,7 @@ ctxdata_free: | |||
1055 | static int init_subctxts(struct hfi1_ctxtdata *uctxt, | 1068 | static int init_subctxts(struct hfi1_ctxtdata *uctxt, |
1056 | const struct hfi1_user_info *uinfo) | 1069 | const struct hfi1_user_info *uinfo) |
1057 | { | 1070 | { |
1058 | unsigned num_subctxts; | 1071 | u16 num_subctxts; |
1059 | 1072 | ||
1060 | num_subctxts = uinfo->subctxt_cnt; | 1073 | num_subctxts = uinfo->subctxt_cnt; |
1061 | if (num_subctxts > HFI1_MAX_SHARED_CTXTS) | 1074 | if (num_subctxts > HFI1_MAX_SHARED_CTXTS) |
@@ -1063,7 +1076,6 @@ static int init_subctxts(struct hfi1_ctxtdata *uctxt, | |||
1063 | 1076 | ||
1064 | uctxt->subctxt_cnt = uinfo->subctxt_cnt; | 1077 | uctxt->subctxt_cnt = uinfo->subctxt_cnt; |
1065 | uctxt->subctxt_id = uinfo->subctxt_id; | 1078 | uctxt->subctxt_id = uinfo->subctxt_id; |
1066 | uctxt->active_slaves = 1; | ||
1067 | uctxt->redirect_seq_cnt = 1; | 1079 | uctxt->redirect_seq_cnt = 1; |
1068 | set_bit(HFI1_CTXT_BASE_UNINIT, &uctxt->event_flags); | 1080 | set_bit(HFI1_CTXT_BASE_UNINIT, &uctxt->event_flags); |
1069 | 1081 | ||
@@ -1073,7 +1085,7 @@ static int init_subctxts(struct hfi1_ctxtdata *uctxt, | |||
1073 | static int setup_subctxt(struct hfi1_ctxtdata *uctxt) | 1085 | static int setup_subctxt(struct hfi1_ctxtdata *uctxt) |
1074 | { | 1086 | { |
1075 | int ret = 0; | 1087 | int ret = 0; |
1076 | unsigned num_subctxts = uctxt->subctxt_cnt; | 1088 | u16 num_subctxts = uctxt->subctxt_cnt; |
1077 | 1089 | ||
1078 | uctxt->subctxt_uregbase = vmalloc_user(PAGE_SIZE); | 1090 | uctxt->subctxt_uregbase = vmalloc_user(PAGE_SIZE); |
1079 | if (!uctxt->subctxt_uregbase) | 1091 | if (!uctxt->subctxt_uregbase) |
@@ -1425,7 +1437,7 @@ done: | |||
1425 | * overflow conditions. start_stop==1 re-enables, to be used to | 1437 | * overflow conditions. start_stop==1 re-enables, to be used to |
1426 | * re-init the software copy of the head register | 1438 | * re-init the software copy of the head register |
1427 | */ | 1439 | */ |
1428 | static int manage_rcvq(struct hfi1_ctxtdata *uctxt, unsigned subctxt, | 1440 | static int manage_rcvq(struct hfi1_ctxtdata *uctxt, u16 subctxt, |
1429 | int start_stop) | 1441 | int start_stop) |
1430 | { | 1442 | { |
1431 | struct hfi1_devdata *dd = uctxt->dd; | 1443 | struct hfi1_devdata *dd = uctxt->dd; |
@@ -1460,7 +1472,7 @@ bail: | |||
1460 | * User process then performs actions appropriate to bit having been | 1472 | * User process then performs actions appropriate to bit having been |
1461 | * set, if desired, and checks again in future. | 1473 | * set, if desired, and checks again in future. |
1462 | */ | 1474 | */ |
1463 | static int user_event_ack(struct hfi1_ctxtdata *uctxt, int subctxt, | 1475 | static int user_event_ack(struct hfi1_ctxtdata *uctxt, u16 subctxt, |
1464 | unsigned long events) | 1476 | unsigned long events) |
1465 | { | 1477 | { |
1466 | int i; | 1478 | int i; |
@@ -1481,8 +1493,7 @@ static int user_event_ack(struct hfi1_ctxtdata *uctxt, int subctxt, | |||
1481 | return 0; | 1493 | return 0; |
1482 | } | 1494 | } |
1483 | 1495 | ||
1484 | static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, unsigned subctxt, | 1496 | static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, u16 subctxt, u16 pkey) |
1485 | u16 pkey) | ||
1486 | { | 1497 | { |
1487 | int ret = -ENOENT, i, intable = 0; | 1498 | int ret = -ENOENT, i, intable = 0; |
1488 | struct hfi1_pportdata *ppd = uctxt->ppd; | 1499 | struct hfi1_pportdata *ppd = uctxt->ppd; |
diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index 1b7203a3f1ce..f3d75fcd5f07 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h | |||
@@ -228,7 +228,7 @@ struct hfi1_ctxtdata { | |||
228 | unsigned ctxt; | 228 | unsigned ctxt; |
229 | /* | 229 | /* |
230 | * non-zero if ctxt can be shared, and defines the maximum number of | 230 | * non-zero if ctxt can be shared, and defines the maximum number of |
231 | * sub contexts allowed. | 231 | * sub-contexts for this device context. |
232 | */ | 232 | */ |
233 | u16 subctxt_cnt; | 233 | u16 subctxt_cnt; |
234 | /* non-zero if ctxt is being shared. */ | 234 | /* non-zero if ctxt is being shared. */ |
@@ -287,10 +287,10 @@ struct hfi1_ctxtdata { | |||
287 | void *subctxt_rcvegrbuf; | 287 | void *subctxt_rcvegrbuf; |
288 | /* An array of pages for the eager header queue entries * N */ | 288 | /* An array of pages for the eager header queue entries * N */ |
289 | void *subctxt_rcvhdr_base; | 289 | void *subctxt_rcvhdr_base; |
290 | /* Bitmask of in use context(s) */ | ||
291 | DECLARE_BITMAP(in_use_ctxts, HFI1_MAX_SHARED_CTXTS); | ||
290 | /* The version of the library which opened this ctxt */ | 292 | /* The version of the library which opened this ctxt */ |
291 | u32 userversion; | 293 | u32 userversion; |
292 | /* Bitmask of active slaves */ | ||
293 | u32 active_slaves; | ||
294 | /* Type of packets or conditions we want to poll for */ | 294 | /* Type of packets or conditions we want to poll for */ |
295 | u16 poll_type; | 295 | u16 poll_type; |
296 | /* receive packet sequence counter */ | 296 | /* receive packet sequence counter */ |
@@ -1239,9 +1239,9 @@ struct mmu_rb_handler; | |||
1239 | struct hfi1_filedata { | 1239 | struct hfi1_filedata { |
1240 | struct hfi1_devdata *dd; | 1240 | struct hfi1_devdata *dd; |
1241 | struct hfi1_ctxtdata *uctxt; | 1241 | struct hfi1_ctxtdata *uctxt; |
1242 | unsigned subctxt; | ||
1243 | struct hfi1_user_sdma_comp_q *cq; | 1242 | struct hfi1_user_sdma_comp_q *cq; |
1244 | struct hfi1_user_sdma_pkt_q *pq; | 1243 | struct hfi1_user_sdma_pkt_q *pq; |
1244 | u16 subctxt; | ||
1245 | /* for cpu affinity; -1 if none */ | 1245 | /* for cpu affinity; -1 if none */ |
1246 | int rec_cpu_num; | 1246 | int rec_cpu_num; |
1247 | u32 tid_n_pinned; | 1247 | u32 tid_n_pinned; |
diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index 52a6364c30de..694a8ecf9f26 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <linux/module.h> | 53 | #include <linux/module.h> |
54 | #include <linux/printk.h> | 54 | #include <linux/printk.h> |
55 | #include <linux/hrtimer.h> | 55 | #include <linux/hrtimer.h> |
56 | #include <linux/bitmap.h> | ||
56 | #include <rdma/rdma_vt.h> | 57 | #include <rdma/rdma_vt.h> |
57 | 58 | ||
58 | #include "hfi.h" | 59 | #include "hfi.h" |
@@ -222,7 +223,7 @@ struct hfi1_ctxtdata *hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, u32 ctxt, | |||
222 | INIT_LIST_HEAD(&rcd->qp_wait_list); | 223 | INIT_LIST_HEAD(&rcd->qp_wait_list); |
223 | rcd->ppd = ppd; | 224 | rcd->ppd = ppd; |
224 | rcd->dd = dd; | 225 | rcd->dd = dd; |
225 | rcd->cnt = 1; | 226 | __set_bit(0, rcd->in_use_ctxts); |
226 | rcd->ctxt = ctxt; | 227 | rcd->ctxt = ctxt; |
227 | dd->rcd[ctxt] = rcd; | 228 | dd->rcd[ctxt] = rcd; |
228 | rcd->numa_id = numa; | 229 | rcd->numa_id = numa; |
diff --git a/drivers/infiniband/hw/hfi1/intr.c b/drivers/infiniband/hw/hfi1/intr.c index 232014d46f79..ba265d0ae93b 100644 --- a/drivers/infiniband/hw/hfi1/intr.c +++ b/drivers/infiniband/hw/hfi1/intr.c | |||
@@ -47,6 +47,7 @@ | |||
47 | 47 | ||
48 | #include <linux/pci.h> | 48 | #include <linux/pci.h> |
49 | #include <linux/delay.h> | 49 | #include <linux/delay.h> |
50 | #include <linux/bitmap.h> | ||
50 | 51 | ||
51 | #include "hfi.h" | 52 | #include "hfi.h" |
52 | #include "common.h" | 53 | #include "common.h" |
@@ -189,7 +190,7 @@ void handle_user_interrupt(struct hfi1_ctxtdata *rcd) | |||
189 | unsigned long flags; | 190 | unsigned long flags; |
190 | 191 | ||
191 | spin_lock_irqsave(&dd->uctxt_lock, flags); | 192 | spin_lock_irqsave(&dd->uctxt_lock, flags); |
192 | if (!rcd->cnt) | 193 | if (bitmap_empty(rcd->in_use_ctxts, HFI1_MAX_SHARED_CTXTS)) |
193 | goto done; | 194 | goto done; |
194 | 195 | ||
195 | if (test_and_clear_bit(HFI1_CTXT_WAITING_RCV, &rcd->event_flags)) { | 196 | if (test_and_clear_bit(HFI1_CTXT_WAITING_RCV, &rcd->event_flags)) { |
diff --git a/drivers/infiniband/hw/hfi1/user_sdma.h b/drivers/infiniband/hw/hfi1/user_sdma.h index 9181d7cbe8f6..e5b10aefe212 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.h +++ b/drivers/infiniband/hw/hfi1/user_sdma.h | |||
@@ -58,7 +58,7 @@ extern uint extended_psn; | |||
58 | struct hfi1_user_sdma_pkt_q { | 58 | struct hfi1_user_sdma_pkt_q { |
59 | struct list_head list; | 59 | struct list_head list; |
60 | unsigned ctxt; | 60 | unsigned ctxt; |
61 | unsigned subctxt; | 61 | u16 subctxt; |
62 | u16 n_max_reqs; | 62 | u16 n_max_reqs; |
63 | atomic_t n_reqs; | 63 | atomic_t n_reqs; |
64 | u16 reqidx; | 64 | u16 reqidx; |