Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v5.3-rc4 414 lines 9.7 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Sync File validation framework 4 * 5 * Copyright (C) 2012 Google, Inc. 6 */ 7 8#include <linux/file.h> 9#include <linux/fs.h> 10#include <linux/uaccess.h> 11#include <linux/slab.h> 12#include <linux/sync_file.h> 13 14#include "sync_debug.h" 15 16#define CREATE_TRACE_POINTS 17#include "sync_trace.h" 18 19/* 20 * SW SYNC validation framework 21 * 22 * A sync object driver that uses a 32bit counter to coordinate 23 * synchronization. Useful when there is no hardware primitive backing 24 * the synchronization. 25 * 26 * To start the framework just open: 27 * 28 * <debugfs>/sync/sw_sync 29 * 30 * That will create a sync timeline, all fences created under this timeline 31 * file descriptor will belong to the this timeline. 32 * 33 * The 'sw_sync' file can be opened many times as to create different 34 * timelines. 35 * 36 * Fences can be created with SW_SYNC_IOC_CREATE_FENCE ioctl with struct 37 * sw_sync_create_fence_data as parameter. 38 * 39 * To increment the timeline counter, SW_SYNC_IOC_INC ioctl should be used 40 * with the increment as u32. This will update the last signaled value 41 * from the timeline and signal any fence that has a seqno smaller or equal 42 * to it. 43 * 44 * struct sw_sync_create_fence_data 45 * @value: the seqno to initialise the fence with 46 * @name: the name of the new sync point 47 * @fence: return the fd of the new sync_file with the created fence 48 */ 49struct sw_sync_create_fence_data { 50 __u32 value; 51 char name[32]; 52 __s32 fence; /* fd of new fence */ 53}; 54 55#define SW_SYNC_IOC_MAGIC 'W' 56 57#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\ 58 struct sw_sync_create_fence_data) 59 60#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32) 61 62static const struct dma_fence_ops timeline_fence_ops; 63 64static inline struct sync_pt *dma_fence_to_sync_pt(struct dma_fence *fence) 65{ 66 if (fence->ops != &timeline_fence_ops) 67 return NULL; 68 return container_of(fence, struct sync_pt, base); 69} 70 71/** 72 * sync_timeline_create() - creates a sync object 73 * @name: sync_timeline name 74 * 75 * Creates a new sync_timeline. Returns the sync_timeline object or NULL in 76 * case of error. 77 */ 78static struct sync_timeline *sync_timeline_create(const char *name) 79{ 80 struct sync_timeline *obj; 81 82 obj = kzalloc(sizeof(*obj), GFP_KERNEL); 83 if (!obj) 84 return NULL; 85 86 kref_init(&obj->kref); 87 obj->context = dma_fence_context_alloc(1); 88 strlcpy(obj->name, name, sizeof(obj->name)); 89 90 obj->pt_tree = RB_ROOT; 91 INIT_LIST_HEAD(&obj->pt_list); 92 spin_lock_init(&obj->lock); 93 94 sync_timeline_debug_add(obj); 95 96 return obj; 97} 98 99static void sync_timeline_free(struct kref *kref) 100{ 101 struct sync_timeline *obj = 102 container_of(kref, struct sync_timeline, kref); 103 104 sync_timeline_debug_remove(obj); 105 106 kfree(obj); 107} 108 109static void sync_timeline_get(struct sync_timeline *obj) 110{ 111 kref_get(&obj->kref); 112} 113 114static void sync_timeline_put(struct sync_timeline *obj) 115{ 116 kref_put(&obj->kref, sync_timeline_free); 117} 118 119static const char *timeline_fence_get_driver_name(struct dma_fence *fence) 120{ 121 return "sw_sync"; 122} 123 124static const char *timeline_fence_get_timeline_name(struct dma_fence *fence) 125{ 126 struct sync_timeline *parent = dma_fence_parent(fence); 127 128 return parent->name; 129} 130 131static void timeline_fence_release(struct dma_fence *fence) 132{ 133 struct sync_pt *pt = dma_fence_to_sync_pt(fence); 134 struct sync_timeline *parent = dma_fence_parent(fence); 135 136 if (!list_empty(&pt->link)) { 137 unsigned long flags; 138 139 spin_lock_irqsave(fence->lock, flags); 140 if (!list_empty(&pt->link)) { 141 list_del(&pt->link); 142 rb_erase(&pt->node, &parent->pt_tree); 143 } 144 spin_unlock_irqrestore(fence->lock, flags); 145 } 146 147 sync_timeline_put(parent); 148 dma_fence_free(fence); 149} 150 151static bool timeline_fence_signaled(struct dma_fence *fence) 152{ 153 struct sync_timeline *parent = dma_fence_parent(fence); 154 155 return !__dma_fence_is_later(fence->seqno, parent->value, fence->ops); 156} 157 158static bool timeline_fence_enable_signaling(struct dma_fence *fence) 159{ 160 return true; 161} 162 163static void timeline_fence_value_str(struct dma_fence *fence, 164 char *str, int size) 165{ 166 snprintf(str, size, "%lld", fence->seqno); 167} 168 169static void timeline_fence_timeline_value_str(struct dma_fence *fence, 170 char *str, int size) 171{ 172 struct sync_timeline *parent = dma_fence_parent(fence); 173 174 snprintf(str, size, "%d", parent->value); 175} 176 177static const struct dma_fence_ops timeline_fence_ops = { 178 .get_driver_name = timeline_fence_get_driver_name, 179 .get_timeline_name = timeline_fence_get_timeline_name, 180 .enable_signaling = timeline_fence_enable_signaling, 181 .signaled = timeline_fence_signaled, 182 .release = timeline_fence_release, 183 .fence_value_str = timeline_fence_value_str, 184 .timeline_value_str = timeline_fence_timeline_value_str, 185}; 186 187/** 188 * sync_timeline_signal() - signal a status change on a sync_timeline 189 * @obj: sync_timeline to signal 190 * @inc: num to increment on timeline->value 191 * 192 * A sync implementation should call this any time one of it's fences 193 * has signaled or has an error condition. 194 */ 195static void sync_timeline_signal(struct sync_timeline *obj, unsigned int inc) 196{ 197 struct sync_pt *pt, *next; 198 199 trace_sync_timeline(obj); 200 201 spin_lock_irq(&obj->lock); 202 203 obj->value += inc; 204 205 list_for_each_entry_safe(pt, next, &obj->pt_list, link) { 206 if (!timeline_fence_signaled(&pt->base)) 207 break; 208 209 list_del_init(&pt->link); 210 rb_erase(&pt->node, &obj->pt_tree); 211 212 /* 213 * A signal callback may release the last reference to this 214 * fence, causing it to be freed. That operation has to be 215 * last to avoid a use after free inside this loop, and must 216 * be after we remove the fence from the timeline in order to 217 * prevent deadlocking on timeline->lock inside 218 * timeline_fence_release(). 219 */ 220 dma_fence_signal_locked(&pt->base); 221 } 222 223 spin_unlock_irq(&obj->lock); 224} 225 226/** 227 * sync_pt_create() - creates a sync pt 228 * @obj: parent sync_timeline 229 * @value: value of the fence 230 * 231 * Creates a new sync_pt (fence) as a child of @parent. @size bytes will be 232 * allocated allowing for implementation specific data to be kept after 233 * the generic sync_timeline struct. Returns the sync_pt object or 234 * NULL in case of error. 235 */ 236static struct sync_pt *sync_pt_create(struct sync_timeline *obj, 237 unsigned int value) 238{ 239 struct sync_pt *pt; 240 241 pt = kzalloc(sizeof(*pt), GFP_KERNEL); 242 if (!pt) 243 return NULL; 244 245 sync_timeline_get(obj); 246 dma_fence_init(&pt->base, &timeline_fence_ops, &obj->lock, 247 obj->context, value); 248 INIT_LIST_HEAD(&pt->link); 249 250 spin_lock_irq(&obj->lock); 251 if (!dma_fence_is_signaled_locked(&pt->base)) { 252 struct rb_node **p = &obj->pt_tree.rb_node; 253 struct rb_node *parent = NULL; 254 255 while (*p) { 256 struct sync_pt *other; 257 int cmp; 258 259 parent = *p; 260 other = rb_entry(parent, typeof(*pt), node); 261 cmp = value - other->base.seqno; 262 if (cmp > 0) { 263 p = &parent->rb_right; 264 } else if (cmp < 0) { 265 p = &parent->rb_left; 266 } else { 267 if (dma_fence_get_rcu(&other->base)) { 268 dma_fence_put(&pt->base); 269 pt = other; 270 goto unlock; 271 } 272 p = &parent->rb_left; 273 } 274 } 275 rb_link_node(&pt->node, parent, p); 276 rb_insert_color(&pt->node, &obj->pt_tree); 277 278 parent = rb_next(&pt->node); 279 list_add_tail(&pt->link, 280 parent ? &rb_entry(parent, typeof(*pt), node)->link : &obj->pt_list); 281 } 282unlock: 283 spin_unlock_irq(&obj->lock); 284 285 return pt; 286} 287 288/* 289 * *WARNING* 290 * 291 * improper use of this can result in deadlocking kernel drivers from userspace. 292 */ 293 294/* opening sw_sync create a new sync obj */ 295static int sw_sync_debugfs_open(struct inode *inode, struct file *file) 296{ 297 struct sync_timeline *obj; 298 char task_comm[TASK_COMM_LEN]; 299 300 get_task_comm(task_comm, current); 301 302 obj = sync_timeline_create(task_comm); 303 if (!obj) 304 return -ENOMEM; 305 306 file->private_data = obj; 307 308 return 0; 309} 310 311static int sw_sync_debugfs_release(struct inode *inode, struct file *file) 312{ 313 struct sync_timeline *obj = file->private_data; 314 struct sync_pt *pt, *next; 315 316 spin_lock_irq(&obj->lock); 317 318 list_for_each_entry_safe(pt, next, &obj->pt_list, link) { 319 dma_fence_set_error(&pt->base, -ENOENT); 320 dma_fence_signal_locked(&pt->base); 321 } 322 323 spin_unlock_irq(&obj->lock); 324 325 sync_timeline_put(obj); 326 return 0; 327} 328 329static long sw_sync_ioctl_create_fence(struct sync_timeline *obj, 330 unsigned long arg) 331{ 332 int fd = get_unused_fd_flags(O_CLOEXEC); 333 int err; 334 struct sync_pt *pt; 335 struct sync_file *sync_file; 336 struct sw_sync_create_fence_data data; 337 338 if (fd < 0) 339 return fd; 340 341 if (copy_from_user(&data, (void __user *)arg, sizeof(data))) { 342 err = -EFAULT; 343 goto err; 344 } 345 346 pt = sync_pt_create(obj, data.value); 347 if (!pt) { 348 err = -ENOMEM; 349 goto err; 350 } 351 352 sync_file = sync_file_create(&pt->base); 353 dma_fence_put(&pt->base); 354 if (!sync_file) { 355 err = -ENOMEM; 356 goto err; 357 } 358 359 data.fence = fd; 360 if (copy_to_user((void __user *)arg, &data, sizeof(data))) { 361 fput(sync_file->file); 362 err = -EFAULT; 363 goto err; 364 } 365 366 fd_install(fd, sync_file->file); 367 368 return 0; 369 370err: 371 put_unused_fd(fd); 372 return err; 373} 374 375static long sw_sync_ioctl_inc(struct sync_timeline *obj, unsigned long arg) 376{ 377 u32 value; 378 379 if (copy_from_user(&value, (void __user *)arg, sizeof(value))) 380 return -EFAULT; 381 382 while (value > INT_MAX) { 383 sync_timeline_signal(obj, INT_MAX); 384 value -= INT_MAX; 385 } 386 387 sync_timeline_signal(obj, value); 388 389 return 0; 390} 391 392static long sw_sync_ioctl(struct file *file, unsigned int cmd, 393 unsigned long arg) 394{ 395 struct sync_timeline *obj = file->private_data; 396 397 switch (cmd) { 398 case SW_SYNC_IOC_CREATE_FENCE: 399 return sw_sync_ioctl_create_fence(obj, arg); 400 401 case SW_SYNC_IOC_INC: 402 return sw_sync_ioctl_inc(obj, arg); 403 404 default: 405 return -ENOTTY; 406 } 407} 408 409const struct file_operations sw_sync_debugfs_fops = { 410 .open = sw_sync_debugfs_open, 411 .release = sw_sync_debugfs_release, 412 .unlocked_ioctl = sw_sync_ioctl, 413 .compat_ioctl = sw_sync_ioctl, 414};