LCOV - code coverage report
Current view: top level - drivers/dma-buf - sync_file.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 125 0.0 %
Date: 2023-03-27 20:00:47 Functions: 0 13 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 :                 strscpy(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             : /**
     150             :  * sync_file_merge() - merge two sync_files
     151             :  * @name:       name of new fence
     152             :  * @a:          sync_file a
     153             :  * @b:          sync_file b
     154             :  *
     155             :  * Creates a new sync_file which contains copies of all the fences in both
     156             :  * @a and @b.  @a and @b remain valid, independent sync_file. Returns the
     157             :  * new merged sync_file or NULL in case of error.
     158             :  */
     159           0 : static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
     160             :                                          struct sync_file *b)
     161             : {
     162             :         struct sync_file *sync_file;
     163             :         struct dma_fence *fence;
     164             : 
     165           0 :         sync_file = sync_file_alloc();
     166           0 :         if (!sync_file)
     167             :                 return NULL;
     168             : 
     169           0 :         fence = dma_fence_unwrap_merge(a->fence, b->fence);
     170           0 :         if (!fence) {
     171           0 :                 fput(sync_file->file);
     172             :                 return NULL;
     173             :         }
     174           0 :         sync_file->fence = fence;
     175           0 :         strscpy(sync_file->user_name, name, sizeof(sync_file->user_name));
     176             :         return sync_file;
     177             : }
     178             : 
     179           0 : static int sync_file_release(struct inode *inode, struct file *file)
     180             : {
     181           0 :         struct sync_file *sync_file = file->private_data;
     182             : 
     183           0 :         if (test_bit(POLL_ENABLED, &sync_file->flags))
     184           0 :                 dma_fence_remove_callback(sync_file->fence, &sync_file->cb);
     185           0 :         dma_fence_put(sync_file->fence);
     186           0 :         kfree(sync_file);
     187             : 
     188           0 :         return 0;
     189             : }
     190             : 
     191           0 : static __poll_t sync_file_poll(struct file *file, poll_table *wait)
     192             : {
     193           0 :         struct sync_file *sync_file = file->private_data;
     194             : 
     195           0 :         poll_wait(file, &sync_file->wq, wait);
     196             : 
     197           0 :         if (list_empty(&sync_file->cb.node) &&
     198           0 :             !test_and_set_bit(POLL_ENABLED, &sync_file->flags)) {
     199           0 :                 if (dma_fence_add_callback(sync_file->fence, &sync_file->cb,
     200             :                                            fence_check_cb_func) < 0)
     201           0 :                         wake_up_all(&sync_file->wq);
     202             :         }
     203             : 
     204           0 :         return dma_fence_is_signaled(sync_file->fence) ? EPOLLIN : 0;
     205             : }
     206             : 
     207           0 : static long sync_file_ioctl_merge(struct sync_file *sync_file,
     208             :                                   unsigned long arg)
     209             : {
     210           0 :         int fd = get_unused_fd_flags(O_CLOEXEC);
     211             :         int err;
     212             :         struct sync_file *fence2, *fence3;
     213             :         struct sync_merge_data data;
     214             : 
     215           0 :         if (fd < 0)
     216           0 :                 return fd;
     217             : 
     218           0 :         if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
     219             :                 err = -EFAULT;
     220             :                 goto err_put_fd;
     221             :         }
     222             : 
     223           0 :         if (data.flags || data.pad) {
     224             :                 err = -EINVAL;
     225             :                 goto err_put_fd;
     226             :         }
     227             : 
     228           0 :         fence2 = sync_file_fdget(data.fd2);
     229           0 :         if (!fence2) {
     230             :                 err = -ENOENT;
     231             :                 goto err_put_fd;
     232             :         }
     233             : 
     234           0 :         data.name[sizeof(data.name) - 1] = '\0';
     235           0 :         fence3 = sync_file_merge(data.name, sync_file, fence2);
     236           0 :         if (!fence3) {
     237             :                 err = -ENOMEM;
     238             :                 goto err_put_fence2;
     239             :         }
     240             : 
     241           0 :         data.fence = fd;
     242           0 :         if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
     243           0 :                 err = -EFAULT;
     244             :                 goto err_put_fence3;
     245             :         }
     246             : 
     247           0 :         fd_install(fd, fence3->file);
     248           0 :         fput(fence2->file);
     249           0 :         return 0;
     250             : 
     251             : err_put_fence3:
     252           0 :         fput(fence3->file);
     253             : 
     254             : err_put_fence2:
     255           0 :         fput(fence2->file);
     256             : 
     257             : err_put_fd:
     258           0 :         put_unused_fd(fd);
     259           0 :         return err;
     260             : }
     261             : 
     262           0 : static int sync_fill_fence_info(struct dma_fence *fence,
     263             :                                  struct sync_fence_info *info)
     264             : {
     265           0 :         strscpy(info->obj_name, fence->ops->get_timeline_name(fence),
     266             :                 sizeof(info->obj_name));
     267           0 :         strscpy(info->driver_name, fence->ops->get_driver_name(fence),
     268             :                 sizeof(info->driver_name));
     269             : 
     270           0 :         info->status = dma_fence_get_status(fence);
     271           0 :         while (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) &&
     272           0 :                !test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags))
     273             :                 cpu_relax();
     274           0 :         info->timestamp_ns =
     275           0 :                 test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags) ?
     276           0 :                 ktime_to_ns(fence->timestamp) :
     277             :                 ktime_set(0, 0);
     278             : 
     279           0 :         return info->status;
     280             : }
     281             : 
     282           0 : static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
     283             :                                        unsigned long arg)
     284             : {
     285           0 :         struct sync_fence_info *fence_info = NULL;
     286             :         struct dma_fence_unwrap iter;
     287             :         struct sync_file_info info;
     288             :         unsigned int num_fences;
     289             :         struct dma_fence *fence;
     290             :         int ret;
     291             :         __u32 size;
     292             : 
     293           0 :         if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
     294             :                 return -EFAULT;
     295             : 
     296           0 :         if (info.flags || info.pad)
     297             :                 return -EINVAL;
     298             : 
     299           0 :         num_fences = 0;
     300           0 :         dma_fence_unwrap_for_each(fence, &iter, sync_file->fence)
     301           0 :                 ++num_fences;
     302             : 
     303             :         /*
     304             :          * Passing num_fences = 0 means that userspace doesn't want to
     305             :          * retrieve any sync_fence_info. If num_fences = 0 we skip filling
     306             :          * sync_fence_info and return the actual number of fences on
     307             :          * info->num_fences.
     308             :          */
     309           0 :         if (!info.num_fences) {
     310           0 :                 info.status = dma_fence_get_status(sync_file->fence);
     311           0 :                 goto no_fences;
     312             :         } else {
     313           0 :                 info.status = 1;
     314             :         }
     315             : 
     316           0 :         if (info.num_fences < num_fences)
     317             :                 return -EINVAL;
     318             : 
     319           0 :         size = num_fences * sizeof(*fence_info);
     320           0 :         fence_info = kzalloc(size, GFP_KERNEL);
     321           0 :         if (!fence_info)
     322             :                 return -ENOMEM;
     323             : 
     324           0 :         num_fences = 0;
     325           0 :         dma_fence_unwrap_for_each(fence, &iter, sync_file->fence) {
     326             :                 int status;
     327             : 
     328           0 :                 status = sync_fill_fence_info(fence, &fence_info[num_fences++]);
     329           0 :                 info.status = info.status <= 0 ? info.status : status;
     330             :         }
     331             : 
     332           0 :         if (copy_to_user(u64_to_user_ptr(info.sync_fence_info), fence_info,
     333             :                          size)) {
     334             :                 ret = -EFAULT;
     335             :                 goto out;
     336             :         }
     337             : 
     338             : no_fences:
     339           0 :         sync_file_get_name(sync_file, info.name, sizeof(info.name));
     340           0 :         info.num_fences = num_fences;
     341             : 
     342           0 :         if (copy_to_user((void __user *)arg, &info, sizeof(info)))
     343             :                 ret = -EFAULT;
     344             :         else
     345           0 :                 ret = 0;
     346             : 
     347             : out:
     348           0 :         kfree(fence_info);
     349             : 
     350           0 :         return ret;
     351             : }
     352             : 
     353           0 : static long sync_file_ioctl(struct file *file, unsigned int cmd,
     354             :                             unsigned long arg)
     355             : {
     356           0 :         struct sync_file *sync_file = file->private_data;
     357             : 
     358           0 :         switch (cmd) {
     359             :         case SYNC_IOC_MERGE:
     360           0 :                 return sync_file_ioctl_merge(sync_file, arg);
     361             : 
     362             :         case SYNC_IOC_FILE_INFO:
     363           0 :                 return sync_file_ioctl_fence_info(sync_file, arg);
     364             : 
     365             :         default:
     366             :                 return -ENOTTY;
     367             :         }
     368             : }
     369             : 
     370             : static const struct file_operations sync_file_fops = {
     371             :         .release = sync_file_release,
     372             :         .poll = sync_file_poll,
     373             :         .unlocked_ioctl = sync_file_ioctl,
     374             :         .compat_ioctl = compat_ptr_ioctl,
     375             : };

Generated by: LCOV version 1.14