1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | // ! /sys/ipc/<server_name> operations to connect to an IPC server |
4 | |
5 | #include "mos/filesystem/dentry.h" |
6 | #include "mos/filesystem/vfs_types.h" |
7 | #include "mos/ipc/ipc.h" |
8 | #include "mos/ipc/ipc_io.h" |
9 | #include "mos/mm/slab_autoinit.h" |
10 | #include "mos/platform/platform.h" |
11 | #include "mos/tasks/process.h" |
12 | |
13 | #include <mos_stdlib.h> |
14 | #include <mos_string.h> |
15 | |
16 | typedef struct |
17 | { |
18 | bool server_control_file; |
19 | ipc_server_t *server; |
20 | ipc_t *client_ipc; |
21 | } ipc_vfs_private_t; |
22 | |
23 | slab_t *ipc_vfs_private_slab = NULL; |
24 | SLAB_AUTOINIT("ipc_vfs_private" , ipc_vfs_private_slab, ipc_vfs_private_t); |
25 | |
26 | static bool vfs_open_ipc(inode_t *ino, file_t *file, bool created) |
27 | { |
28 | MOS_UNUSED(ino); |
29 | |
30 | ipc_t *ipc = NULL; |
31 | ipc_server_t *server = NULL; |
32 | |
33 | if (created) |
34 | { |
35 | server = ipc_get_server(name: file->dentry->name); |
36 | MOS_ASSERT(server); |
37 | } |
38 | else |
39 | { |
40 | ipc = ipc_connect_to_server(name: file->dentry->name, MOS_PAGE_SIZE); |
41 | if (IS_ERR(ptr: ipc)) |
42 | return false; |
43 | } |
44 | |
45 | ipc_vfs_private_t *private = kmalloc(ipc_vfs_private_slab); |
46 | private->server_control_file = created; |
47 | private->client_ipc = ipc; |
48 | private->server = server; |
49 | |
50 | file->private_data = private; |
51 | return true; |
52 | } |
53 | |
54 | static ssize_t vfs_ipc_file_read(const file_t *file, void *buf, size_t size, off_t offset) |
55 | { |
56 | MOS_UNUSED(offset); |
57 | |
58 | ipc_vfs_private_t *private = file->private_data; |
59 | if (private->server_control_file) |
60 | { |
61 | // reading from the server's control file accepts and returns a new connection, as a fd |
62 | if (size < sizeof(fd_t)) |
63 | return -EINVAL; |
64 | |
65 | ipc_t *ipc = ipc_server_accept(server: private->server); |
66 | if (IS_ERR(ptr: ipc)) |
67 | return PTR_ERR(ptr: ipc); |
68 | |
69 | ipc_conn_io_t *connio = ipc_conn_io_create(ipc, is_server_side: true); |
70 | if (IS_ERR(ptr: connio)) |
71 | return PTR_ERR(ptr: connio); |
72 | |
73 | const fd_t fd = process_attach_ref_fd(current_process, file: &connio->io, flags: FD_FLAGS_NONE); |
74 | if (IS_ERR_VALUE(fd)) |
75 | return fd; |
76 | |
77 | // return the fd to the client |
78 | memcpy(dest: buf, src: &fd, n: sizeof(fd_t)); |
79 | return sizeof(fd_t); |
80 | } |
81 | else |
82 | { |
83 | return ipc_client_read(ipc: private->client_ipc, buffer: buf, size); |
84 | } |
85 | } |
86 | |
87 | static ssize_t vfs_ipc_file_write(const file_t *file, const void *buf, size_t size, off_t offset) |
88 | { |
89 | MOS_UNUSED(offset); |
90 | ipc_vfs_private_t *private = file->private_data; |
91 | if (private->server_control_file) |
92 | return -EBADF; // writing to the server's control file is not supported |
93 | |
94 | return ipc_client_write(ipc: private->client_ipc, buffer: buf, size); |
95 | } |
96 | |
97 | static void vfs_ipc_file_release(file_t *file) |
98 | { |
99 | ipc_vfs_private_t *private = file->private_data; |
100 | if (private->server_control_file) |
101 | { |
102 | ipc_server_close(server: private->server); |
103 | dentry_detach(dentry: file->dentry); |
104 | } |
105 | else |
106 | ipc_client_close_channel(ipc: private->client_ipc); |
107 | kfree(ptr: private); |
108 | } |
109 | |
110 | const file_ops_t ipc_sysfs_file_ops = { |
111 | .open = vfs_open_ipc, |
112 | .read = vfs_ipc_file_read, |
113 | .write = vfs_ipc_file_write, |
114 | .release = vfs_ipc_file_release, |
115 | }; |
116 | |