1 /*
2 * Copyright (c) 2024, Google Inc. All rights reserved.
3 * Author: codycswong@google.com (Cody Wong)
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files
7 * (the "Software"), to deal in the Software without restriction,
8 * including without limitation the rights to use, copy, modify, merge,
9 * publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so,
11 * subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24 #include <dev/virtio/9p.h>
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <lk/trace.h>
29 #include <lk/init.h>
30 #include <lk/list.h>
31 #include <lk/err.h>
32 #include <lib/fs.h>
33 #include <kernel/mutex.h>
34
35 #include "v9fs_priv.h"
36
37 #define LOCAL_TRACE 0
38
path_to_wname(char * path,uint16_t * nwname,const char * wname[P9_MAXWELEM])39 status_t path_to_wname(char *path, uint16_t *nwname,
40 const char *wname[P9_MAXWELEM])
41 {
42 char *cptr, *ncptr;
43 *nwname = 0;
44
45 if (path[0] == '\0')
46 return NO_ERROR;
47
48 cptr = path[0] == '/' ? path + 1 : path;
49
50 while ((ncptr = strchr(cptr, '/')) != NULL) {
51 *ncptr = '\0';
52 if (strlen(cptr) != 0)
53 wname[(*nwname)++] = cptr;
54 cptr = ncptr + 1;
55
56 if (*nwname == P9_MAXWELEM)
57 return ERR_BAD_PATH;
58 }
59
60 wname[(*nwname)++] = strlen(cptr) != 0? cptr : ".";
61
62 return NO_ERROR;
63 }
64
get_unused_fid(v9fs_t * v9fs)65 uint32_t get_unused_fid(v9fs_t *v9fs)
66 {
67 mutex_acquire(&v9fs->lock);
68 uint32_t fid = v9fs->unused_fid++;
69 mutex_release(&v9fs->lock);
70 return fid;
71 }
72
put_fid(v9fs_t * v9fs,uint32_t fid)73 void put_fid(v9fs_t *v9fs, uint32_t fid)
74 {
75 virtio_9p_msg_t tclunk = {
76 .msg_type = P9_TCLUNK,
77 .tag = P9_TAG_DEFAULT,
78 .msg.tclunk = { .fid = fid, }
79 };
80 virtio_9p_msg_t rclunk = {};
81
82 ASSERT(virtio_9p_rpc(v9fs->dev, &tclunk, &rclunk) == NO_ERROR);
83 ASSERT(rclunk.msg_type == P9_RCLUNK);
84
85 virtio_9p_msg_destroy(&rclunk);
86 }
87
v9fs_mount(bdev_t * dev,fscookie ** cookie)88 status_t v9fs_mount(bdev_t *dev, fscookie **cookie)
89 {
90 status_t ret;
91
92 LTRACEF("bdev (%p) cookie (%p)\n", dev, cookie);
93
94 if (!dev) {
95 return ERR_INVALID_ARGS;
96 }
97
98 v9fs_t *v9fs = calloc(1, sizeof(v9fs_t));
99
100 if (!v9fs)
101 return ERR_NO_MEMORY;
102
103 // initialize v9fs structure
104 v9fs->dev = virtio_9p_bdev_to_virtio_device(dev);
105 v9fs->bdev = dev;
106 v9fs->unused_fid = 0;
107 list_initialize(&v9fs->files);
108 list_initialize(&v9fs->dirs);
109 mutex_init(&v9fs->lock);
110 v9fs->root.fid = get_unused_fid(v9fs);
111
112 LTRACEF("v9fs->root.fid: %u\n", v9fs->root.fid);
113 // attach to the host
114 virtio_9p_msg_t tatt = {
115 .msg_type = P9_TATTACH,
116 .tag = P9_TAG_DEFAULT,
117 .msg.tattach = {
118 .fid = v9fs->root.fid,
119 .afid = P9_FID_NOFID,
120 .uname = "root",
121 .aname = V9P_MOUNT_ANAME,
122 .n_uname = P9_UNAME_NONUNAME,
123 }
124 };
125 virtio_9p_msg_t ratt = {};
126
127 if ((ret = virtio_9p_rpc(v9fs->dev, &tatt, &ratt)) != NO_ERROR)
128 goto err;
129
130 v9fs->root.qid = ratt.msg.rattach.qid;
131
132 virtio_9p_msg_destroy(&ratt);
133
134 *cookie = (fscookie *)v9fs;
135
136 return NO_ERROR;
137
138 err:
139 LTRACEF("mount 9p dev (%s) failed: %d\n", dev->name, ret);
140
141 free(v9fs);
142 v9fs = NULL;
143 return ret;
144 }
145
v9fs_unmount(fscookie * cookie)146 status_t v9fs_unmount(fscookie *cookie)
147 {
148 v9fs_t *v9fs = (v9fs_t *)cookie;
149
150 LTRACEF("v9fs (%p)\n", v9fs);
151
152 if (v9fs)
153 free(v9fs);
154
155 return 0;
156 }
157
158 static const struct fs_api v9fs_api = {
159 .format = NULL,
160 .fs_stat = NULL,
161
162 .mount = v9fs_mount,
163 .unmount = v9fs_unmount,
164 .open = v9fs_open_file,
165 .create = v9fs_create_file,
166 .remove = NULL,
167 .truncate = NULL,
168 .stat = v9fs_stat_file,
169 .read = v9fs_read_file,
170 .write = v9fs_write_file,
171 .close = v9fs_close_file,
172
173 .mkdir = v9fs_mkdir,
174 .opendir = v9fs_open_dir,
175 .readdir = v9fs_read_dir,
176 .closedir = v9fs_close_dir,
177
178 .file_ioctl = NULL,
179 };
180
181 STATIC_FS_IMPL(9p, &v9fs_api);
182