Bug Summary

File:dev/pci/drm/dma-resv.c
Warning:line 529, column 26
Array access (from variable 'shared') results in a null pointer dereference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name dma-resv.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/dev/pci/drm/dma-resv.c
1/*
2 * Copyright (C) 2012-2014 Canonical Ltd (Maarten Lankhorst)
3 *
4 * Based on bo.c which bears the following copyright notice,
5 * but is dual licensed:
6 *
7 * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
8 * All Rights Reserved.
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the
12 * "Software"), to deal in the Software without restriction, including
13 * without limitation the rights to use, copy, modify, merge, publish,
14 * distribute, sub license, and/or sell copies of the Software, and to
15 * permit persons to whom the Software is furnished to do so, subject to
16 * the following conditions:
17 *
18 * The above copyright notice and this permission notice (including the
19 * next paragraph) shall be included in all copies or substantial portions
20 * of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
25 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
26 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
27 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
28 * USE OR OTHER DEALINGS IN THE SOFTWARE.
29 *
30 **************************************************************************/
31/*
32 * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
33 */
34
35#include <linux/dma-resv.h>
36#include <linux/export.h>
37#include <linux/sched/mm.h>
38
39/**
40 * DOC: Reservation Object Overview
41 *
42 * The reservation object provides a mechanism to manage shared and
43 * exclusive fences associated with a buffer. A reservation object
44 * can have attached one exclusive fence (normally associated with
45 * write operations) or N shared fences (read operations). The RCU
46 * mechanism is used to protect read access to fences from locked
47 * write-side updates.
48 */
49
50DEFINE_WD_CLASS(reservation_ww_class)struct ww_class reservation_ww_class = { .stamp = 0, .name = "reservation_ww_class"
}
;
51EXPORT_SYMBOL(reservation_ww_class);
52
53struct lock_class_key reservation_seqcount_class;
54EXPORT_SYMBOL(reservation_seqcount_class);
55
56const char reservation_seqcount_string[] = "reservation_seqcount";
57EXPORT_SYMBOL(reservation_seqcount_string);
58
59/**
60 * dma_resv_list_alloc - allocate fence list
61 * @shared_max: number of fences we need space for
62 *
63 * Allocate a new dma_resv_list and make sure to correctly initialize
64 * shared_max.
65 */
66static struct dma_resv_list *dma_resv_list_alloc(unsigned int shared_max)
67{
68 struct dma_resv_list *list;
69
70 list = kmalloc(offsetof(typeof(*list), shared[shared_max])__builtin_offsetof(typeof(*list), shared[shared_max]), GFP_KERNEL(0x0001 | 0x0004));
71 if (!list)
72 return NULL((void *)0);
73
74#ifdef __linux__
75 list->shared_max = (ksize(list) - offsetof(typeof(*list), shared)__builtin_offsetof(typeof(*list), shared)) /
76 sizeof(*list->shared);
77#else
78 list->shared_max = (offsetof(typeof(*list), shared[shared_max])__builtin_offsetof(typeof(*list), shared[shared_max]) -
79 offsetof(typeof(*list), shared)__builtin_offsetof(typeof(*list), shared)) / sizeof(*list->shared);
80#endif
81
82 return list;
83}
84
85/**
86 * dma_resv_list_free - free fence list
87 * @list: list to free
88 *
89 * Free a dma_resv_list and make sure to drop all references.
90 */
91static void dma_resv_list_free(struct dma_resv_list *list)
92{
93 unsigned int i;
94
95 if (!list)
96 return;
97
98 for (i = 0; i < list->shared_count; ++i)
99 dma_fence_put(rcu_dereference_protected(list->shared[i], true)(list->shared[i]));
100
101 kfree_rcu(list, rcu)do { free((void *)list, 145, 0); } while(0);
102}
103
104#if IS_ENABLED(CONFIG_LOCKDEP)0
105static int __init dma_resv_lockdep(void)
106{
107 struct mm_struct *mm = mm_alloc();
108 struct ww_acquire_ctx ctx;
109 struct dma_resv obj;
110 int ret;
111
112 if (!mm)
113 return -ENOMEM12;
114
115 dma_resv_init(&obj);
116
117 down_read(&mm->mmap_sem)rw_enter_read(&mm->mmap_sem);
118 ww_acquire_init(&ctx, &reservation_ww_class);
119 ret = dma_resv_lock(&obj, &ctx);
120 if (ret == -EDEADLK11)
121 dma_resv_lock_slow(&obj, &ctx);
122 fs_reclaim_acquire(GFP_KERNEL(0x0001 | 0x0004));
123 fs_reclaim_release(GFP_KERNEL(0x0001 | 0x0004));
124 ww_mutex_unlock(&obj.lock);
125 ww_acquire_fini(&ctx);
126 up_read(&mm->mmap_sem)rw_exit_read(&mm->mmap_sem);
127
128 mmput(mm);
129
130 return 0;
131}
132subsys_initcall(dma_resv_lockdep);
133#endif
134
135/**
136 * dma_resv_init - initialize a reservation object
137 * @obj: the reservation object
138 */
139void dma_resv_init(struct dma_resv *obj)
140{
141 ww_mutex_init(&obj->lock, &reservation_ww_class);
142
143 __seqcount_init(&obj->seq, reservation_seqcount_string,
144 &reservation_seqcount_class);
145 RCU_INIT_POINTER(obj->fence, NULL)do { (obj->fence) = (((void *)0)); } while(0);
146 RCU_INIT_POINTER(obj->fence_excl, NULL)do { (obj->fence_excl) = (((void *)0)); } while(0);
147}
148EXPORT_SYMBOL(dma_resv_init);
149
150/**
151 * dma_resv_fini - destroys a reservation object
152 * @obj: the reservation object
153 */
154void dma_resv_fini(struct dma_resv *obj)
155{
156 struct dma_resv_list *fobj;
157 struct dma_fence *excl;
158
159 /*
160 * This object should be dead and all references must have
161 * been released to it, so no need to be protected with rcu.
162 */
163 excl = rcu_dereference_protected(obj->fence_excl, 1)(obj->fence_excl);
164 if (excl)
165 dma_fence_put(excl);
166
167 fobj = rcu_dereference_protected(obj->fence, 1)(obj->fence);
168 dma_resv_list_free(fobj);
169 ww_mutex_destroy(&obj->lock);
170}
171EXPORT_SYMBOL(dma_resv_fini);
172
173/**
174 * dma_resv_reserve_shared - Reserve space to add shared fences to
175 * a dma_resv.
176 * @obj: reservation object
177 * @num_fences: number of fences we want to add
178 *
179 * Should be called before dma_resv_add_shared_fence(). Must
180 * be called with obj->lock held.
181 *
182 * RETURNS
183 * Zero for success, or -errno
184 */
185int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences)
186{
187 struct dma_resv_list *old, *new;
188 unsigned int i, j, k, max;
189
190 dma_resv_assert_held(obj)do { (void)(&(obj)->lock.base); } while(0);
191
192 old = dma_resv_get_list(obj);
193
194 if (old && old->shared_max) {
195 if ((old->shared_count + num_fences) <= old->shared_max)
196 return 0;
197 else
198 max = max(old->shared_count + num_fences,(((old->shared_count + num_fences)>(old->shared_max *
2))?(old->shared_count + num_fences):(old->shared_max *
2))
199 old->shared_max * 2)(((old->shared_count + num_fences)>(old->shared_max *
2))?(old->shared_count + num_fences):(old->shared_max *
2))
;
200 } else {
201 max = 4;
202 }
203
204 new = dma_resv_list_alloc(max);
205 if (!new)
206 return -ENOMEM12;
207
208 /*
209 * no need to bump fence refcounts, rcu_read access
210 * requires the use of kref_get_unless_zero, and the
211 * references from the old struct are carried over to
212 * the new.
213 */
214 for (i = 0, j = 0, k = max; i < (old ? old->shared_count : 0); ++i) {
215 struct dma_fence *fence;
216
217 fence = rcu_dereference_protected(old->shared[i],(old->shared[i])
218 dma_resv_held(obj))(old->shared[i]);
219 if (dma_fence_is_signaled(fence))
220 RCU_INIT_POINTER(new->shared[--k], fence)do { (new->shared[--k]) = (fence); } while(0);
221 else
222 RCU_INIT_POINTER(new->shared[j++], fence)do { (new->shared[j++]) = (fence); } while(0);
223 }
224 new->shared_count = j;
225
226 /*
227 * We are not changing the effective set of fences here so can
228 * merely update the pointer to the new array; both existing
229 * readers and new readers will see exactly the same set of
230 * active (unsignaled) shared fences. Individual fences and the
231 * old array are protected by RCU and so will not vanish under
232 * the gaze of the rcu_read_lock() readers.
233 */
234 rcu_assign_pointer(obj->fence, new)do { (obj->fence) = (new); } while(0);
235
236 if (!old)
237 return 0;
238
239 /* Drop the references to the signaled fences */
240 for (i = k; i < max; ++i) {
241 struct dma_fence *fence;
242
243 fence = rcu_dereference_protected(new->shared[i],(new->shared[i])
244 dma_resv_held(obj))(new->shared[i]);
245 dma_fence_put(fence);
246 }
247 kfree_rcu(old, rcu)do { free((void *)old, 145, 0); } while(0);
248
249 return 0;
250}
251EXPORT_SYMBOL(dma_resv_reserve_shared);
252
253/**
254 * dma_resv_add_shared_fence - Add a fence to a shared slot
255 * @obj: the reservation object
256 * @fence: the shared fence to add
257 *
258 * Add a fence to a shared slot, obj->lock must be held, and
259 * dma_resv_reserve_shared() has been called.
260 */
261void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
262{
263 struct dma_resv_list *fobj;
264 struct dma_fence *old;
265 unsigned int i, count;
266
267 dma_fence_get(fence);
268
269 dma_resv_assert_held(obj)do { (void)(&(obj)->lock.base); } while(0);
270
271 fobj = dma_resv_get_list(obj);
272 count = fobj->shared_count;
273
274 preempt_disable();
275 write_seqcount_begin(&obj->seq);
276
277 for (i = 0; i < count; ++i) {
278
279 old = rcu_dereference_protected(fobj->shared[i],(fobj->shared[i])
280 dma_resv_held(obj))(fobj->shared[i]);
281 if (old->context == fence->context ||
282 dma_fence_is_signaled(old))
283 goto replace;
284 }
285
286 BUG_ON(fobj->shared_count >= fobj->shared_max)((!(fobj->shared_count >= fobj->shared_max)) ? (void
)0 : __assert("diagnostic ", "/usr/src/sys/dev/pci/drm/dma-resv.c"
, 286, "!(fobj->shared_count >= fobj->shared_max)"))
;
287 old = NULL((void *)0);
288 count++;
289
290replace:
291 RCU_INIT_POINTER(fobj->shared[i], fence)do { (fobj->shared[i]) = (fence); } while(0);
292 /* pointer update must be visible before we extend the shared_count */
293 smp_store_mb(fobj->shared_count, count)do { fobj->shared_count = count; do { __asm volatile("mfence"
::: "memory"); } while (0); } while (0)
;
294
295 write_seqcount_end(&obj->seq);
296 preempt_enable();
297 dma_fence_put(old);
298}
299EXPORT_SYMBOL(dma_resv_add_shared_fence);
300
301/**
302 * dma_resv_add_excl_fence - Add an exclusive fence.
303 * @obj: the reservation object
304 * @fence: the shared fence to add
305 *
306 * Add a fence to the exclusive slot. The obj->lock must be held.
307 */
308void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence)
309{
310 struct dma_fence *old_fence = dma_resv_get_excl(obj);
311 struct dma_resv_list *old;
312 u32 i = 0;
313
314 dma_resv_assert_held(obj)do { (void)(&(obj)->lock.base); } while(0);
315
316 old = dma_resv_get_list(obj);
317 if (old)
318 i = old->shared_count;
319
320 if (fence)
321 dma_fence_get(fence);
322
323 preempt_disable();
324 write_seqcount_begin(&obj->seq);
325 /* write_seqcount_begin provides the necessary memory barrier */
326 RCU_INIT_POINTER(obj->fence_excl, fence)do { (obj->fence_excl) = (fence); } while(0);
327 if (old)
328 old->shared_count = 0;
329 write_seqcount_end(&obj->seq);
330 preempt_enable();
331
332 /* inplace update, no shared fences */
333 while (i--)
334 dma_fence_put(rcu_dereference_protected(old->shared[i],(old->shared[i])
335 dma_resv_held(obj))(old->shared[i]));
336
337 dma_fence_put(old_fence);
338}
339EXPORT_SYMBOL(dma_resv_add_excl_fence);
340
341/**
342* dma_resv_copy_fences - Copy all fences from src to dst.
343* @dst: the destination reservation object
344* @src: the source reservation object
345*
346* Copy all fences from src to dst. dst-lock must be held.
347*/
348int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src)
349{
350 struct dma_resv_list *src_list, *dst_list;
351 struct dma_fence *old, *new;
352 unsigned i;
353
354 dma_resv_assert_held(dst)do { (void)(&(dst)->lock.base); } while(0);
355
356 rcu_read_lock();
357 src_list = rcu_dereference(src->fence)(src->fence);
358
359retry:
360 if (src_list) {
361 unsigned shared_count = src_list->shared_count;
362
363 rcu_read_unlock();
364
365 dst_list = dma_resv_list_alloc(shared_count);
366 if (!dst_list)
367 return -ENOMEM12;
368
369 rcu_read_lock();
370 src_list = rcu_dereference(src->fence)(src->fence);
371 if (!src_list || src_list->shared_count > shared_count) {
372 kfree(dst_list);
373 goto retry;
374 }
375
376 dst_list->shared_count = 0;
377 for (i = 0; i < src_list->shared_count; ++i) {
378 struct dma_fence *fence;
379
380 fence = rcu_dereference(src_list->shared[i])(src_list->shared[i]);
381 if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
382 &fence->flags))
383 continue;
384
385 if (!dma_fence_get_rcu(fence)) {
386 dma_resv_list_free(dst_list);
387 src_list = rcu_dereference(src->fence)(src->fence);
388 goto retry;
389 }
390
391 if (dma_fence_is_signaled(fence)) {
392 dma_fence_put(fence);
393 continue;
394 }
395
396 rcu_assign_pointer(dst_list->shared[dst_list->shared_count++], fence)do { (dst_list->shared[dst_list->shared_count++]) = (fence
); } while(0)
;
397 }
398 } else {
399 dst_list = NULL((void *)0);
400 }
401
402 new = dma_fence_get_rcu_safe(&src->fence_excl);
403 rcu_read_unlock();
404
405 src_list = dma_resv_get_list(dst);
406 old = dma_resv_get_excl(dst);
407
408 preempt_disable();
409 write_seqcount_begin(&dst->seq);
410 /* write_seqcount_begin provides the necessary memory barrier */
411 RCU_INIT_POINTER(dst->fence_excl, new)do { (dst->fence_excl) = (new); } while(0);
412 RCU_INIT_POINTER(dst->fence, dst_list)do { (dst->fence) = (dst_list); } while(0);
413 write_seqcount_end(&dst->seq);
414 preempt_enable();
415
416 dma_resv_list_free(src_list);
417 dma_fence_put(old);
418
419 return 0;
420}
421EXPORT_SYMBOL(dma_resv_copy_fences);
422
423/**
424 * dma_resv_get_fences_rcu - Get an object's shared and exclusive
425 * fences without update side lock held
426 * @obj: the reservation object
427 * @pfence_excl: the returned exclusive fence (or NULL)
428 * @pshared_count: the number of shared fences returned
429 * @pshared: the array of shared fence ptrs returned (array is krealloc'd to
430 * the required size, and must be freed by caller)
431 *
432 * Retrieve all fences from the reservation object. If the pointer for the
433 * exclusive fence is not specified the fence is put into the array of the
434 * shared fences as well. Returns either zero or -ENOMEM.
435 */
436int dma_resv_get_fences_rcu(struct dma_resv *obj,
437 struct dma_fence **pfence_excl,
438 unsigned *pshared_count,
439 struct dma_fence ***pshared)
440{
441 struct dma_fence **shared = NULL((void *)0);
1
'shared' initialized to a null pointer value
442 struct dma_fence *fence_excl;
443 unsigned int shared_count;
444 int ret = 1;
445
446 do {
12
Loop condition is false. Exiting loop
447 struct dma_resv_list *fobj;
448 unsigned int i, seq;
449 size_t sz = 0;
450
451 shared_count = i = 0;
452
453 rcu_read_lock();
454 seq = read_seqcount_begin(&obj->seq);
455
456 fence_excl = rcu_dereference(obj->fence_excl)(obj->fence_excl);
457 if (fence_excl && !dma_fence_get_rcu(fence_excl))
2
Assuming 'fence_excl' is non-null
3
Assuming the condition is false
4
Taking false branch
458 goto unlock;
459
460 fobj = rcu_dereference(obj->fence)(obj->fence);
461 if (fobj)
5
Assuming 'fobj' is non-null
6
Taking true branch
462 sz += sizeof(*shared) * fobj->shared_max;
463
464 if (!pfence_excl && fence_excl
7.1
'fence_excl' is non-null
)
7
Assuming 'pfence_excl' is null
8
Taking true branch
465 sz += sizeof(*shared);
466
467 if (sz) {
9
Assuming 'sz' is 0
10
Taking false branch
468 struct dma_fence **nshared;
469
470#ifdef __linux__
471 nshared = krealloc(shared, sz,
472 GFP_NOWAIT0x0002 | __GFP_NOWARN0);
473#else
474 nshared = kmalloc(sz, GFP_NOWAIT0x0002 | __GFP_NOWARN0);
475 if (nshared != NULL((void *)0) && shared != NULL((void *)0))
476 memcpy(nshared, shared, sz)__builtin_memcpy((nshared), (shared), (sz));
477 if (nshared) {
478 kfree(shared);
479 shared = NULL((void *)0);
480 }
481#endif
482 if (!nshared) {
483 rcu_read_unlock();
484
485 dma_fence_put(fence_excl);
486 fence_excl = NULL((void *)0);
487
488#ifdef __linux__
489 nshared = krealloc(shared, sz, GFP_KERNEL(0x0001 | 0x0004));
490#else
491 nshared = kmalloc(sz, GFP_KERNEL(0x0001 | 0x0004));
492 if (nshared != NULL((void *)0) && shared != NULL((void *)0))
493 memcpy(nshared, shared, sz)__builtin_memcpy((nshared), (shared), (sz));
494 kfree(shared);
495 shared = NULL((void *)0);
496#endif
497 if (nshared) {
498 shared = nshared;
499 continue;
500 }
501
502 ret = -ENOMEM12;
503 break;
504 }
505 shared = nshared;
506 shared_count = fobj ? fobj->shared_count : 0;
507 for (i = 0; i < shared_count; ++i) {
508 shared[i] = rcu_dereference(fobj->shared[i])(fobj->shared[i]);
509 if (!dma_fence_get_rcu(shared[i]))
510 break;
511 }
512 }
513
514 if (i
10.1
'i' is equal to 'shared_count'
!= shared_count || read_seqcount_retry(&obj->seq, seq)) {
11
Taking false branch
515 while (i--)
516 dma_fence_put(shared[i]);
517 dma_fence_put(fence_excl);
518 goto unlock;
519 }
520
521 ret = 0;
522unlock:
523 rcu_read_unlock();
524 } while (ret);
525
526 if (pfence_excl
12.1
'pfence_excl' is null
)
13
Taking false branch
527 *pfence_excl = fence_excl;
528 else if (fence_excl
13.1
'fence_excl' is non-null
)
14
Taking true branch
529 shared[shared_count++] = fence_excl;
15
Array access (from variable 'shared') results in a null pointer dereference
530
531 if (!shared_count) {
532 kfree(shared);
533 shared = NULL((void *)0);
534 }
535
536 *pshared_count = shared_count;
537 *pshared = shared;
538 return ret;
539}
540EXPORT_SYMBOL_GPL(dma_resv_get_fences_rcu);
541
542/**
543 * dma_resv_wait_timeout_rcu - Wait on reservation's objects
544 * shared and/or exclusive fences.
545 * @obj: the reservation object
546 * @wait_all: if true, wait on all fences, else wait on just exclusive fence
547 * @intr: if true, do interruptible wait
548 * @timeout: timeout value in jiffies or zero to return immediately
549 *
550 * RETURNS
551 * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
552 * greater than zer on success.
553 */
554long dma_resv_wait_timeout_rcu(struct dma_resv *obj,
555 bool_Bool wait_all, bool_Bool intr,
556 unsigned long timeout)
557{
558 struct dma_fence *fence;
559 unsigned seq, shared_count;
560 long ret = timeout ? timeout : 1;
561 int i;
562
563retry:
564 shared_count = 0;
565 seq = read_seqcount_begin(&obj->seq);
566 rcu_read_lock();
567 i = -1;
568
569 fence = rcu_dereference(obj->fence_excl)(obj->fence_excl);
570 if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
571 if (!dma_fence_get_rcu(fence))
572 goto unlock_retry;
573
574 if (dma_fence_is_signaled(fence)) {
575 dma_fence_put(fence);
576 fence = NULL((void *)0);
577 }
578
579 } else {
580 fence = NULL((void *)0);
581 }
582
583 if (wait_all) {
584 struct dma_resv_list *fobj = rcu_dereference(obj->fence)(obj->fence);
585
586 if (fobj)
587 shared_count = fobj->shared_count;
588
589 for (i = 0; !fence && i < shared_count; ++i) {
590 struct dma_fence *lfence = rcu_dereference(fobj->shared[i])(fobj->shared[i]);
591
592 if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
593 &lfence->flags))
594 continue;
595
596 if (!dma_fence_get_rcu(lfence))
597 goto unlock_retry;
598
599 if (dma_fence_is_signaled(lfence)) {
600 dma_fence_put(lfence);
601 continue;
602 }
603
604 fence = lfence;
605 break;
606 }
607 }
608
609 rcu_read_unlock();
610 if (fence) {
611 if (read_seqcount_retry(&obj->seq, seq)) {
612 dma_fence_put(fence);
613 goto retry;
614 }
615
616 ret = dma_fence_wait_timeout(fence, intr, ret);
617 dma_fence_put(fence);
618 if (ret > 0 && wait_all && (i + 1 < shared_count))
619 goto retry;
620 }
621 return ret;
622
623unlock_retry:
624 rcu_read_unlock();
625 goto retry;
626}
627EXPORT_SYMBOL_GPL(dma_resv_wait_timeout_rcu);
628
629
630static inline int dma_resv_test_signaled_single(struct dma_fence *passed_fence)
631{
632 struct dma_fence *fence, *lfence = passed_fence;
633 int ret = 1;
634
635 if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &lfence->flags)) {
636 fence = dma_fence_get_rcu(lfence);
637 if (!fence)
638 return -1;
639
640 ret = !!dma_fence_is_signaled(fence);
641 dma_fence_put(fence);
642 }
643 return ret;
644}
645
646/**
647 * dma_resv_test_signaled_rcu - Test if a reservation object's
648 * fences have been signaled.
649 * @obj: the reservation object
650 * @test_all: if true, test all fences, otherwise only test the exclusive
651 * fence
652 *
653 * RETURNS
654 * true if all fences signaled, else false
655 */
656bool_Bool dma_resv_test_signaled_rcu(struct dma_resv *obj, bool_Bool test_all)
657{
658 unsigned seq, shared_count;
659 int ret;
660
661 rcu_read_lock();
662retry:
663 ret = true1;
664 shared_count = 0;
665 seq = read_seqcount_begin(&obj->seq);
666
667 if (test_all) {
668 unsigned i;
669
670 struct dma_resv_list *fobj = rcu_dereference(obj->fence)(obj->fence);
671
672 if (fobj)
673 shared_count = fobj->shared_count;
674
675 for (i = 0; i < shared_count; ++i) {
676 struct dma_fence *fence = rcu_dereference(fobj->shared[i])(fobj->shared[i]);
677
678 ret = dma_resv_test_signaled_single(fence);
679 if (ret < 0)
680 goto retry;
681 else if (!ret)
682 break;
683 }
684
685 if (read_seqcount_retry(&obj->seq, seq))
686 goto retry;
687 }
688
689 if (!shared_count) {
690 struct dma_fence *fence_excl = rcu_dereference(obj->fence_excl)(obj->fence_excl);
691
692 if (fence_excl) {
693 ret = dma_resv_test_signaled_single(fence_excl);
694 if (ret < 0)
695 goto retry;
696
697 if (read_seqcount_retry(&obj->seq, seq))
698 goto retry;
699 }
700 }
701
702 rcu_read_unlock();
703 return ret;
704}
705EXPORT_SYMBOL_GPL(dma_resv_test_signaled_rcu);