DF-5689 / fix.diff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | --- a/sys/libkern/linux_idr.c +++ b/sys/libkern/linux_idr.c @@ -184,7 +184,7 @@ if (id < 0 || id >= idp->idr_count) return (NULL); idrnp = &idp->idr_nodes[id]; - if (idrnp->allocated == 0) + if (idrnp->used == 0) return (NULL); return (idrnp); } @@ -345,6 +345,7 @@ *id = resid; idr_reserve(idp, resid, 1); idp->idr_nodes[resid].data = ptr; + idp->idr_nodes[resid].used = 1; lwkt_reltoken(&idp->idr_token); return (0); @@ -400,6 +401,7 @@ result = id; idr_reserve(idp, id, 1); idp->idr_nodes[id].data = ptr; + idp->idr_nodes[id].used = 1; done: lwkt_reltoken(&idp->idr_token); @@ -470,12 +472,13 @@ lwkt_reltoken(&idp->idr_token); return NULL; } - if (idp->idr_nodes[id].allocated == 0) { + if (idp->idr_nodes[id].used == 0) { lwkt_reltoken(&idp->idr_token); return NULL; } ptr = idp->idr_nodes[id].data; idp->idr_nodes[id].data = NULL; + idp->idr_nodes[id].used = 0; idr_reserve(idp, id, -1); idrfixup(idp, id); lwkt_reltoken(&idp->idr_token); @@ -517,14 +520,29 @@ { void *ret; + lwkt_gettoken(&idp->idr_token); + ret = __idr_find(idp, id); + lwkt_reltoken(&idp->idr_token); + return (ret); +} + +/* + * Unlocked variant for callers already holding idp->idr_token + * (idr_get_next() in the drm linux-compat shim). + */ +void * +__idr_find(struct idr *idp, int id) +{ + void *ret; + if (id < 0 || id >= idp->idr_count) { ret = NULL; - } else if (idp->idr_nodes[id].allocated == 0) { + } else if (idp->idr_nodes[id].used == 0) { ret = NULL; } else { ret = idp->idr_nodes[id].data; } - return ret; + return (ret); } int @@ -534,14 +552,16 @@ int i, error = 0; struct idr_node *nodes; + lwkt_gettoken(&idp->idr_token); nodes = idp->idr_nodes; for (i = 0; i < idp->idr_count; i++) { - if (nodes[i].data != NULL && nodes[i].allocated > 0) { + if (nodes[i].data != NULL && nodes[i].used > 0) { error = fn(i, nodes[i].data, data); if (error != 0) break; } } + lwkt_reltoken(&idp->idr_token); return error; } --- a/sys/sys/idr.h +++ b/sys/sys/idr.h @@ -53,6 +53,7 @@ struct idr_node { void *data; int allocated; + int used; /* leaf id itself is allocated */ }; struct idr { @@ -76,6 +77,7 @@ int idr_pre_get(struct idr *idp, unsigned gfp_mask); void idr_init(struct idr *idp); +void *__idr_find(struct idr *idp, int id); int idr_alloc(struct idr *idp, void *ptr, int start, int end, unsigned gfp_mask); --- a/sys/dev/drm/include/linux/idr.h +++ b/sys/dev/drm/include/linux/idr.h @@ -109,7 +109,7 @@ lwkt_gettoken(&idp->idr_token); for (int id = *nextid; id < idp->idr_count; id++) { - res = idr_find(idp, id); + res = __idr_find(idp, id); if (res == NULL) continue; *nextid = id; |