Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dma-buf: remove shared fence staging in reservation object

No need for that any more. Just replace the list when there isn't enough
room any more for the additional fence.

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com>
Reviewed-by: Huang Rui <ray.huang@amd.com>
Link: https://patchwork.kernel.org/patch/10626143/

+58 -124
+58 -120
drivers/dma-buf/reservation.c
··· 68 68 */ 69 69 int reservation_object_reserve_shared(struct reservation_object *obj) 70 70 { 71 - struct reservation_object_list *fobj, *old; 72 - u32 max; 71 + struct reservation_object_list *old, *new; 72 + unsigned int i, j, k, max; 73 73 74 74 old = reservation_object_get_list(obj); 75 75 76 76 if (old && old->shared_max) { 77 - if (old->shared_count < old->shared_max) { 78 - /* perform an in-place update */ 79 - kfree(obj->staged); 80 - obj->staged = NULL; 77 + if (old->shared_count < old->shared_max) 81 78 return 0; 82 - } else 79 + else 83 80 max = old->shared_max * 2; 84 - } else 85 - max = 4; 86 - 87 - /* 88 - * resize obj->staged or allocate if it doesn't exist, 89 - * noop if already correct size 90 - */ 91 - fobj = krealloc(obj->staged, offsetof(typeof(*fobj), shared[max]), 92 - GFP_KERNEL); 93 - if (!fobj) 94 - return -ENOMEM; 95 - 96 - obj->staged = fobj; 97 - fobj->shared_max = max; 98 - return 0; 99 - } 100 - EXPORT_SYMBOL(reservation_object_reserve_shared); 101 - 102 - static void 103 - reservation_object_add_shared_inplace(struct reservation_object *obj, 104 - struct reservation_object_list *fobj, 105 - struct dma_fence *fence) 106 - { 107 - struct dma_fence *signaled = NULL; 108 - u32 i, signaled_idx; 109 - 110 - dma_fence_get(fence); 111 - 112 - preempt_disable(); 113 - write_seqcount_begin(&obj->seq); 114 - 115 - for (i = 0; i < fobj->shared_count; ++i) { 116 - struct dma_fence *old_fence; 117 - 118 - old_fence = rcu_dereference_protected(fobj->shared[i], 119 - reservation_object_held(obj)); 120 - 121 - if (old_fence->context == fence->context) { 122 - /* memory barrier is added by write_seqcount_begin */ 123 - RCU_INIT_POINTER(fobj->shared[i], fence); 124 - write_seqcount_end(&obj->seq); 125 - preempt_enable(); 126 - 127 - dma_fence_put(old_fence); 128 - return; 129 - } 130 - 131 - if (!signaled && dma_fence_is_signaled(old_fence)) { 132 - signaled = old_fence; 133 - signaled_idx = i; 134 - } 135 - } 136 - 137 - /* 138 - * memory barrier is added by write_seqcount_begin, 139 - * fobj->shared_count is protected by this lock too 140 - */ 141 - if (signaled) { 142 - RCU_INIT_POINTER(fobj->shared[signaled_idx], fence); 143 81 } else { 144 - BUG_ON(fobj->shared_count >= fobj->shared_max); 145 - RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence); 146 - fobj->shared_count++; 82 + max = 4; 147 83 } 148 84 149 - write_seqcount_end(&obj->seq); 150 - preempt_enable(); 151 - 152 - dma_fence_put(signaled); 153 - } 154 - 155 - static void 156 - reservation_object_add_shared_replace(struct reservation_object *obj, 157 - struct reservation_object_list *old, 158 - struct reservation_object_list *fobj, 159 - struct dma_fence *fence) 160 - { 161 - unsigned i, j, k; 162 - 163 - dma_fence_get(fence); 164 - 165 - if (!old) { 166 - RCU_INIT_POINTER(fobj->shared[0], fence); 167 - fobj->shared_count = 1; 168 - goto done; 169 - } 85 + new = kmalloc(offsetof(typeof(*new), shared[max]), GFP_KERNEL); 86 + if (!new) 87 + return -ENOMEM; 170 88 171 89 /* 172 90 * no need to bump fence refcounts, rcu_read access ··· 92 174 * references from the old struct are carried over to 93 175 * the new. 94 176 */ 95 - for (i = 0, j = 0, k = fobj->shared_max; i < old->shared_count; ++i) { 96 - struct dma_fence *check; 177 + for (i = 0, j = 0, k = max; i < (old ? old->shared_count : 0); ++i) { 178 + struct dma_fence *fence; 97 179 98 - check = rcu_dereference_protected(old->shared[i], 99 - reservation_object_held(obj)); 100 - 101 - if (check->context == fence->context || 102 - dma_fence_is_signaled(check)) 103 - RCU_INIT_POINTER(fobj->shared[--k], check); 180 + fence = rcu_dereference_protected(old->shared[i], 181 + reservation_object_held(obj)); 182 + if (dma_fence_is_signaled(fence)) 183 + RCU_INIT_POINTER(new->shared[--k], fence); 104 184 else 105 - RCU_INIT_POINTER(fobj->shared[j++], check); 185 + RCU_INIT_POINTER(new->shared[j++], fence); 106 186 } 107 - fobj->shared_count = j; 108 - RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence); 109 - fobj->shared_count++; 187 + new->shared_count = j; 188 + new->shared_max = max; 110 189 111 - done: 112 190 preempt_disable(); 113 191 write_seqcount_begin(&obj->seq); 114 192 /* 115 193 * RCU_INIT_POINTER can be used here, 116 194 * seqcount provides the necessary barriers 117 195 */ 118 - RCU_INIT_POINTER(obj->fence, fobj); 196 + RCU_INIT_POINTER(obj->fence, new); 119 197 write_seqcount_end(&obj->seq); 120 198 preempt_enable(); 121 199 122 200 if (!old) 123 - return; 201 + return 0; 124 202 125 203 /* Drop the references to the signaled fences */ 126 - for (i = k; i < fobj->shared_max; ++i) { 127 - struct dma_fence *f; 204 + for (i = k; i < new->shared_max; ++i) { 205 + struct dma_fence *fence; 128 206 129 - f = rcu_dereference_protected(fobj->shared[i], 130 - reservation_object_held(obj)); 131 - dma_fence_put(f); 207 + fence = rcu_dereference_protected(new->shared[i], 208 + reservation_object_held(obj)); 209 + dma_fence_put(fence); 132 210 } 133 211 kfree_rcu(old, rcu); 212 + 213 + return 0; 134 214 } 215 + EXPORT_SYMBOL(reservation_object_reserve_shared); 135 216 136 217 /** 137 218 * reservation_object_add_shared_fence - Add a fence to a shared slot ··· 143 226 void reservation_object_add_shared_fence(struct reservation_object *obj, 144 227 struct dma_fence *fence) 145 228 { 146 - struct reservation_object_list *old, *fobj = obj->staged; 229 + struct reservation_object_list *fobj; 230 + unsigned int i; 147 231 148 - old = reservation_object_get_list(obj); 149 - obj->staged = NULL; 232 + dma_fence_get(fence); 150 233 151 - if (!fobj) 152 - reservation_object_add_shared_inplace(obj, old, fence); 153 - else 154 - reservation_object_add_shared_replace(obj, old, fobj, fence); 234 + fobj = reservation_object_get_list(obj); 235 + 236 + preempt_disable(); 237 + write_seqcount_begin(&obj->seq); 238 + 239 + for (i = 0; i < fobj->shared_count; ++i) { 240 + struct dma_fence *old_fence; 241 + 242 + old_fence = rcu_dereference_protected(fobj->shared[i], 243 + reservation_object_held(obj)); 244 + if (old_fence->context == fence->context || 245 + dma_fence_is_signaled(old_fence)) { 246 + dma_fence_put(old_fence); 247 + goto replace; 248 + } 249 + } 250 + 251 + BUG_ON(fobj->shared_count >= fobj->shared_max); 252 + fobj->shared_count++; 253 + 254 + replace: 255 + /* 256 + * memory barrier is added by write_seqcount_begin, 257 + * fobj->shared_count is protected by this lock too 258 + */ 259 + RCU_INIT_POINTER(fobj->shared[i], fence); 260 + write_seqcount_end(&obj->seq); 261 + preempt_enable(); 155 262 } 156 263 EXPORT_SYMBOL(reservation_object_add_shared_fence); 157 264 ··· 283 342 284 343 new = dma_fence_get_rcu_safe(&src->fence_excl); 285 344 rcu_read_unlock(); 286 - 287 - kfree(dst->staged); 288 - dst->staged = NULL; 289 345 290 346 src_list = reservation_object_get_list(dst); 291 347 old = reservation_object_get_excl(dst);
-4
include/linux/reservation.h
··· 68 68 * @seq: sequence count for managing RCU read-side synchronization 69 69 * @fence_excl: the exclusive fence, if there is one currently 70 70 * @fence: list of current shared fences 71 - * @staged: staged copy of shared fences for RCU updates 72 71 */ 73 72 struct reservation_object { 74 73 struct ww_mutex lock; ··· 75 76 76 77 struct dma_fence __rcu *fence_excl; 77 78 struct reservation_object_list __rcu *fence; 78 - struct reservation_object_list *staged; 79 79 }; 80 80 81 81 #define reservation_object_held(obj) lockdep_is_held(&(obj)->lock.base) ··· 93 95 __seqcount_init(&obj->seq, reservation_seqcount_string, &reservation_seqcount_class); 94 96 RCU_INIT_POINTER(obj->fence, NULL); 95 97 RCU_INIT_POINTER(obj->fence_excl, NULL); 96 - obj->staged = NULL; 97 98 } 98 99 99 100 /** ··· 121 124 122 125 kfree(fobj); 123 126 } 124 - kfree(obj->staged); 125 127 126 128 ww_mutex_destroy(&obj->lock); 127 129 }