LCOV - code coverage report
Current view: top level - drivers/dma-buf - sync_file.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 173 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 15 0.0 %

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

Generated by: LCOV version 1.14