18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SPU file system -- system call stubs 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 68c2ecf20Sopenharmony_ci * (C) Copyright 2006-2007, IBM Corporation 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author: Arnd Bergmann <arndb@de.ibm.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/file.h> 118c2ecf20Sopenharmony_ci#include <linux/fs.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/syscalls.h> 148c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 158c2ecf20Sopenharmony_ci#include <linux/binfmts.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/spu.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* protected by rcu */ 208c2ecf20Sopenharmony_cistatic struct spufs_calls *spufs_calls; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#ifdef CONFIG_SPU_FS_MODULE 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic inline struct spufs_calls *spufs_calls_get(void) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct spufs_calls *calls = NULL; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci rcu_read_lock(); 298c2ecf20Sopenharmony_ci calls = rcu_dereference(spufs_calls); 308c2ecf20Sopenharmony_ci if (calls && !try_module_get(calls->owner)) 318c2ecf20Sopenharmony_ci calls = NULL; 328c2ecf20Sopenharmony_ci rcu_read_unlock(); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci return calls; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic inline void spufs_calls_put(struct spufs_calls *calls) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci BUG_ON(calls != spufs_calls); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* we don't need to rcu this, as we hold a reference to the module */ 428c2ecf20Sopenharmony_ci module_put(spufs_calls->owner); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#else /* !defined CONFIG_SPU_FS_MODULE */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic inline struct spufs_calls *spufs_calls_get(void) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci return spufs_calls; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic inline void spufs_calls_put(struct spufs_calls *calls) { } 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#endif /* CONFIG_SPU_FS_MODULE */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ciSYSCALL_DEFINE4(spu_create, const char __user *, name, unsigned int, flags, 578c2ecf20Sopenharmony_ci umode_t, mode, int, neighbor_fd) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci long ret; 608c2ecf20Sopenharmony_ci struct spufs_calls *calls; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci calls = spufs_calls_get(); 638c2ecf20Sopenharmony_ci if (!calls) 648c2ecf20Sopenharmony_ci return -ENOSYS; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (flags & SPU_CREATE_AFFINITY_SPU) { 678c2ecf20Sopenharmony_ci struct fd neighbor = fdget(neighbor_fd); 688c2ecf20Sopenharmony_ci ret = -EBADF; 698c2ecf20Sopenharmony_ci if (neighbor.file) { 708c2ecf20Sopenharmony_ci ret = calls->create_thread(name, flags, mode, neighbor.file); 718c2ecf20Sopenharmony_ci fdput(neighbor); 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci } else 748c2ecf20Sopenharmony_ci ret = calls->create_thread(name, flags, mode, NULL); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci spufs_calls_put(calls); 778c2ecf20Sopenharmony_ci return ret; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciSYSCALL_DEFINE3(spu_run,int, fd, __u32 __user *, unpc, __u32 __user *, ustatus) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci long ret; 838c2ecf20Sopenharmony_ci struct fd arg; 848c2ecf20Sopenharmony_ci struct spufs_calls *calls; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci calls = spufs_calls_get(); 878c2ecf20Sopenharmony_ci if (!calls) 888c2ecf20Sopenharmony_ci return -ENOSYS; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci ret = -EBADF; 918c2ecf20Sopenharmony_ci arg = fdget(fd); 928c2ecf20Sopenharmony_ci if (arg.file) { 938c2ecf20Sopenharmony_ci ret = calls->spu_run(arg.file, unpc, ustatus); 948c2ecf20Sopenharmony_ci fdput(arg); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci spufs_calls_put(calls); 988c2ecf20Sopenharmony_ci return ret; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci#ifdef CONFIG_COREDUMP 1028c2ecf20Sopenharmony_ciint elf_coredump_extra_notes_size(void) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct spufs_calls *calls; 1058c2ecf20Sopenharmony_ci int ret; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci calls = spufs_calls_get(); 1088c2ecf20Sopenharmony_ci if (!calls) 1098c2ecf20Sopenharmony_ci return 0; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci ret = calls->coredump_extra_notes_size(); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci spufs_calls_put(calls); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return ret; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ciint elf_coredump_extra_notes_write(struct coredump_params *cprm) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci struct spufs_calls *calls; 1218c2ecf20Sopenharmony_ci int ret; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci calls = spufs_calls_get(); 1248c2ecf20Sopenharmony_ci if (!calls) 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci ret = calls->coredump_extra_notes_write(cprm); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci spufs_calls_put(calls); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return ret; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci#endif 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_civoid notify_spus_active(void) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct spufs_calls *calls; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci calls = spufs_calls_get(); 1408c2ecf20Sopenharmony_ci if (!calls) 1418c2ecf20Sopenharmony_ci return; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci calls->notify_spus_active(); 1448c2ecf20Sopenharmony_ci spufs_calls_put(calls); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ciint register_spu_syscalls(struct spufs_calls *calls) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci if (spufs_calls) 1528c2ecf20Sopenharmony_ci return -EBUSY; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci rcu_assign_pointer(spufs_calls, calls); 1558c2ecf20Sopenharmony_ci return 0; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(register_spu_syscalls); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_civoid unregister_spu_syscalls(struct spufs_calls *calls) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci BUG_ON(spufs_calls->owner != calls->owner); 1628c2ecf20Sopenharmony_ci RCU_INIT_POINTER(spufs_calls, NULL); 1638c2ecf20Sopenharmony_ci synchronize_rcu(); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_spu_syscalls); 166