]>
Commit | Line | Data |
---|---|---|
9c92ab61 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
d4cab38e GP |
2 | /* |
3 | * drivers/dma-buf/sync_file.c | |
4 | * | |
5 | * Copyright (C) 2012 Google, Inc. | |
d4cab38e GP |
6 | */ |
7 | ||
8 | #include <linux/export.h> | |
9 | #include <linux/file.h> | |
10 | #include <linux/fs.h> | |
11 | #include <linux/kernel.h> | |
12 | #include <linux/poll.h> | |
13 | #include <linux/sched.h> | |
14 | #include <linux/slab.h> | |
15 | #include <linux/uaccess.h> | |
16 | #include <linux/anon_inodes.h> | |
460bfc41 GP |
17 | #include <linux/sync_file.h> |
18 | #include <uapi/linux/sync_file.h> | |
d4cab38e GP |
19 | |
20 | static const struct file_operations sync_file_fops; | |
21 | ||
a02b9dc9 | 22 | static struct sync_file *sync_file_alloc(void) |
d4cab38e GP |
23 | { |
24 | struct sync_file *sync_file; | |
25 | ||
a02b9dc9 | 26 | sync_file = kzalloc(sizeof(*sync_file), GFP_KERNEL); |
d4cab38e GP |
27 | if (!sync_file) |
28 | return NULL; | |
29 | ||
30 | sync_file->file = anon_inode_getfile("sync_file", &sync_file_fops, | |
31 | sync_file, 0); | |
32 | if (IS_ERR(sync_file->file)) | |
33 | goto err; | |
34 | ||
d4cab38e GP |
35 | init_waitqueue_head(&sync_file->wq); |
36 | ||
a02b9dc9 GP |
37 | INIT_LIST_HEAD(&sync_file->cb.node); |
38 | ||
d4cab38e GP |
39 | return sync_file; |
40 | ||
41 | err: | |
42 | kfree(sync_file); | |
43 | return NULL; | |
44 | } | |
45 | ||
f54d1867 | 46 | static void fence_check_cb_func(struct dma_fence *f, struct dma_fence_cb *cb) |
d4cab38e | 47 | { |
d4cab38e GP |
48 | struct sync_file *sync_file; |
49 | ||
a02b9dc9 | 50 | sync_file = container_of(cb, struct sync_file, cb); |
d4cab38e | 51 | |
a02b9dc9 | 52 | wake_up_all(&sync_file->wq); |
d4cab38e GP |
53 | } |
54 | ||
55 | /** | |
c240a714 | 56 | * sync_file_create() - creates a sync file |
d4cab38e GP |
57 | * @fence: fence to add to the sync_fence |
58 | * | |
24a36734 DV |
59 | * Creates a sync_file containg @fence. This function acquires and additional |
60 | * reference of @fence for the newly-created &sync_file, if it succeeds. The | |
61 | * sync_file can be released with fput(sync_file->file). Returns the | |
62 | * sync_file or NULL in case of error. | |
d4cab38e | 63 | */ |
f54d1867 | 64 | struct sync_file *sync_file_create(struct dma_fence *fence) |
d4cab38e GP |
65 | { |
66 | struct sync_file *sync_file; | |
67 | ||
a02b9dc9 | 68 | sync_file = sync_file_alloc(); |
d4cab38e GP |
69 | if (!sync_file) |
70 | return NULL; | |
71 | ||
f54d1867 | 72 | sync_file->fence = dma_fence_get(fence); |
a02b9dc9 | 73 | |
d4cab38e GP |
74 | return sync_file; |
75 | } | |
76 | EXPORT_SYMBOL(sync_file_create); | |
77 | ||
d4cab38e GP |
78 | static struct sync_file *sync_file_fdget(int fd) |
79 | { | |
80 | struct file *file = fget(fd); | |
81 | ||
82 | if (!file) | |
83 | return NULL; | |
84 | ||
85 | if (file->f_op != &sync_file_fops) | |
86 | goto err; | |
87 | ||
88 | return file->private_data; | |
89 | ||
90 | err: | |
91 | fput(file); | |
92 | return NULL; | |
93 | } | |
94 | ||
972526a4 GP |
95 | /** |
96 | * sync_file_get_fence - get the fence related to the sync_file fd | |
97 | * @fd: sync_file fd to get the fence from | |
98 | * | |
99 | * Ensures @fd references a valid sync_file and returns a fence that | |
100 | * represents all fence in the sync_file. On error NULL is returned. | |
101 | */ | |
f54d1867 | 102 | struct dma_fence *sync_file_get_fence(int fd) |
972526a4 GP |
103 | { |
104 | struct sync_file *sync_file; | |
f54d1867 | 105 | struct dma_fence *fence; |
972526a4 GP |
106 | |
107 | sync_file = sync_file_fdget(fd); | |
108 | if (!sync_file) | |
109 | return NULL; | |
110 | ||
f54d1867 | 111 | fence = dma_fence_get(sync_file->fence); |
972526a4 GP |
112 | fput(sync_file->file); |
113 | ||
114 | return fence; | |
115 | } | |
116 | EXPORT_SYMBOL(sync_file_get_fence); | |
117 | ||
71ebc9a3 CW |
118 | /** |
119 | * sync_file_get_name - get the name of the sync_file | |
120 | * @sync_file: sync_file to get the fence from | |
121 | * @buf: destination buffer to copy sync_file name into | |
122 | * @len: available size of destination buffer. | |
123 | * | |
124 | * Each sync_file may have a name assigned either by the user (when merging | |
125 | * sync_files together) or created from the fence it contains. In the latter | |
126 | * case construction of the name is deferred until use, and so requires | |
127 | * sync_file_get_name(). | |
128 | * | |
129 | * Returns: a string representing the name. | |
130 | */ | |
131 | char *sync_file_get_name(struct sync_file *sync_file, char *buf, int len) | |
132 | { | |
133 | if (sync_file->user_name[0]) { | |
134 | strlcpy(buf, sync_file->user_name, len); | |
135 | } else { | |
136 | struct dma_fence *fence = sync_file->fence; | |
137 | ||
b312d8ca | 138 | snprintf(buf, len, "%s-%s%llu-%lld", |
71ebc9a3 CW |
139 | fence->ops->get_driver_name(fence), |
140 | fence->ops->get_timeline_name(fence), | |
141 | fence->context, | |
142 | fence->seqno); | |
143 | } | |
144 | ||
145 | return buf; | |
146 | } | |
147 | ||
a02b9dc9 | 148 | static int sync_file_set_fence(struct sync_file *sync_file, |
f54d1867 | 149 | struct dma_fence **fences, int num_fences) |
d4cab38e | 150 | { |
f54d1867 | 151 | struct dma_fence_array *array; |
a02b9dc9 GP |
152 | |
153 | /* | |
154 | * The reference for the fences in the new sync_file and held | |
155 | * in add_fence() during the merge procedure, so for num_fences == 1 | |
156 | * we already own a new reference to the fence. For num_fence > 1 | |
f54d1867 | 157 | * we own the reference of the dma_fence_array creation. |
a02b9dc9 GP |
158 | */ |
159 | if (num_fences == 1) { | |
160 | sync_file->fence = fences[0]; | |
c654dd07 | 161 | kfree(fences); |
a02b9dc9 | 162 | } else { |
f54d1867 CW |
163 | array = dma_fence_array_create(num_fences, fences, |
164 | dma_fence_context_alloc(1), | |
165 | 1, false); | |
a02b9dc9 GP |
166 | if (!array) |
167 | return -ENOMEM; | |
168 | ||
169 | sync_file->fence = &array->base; | |
170 | } | |
d4cab38e | 171 | |
a02b9dc9 GP |
172 | return 0; |
173 | } | |
174 | ||
f54d1867 CW |
175 | static struct dma_fence **get_fences(struct sync_file *sync_file, |
176 | int *num_fences) | |
a02b9dc9 | 177 | { |
f54d1867 CW |
178 | if (dma_fence_is_array(sync_file->fence)) { |
179 | struct dma_fence_array *array = to_dma_fence_array(sync_file->fence); | |
a02b9dc9 GP |
180 | |
181 | *num_fences = array->num_fences; | |
182 | return array->fences; | |
183 | } | |
184 | ||
185 | *num_fences = 1; | |
186 | return &sync_file->fence; | |
187 | } | |
188 | ||
f54d1867 CW |
189 | static void add_fence(struct dma_fence **fences, |
190 | int *i, struct dma_fence *fence) | |
a02b9dc9 GP |
191 | { |
192 | fences[*i] = fence; | |
193 | ||
f54d1867 CW |
194 | if (!dma_fence_is_signaled(fence)) { |
195 | dma_fence_get(fence); | |
d4cab38e GP |
196 | (*i)++; |
197 | } | |
198 | } | |
199 | ||
200 | /** | |
201 | * sync_file_merge() - merge two sync_files | |
202 | * @name: name of new fence | |
203 | * @a: sync_file a | |
204 | * @b: sync_file b | |
205 | * | |
206 | * Creates a new sync_file which contains copies of all the fences in both | |
207 | * @a and @b. @a and @b remain valid, independent sync_file. Returns the | |
208 | * new merged sync_file or NULL in case of error. | |
209 | */ | |
210 | static struct sync_file *sync_file_merge(const char *name, struct sync_file *a, | |
211 | struct sync_file *b) | |
212 | { | |
d4cab38e | 213 | struct sync_file *sync_file; |
f54d1867 | 214 | struct dma_fence **fences, **nfences, **a_fences, **b_fences; |
a02b9dc9 | 215 | int i, i_a, i_b, num_fences, a_num_fences, b_num_fences; |
d4cab38e | 216 | |
a02b9dc9 | 217 | sync_file = sync_file_alloc(); |
d4cab38e GP |
218 | if (!sync_file) |
219 | return NULL; | |
220 | ||
a02b9dc9 GP |
221 | a_fences = get_fences(a, &a_num_fences); |
222 | b_fences = get_fences(b, &b_num_fences); | |
223 | if (a_num_fences > INT_MAX - b_num_fences) | |
224 | return NULL; | |
225 | ||
226 | num_fences = a_num_fences + b_num_fences; | |
227 | ||
228 | fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL); | |
229 | if (!fences) | |
230 | goto err; | |
d4cab38e GP |
231 | |
232 | /* | |
233 | * Assume sync_file a and b are both ordered and have no | |
234 | * duplicates with the same context. | |
235 | * | |
236 | * If a sync_file can only be created with sync_file_merge | |
237 | * and sync_file_create, this is a reasonable assumption. | |
238 | */ | |
a02b9dc9 | 239 | for (i = i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) { |
f54d1867 CW |
240 | struct dma_fence *pt_a = a_fences[i_a]; |
241 | struct dma_fence *pt_b = b_fences[i_b]; | |
d4cab38e GP |
242 | |
243 | if (pt_a->context < pt_b->context) { | |
a02b9dc9 | 244 | add_fence(fences, &i, pt_a); |
d4cab38e GP |
245 | |
246 | i_a++; | |
247 | } else if (pt_a->context > pt_b->context) { | |
a02b9dc9 | 248 | add_fence(fences, &i, pt_b); |
d4cab38e GP |
249 | |
250 | i_b++; | |
251 | } else { | |
5e498abf CK |
252 | if (__dma_fence_is_later(pt_a->seqno, pt_b->seqno, |
253 | pt_a->ops)) | |
a02b9dc9 | 254 | add_fence(fences, &i, pt_a); |
d4cab38e | 255 | else |
a02b9dc9 | 256 | add_fence(fences, &i, pt_b); |
d4cab38e GP |
257 | |
258 | i_a++; | |
259 | i_b++; | |
260 | } | |
261 | } | |
262 | ||
a02b9dc9 GP |
263 | for (; i_a < a_num_fences; i_a++) |
264 | add_fence(fences, &i, a_fences[i_a]); | |
265 | ||
266 | for (; i_b < b_num_fences; i_b++) | |
267 | add_fence(fences, &i, b_fences[i_b]); | |
268 | ||
7cec540a | 269 | if (i == 0) |
f54d1867 | 270 | fences[i++] = dma_fence_get(a_fences[0]); |
d4cab38e | 271 | |
a02b9dc9 GP |
272 | if (num_fences > i) { |
273 | nfences = krealloc(fences, i * sizeof(*fences), | |
274 | GFP_KERNEL); | |
275 | if (!nfences) | |
276 | goto err; | |
277 | ||
278 | fences = nfences; | |
279 | } | |
280 | ||
281 | if (sync_file_set_fence(sync_file, fences, i) < 0) { | |
282 | kfree(fences); | |
283 | goto err; | |
284 | } | |
d4cab38e | 285 | |
71ebc9a3 | 286 | strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name)); |
d4cab38e | 287 | return sync_file; |
a02b9dc9 GP |
288 | |
289 | err: | |
290 | fput(sync_file->file); | |
291 | return NULL; | |
292 | ||
d4cab38e GP |
293 | } |
294 | ||
d8f2ebaa | 295 | static int sync_file_release(struct inode *inode, struct file *file) |
d4cab38e | 296 | { |
d8f2ebaa | 297 | struct sync_file *sync_file = file->private_data; |
d4cab38e | 298 | |
99f82843 | 299 | if (test_bit(POLL_ENABLED, &sync_file->flags)) |
f54d1867 CW |
300 | dma_fence_remove_callback(sync_file->fence, &sync_file->cb); |
301 | dma_fence_put(sync_file->fence); | |
d4cab38e | 302 | kfree(sync_file); |
d4cab38e | 303 | |
d4cab38e GP |
304 | return 0; |
305 | } | |
306 | ||
afc9a42b | 307 | static __poll_t sync_file_poll(struct file *file, poll_table *wait) |
d4cab38e GP |
308 | { |
309 | struct sync_file *sync_file = file->private_data; | |
d4cab38e GP |
310 | |
311 | poll_wait(file, &sync_file->wq, wait); | |
312 | ||
99f82843 CW |
313 | if (list_empty(&sync_file->cb.node) && |
314 | !test_and_set_bit(POLL_ENABLED, &sync_file->flags)) { | |
f54d1867 CW |
315 | if (dma_fence_add_callback(sync_file->fence, &sync_file->cb, |
316 | fence_check_cb_func) < 0) | |
e2416553 GP |
317 | wake_up_all(&sync_file->wq); |
318 | } | |
d4cab38e | 319 | |
a9a08845 | 320 | return dma_fence_is_signaled(sync_file->fence) ? EPOLLIN : 0; |
d4cab38e GP |
321 | } |
322 | ||
323 | static long sync_file_ioctl_merge(struct sync_file *sync_file, | |
92e06213 | 324 | unsigned long arg) |
d4cab38e GP |
325 | { |
326 | int fd = get_unused_fd_flags(O_CLOEXEC); | |
327 | int err; | |
328 | struct sync_file *fence2, *fence3; | |
329 | struct sync_merge_data data; | |
330 | ||
331 | if (fd < 0) | |
332 | return fd; | |
333 | ||
334 | if (copy_from_user(&data, (void __user *)arg, sizeof(data))) { | |
335 | err = -EFAULT; | |
336 | goto err_put_fd; | |
337 | } | |
338 | ||
339 | if (data.flags || data.pad) { | |
340 | err = -EINVAL; | |
341 | goto err_put_fd; | |
342 | } | |
343 | ||
344 | fence2 = sync_file_fdget(data.fd2); | |
345 | if (!fence2) { | |
346 | err = -ENOENT; | |
347 | goto err_put_fd; | |
348 | } | |
349 | ||
350 | data.name[sizeof(data.name) - 1] = '\0'; | |
351 | fence3 = sync_file_merge(data.name, sync_file, fence2); | |
352 | if (!fence3) { | |
353 | err = -ENOMEM; | |
354 | goto err_put_fence2; | |
355 | } | |
356 | ||
357 | data.fence = fd; | |
358 | if (copy_to_user((void __user *)arg, &data, sizeof(data))) { | |
359 | err = -EFAULT; | |
360 | goto err_put_fence3; | |
361 | } | |
362 | ||
363 | fd_install(fd, fence3->file); | |
364 | fput(fence2->file); | |
365 | return 0; | |
366 | ||
367 | err_put_fence3: | |
368 | fput(fence3->file); | |
369 | ||
370 | err_put_fence2: | |
371 | fput(fence2->file); | |
372 | ||
373 | err_put_fd: | |
374 | put_unused_fd(fd); | |
375 | return err; | |
376 | } | |
377 | ||
f7974880 | 378 | static int sync_fill_fence_info(struct dma_fence *fence, |
92e06213 | 379 | struct sync_fence_info *info) |
d4cab38e GP |
380 | { |
381 | strlcpy(info->obj_name, fence->ops->get_timeline_name(fence), | |
382 | sizeof(info->obj_name)); | |
383 | strlcpy(info->driver_name, fence->ops->get_driver_name(fence), | |
384 | sizeof(info->driver_name)); | |
d6c99f4b CW |
385 | |
386 | info->status = dma_fence_get_status(fence); | |
76250f2b CW |
387 | while (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) && |
388 | !test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags)) | |
389 | cpu_relax(); | |
390 | info->timestamp_ns = | |
391 | test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags) ? | |
392 | ktime_to_ns(fence->timestamp) : | |
393 | ktime_set(0, 0); | |
f7974880 JER |
394 | |
395 | return info->status; | |
d4cab38e GP |
396 | } |
397 | ||
398 | static long sync_file_ioctl_fence_info(struct sync_file *sync_file, | |
92e06213 | 399 | unsigned long arg) |
d4cab38e GP |
400 | { |
401 | struct sync_file_info info; | |
402 | struct sync_fence_info *fence_info = NULL; | |
f54d1867 | 403 | struct dma_fence **fences; |
d4cab38e | 404 | __u32 size; |
a02b9dc9 | 405 | int num_fences, ret, i; |
d4cab38e GP |
406 | |
407 | if (copy_from_user(&info, (void __user *)arg, sizeof(info))) | |
408 | return -EFAULT; | |
409 | ||
410 | if (info.flags || info.pad) | |
411 | return -EINVAL; | |
412 | ||
a02b9dc9 GP |
413 | fences = get_fences(sync_file, &num_fences); |
414 | ||
d4cab38e GP |
415 | /* |
416 | * Passing num_fences = 0 means that userspace doesn't want to | |
417 | * retrieve any sync_fence_info. If num_fences = 0 we skip filling | |
418 | * sync_fence_info and return the actual number of fences on | |
419 | * info->num_fences. | |
420 | */ | |
f7974880 JER |
421 | if (!info.num_fences) { |
422 | info.status = dma_fence_is_signaled(sync_file->fence); | |
d4cab38e | 423 | goto no_fences; |
f7974880 JER |
424 | } else { |
425 | info.status = 1; | |
426 | } | |
d4cab38e | 427 | |
a02b9dc9 | 428 | if (info.num_fences < num_fences) |
d4cab38e GP |
429 | return -EINVAL; |
430 | ||
a02b9dc9 | 431 | size = num_fences * sizeof(*fence_info); |
d4cab38e GP |
432 | fence_info = kzalloc(size, GFP_KERNEL); |
433 | if (!fence_info) | |
434 | return -ENOMEM; | |
435 | ||
f7974880 JER |
436 | for (i = 0; i < num_fences; i++) { |
437 | int status = sync_fill_fence_info(fences[i], &fence_info[i]); | |
438 | info.status = info.status <= 0 ? info.status : status; | |
439 | } | |
d4cab38e GP |
440 | |
441 | if (copy_to_user(u64_to_user_ptr(info.sync_fence_info), fence_info, | |
442 | size)) { | |
443 | ret = -EFAULT; | |
444 | goto out; | |
445 | } | |
446 | ||
447 | no_fences: | |
71ebc9a3 | 448 | sync_file_get_name(sync_file, info.name, sizeof(info.name)); |
a02b9dc9 | 449 | info.num_fences = num_fences; |
d4cab38e GP |
450 | |
451 | if (copy_to_user((void __user *)arg, &info, sizeof(info))) | |
452 | ret = -EFAULT; | |
453 | else | |
454 | ret = 0; | |
455 | ||
456 | out: | |
457 | kfree(fence_info); | |
458 | ||
459 | return ret; | |
460 | } | |
461 | ||
462 | static long sync_file_ioctl(struct file *file, unsigned int cmd, | |
92e06213 | 463 | unsigned long arg) |
d4cab38e GP |
464 | { |
465 | struct sync_file *sync_file = file->private_data; | |
466 | ||
467 | switch (cmd) { | |
468 | case SYNC_IOC_MERGE: | |
469 | return sync_file_ioctl_merge(sync_file, arg); | |
470 | ||
471 | case SYNC_IOC_FILE_INFO: | |
472 | return sync_file_ioctl_fence_info(sync_file, arg); | |
473 | ||
474 | default: | |
475 | return -ENOTTY; | |
476 | } | |
477 | } | |
478 | ||
479 | static const struct file_operations sync_file_fops = { | |
480 | .release = sync_file_release, | |
481 | .poll = sync_file_poll, | |
482 | .unlocked_ioctl = sync_file_ioctl, | |
483 | .compat_ioctl = sync_file_ioctl, | |
484 | }; |