c673e8418b6866541d8b413e68e5c72ea689806e
[lunaix-os.git] / lunaix-os / kernel / fs / mount.c
1 #include <lunaix/foptions.h>
2 #include <lunaix/fs/api.h>
3 #include <lunaix/mm/valloc.h>
4 #include <lunaix/process.h>
5 #include <lunaix/spike.h>
6 #include <lunaix/syscall_utils.h>
7 #include <lunaix/syslog.h>
8 #include <lunaix/types.h>
9
10 LOG_MODULE("fs")
11
12 struct llist_header all_mnts = { .next = &all_mnts, .prev = &all_mnts };
13
14 struct v_mount*
15 vfs_create_mount(struct v_mount* parent, struct v_dnode* mnt_point)
16 {
17     struct v_mount* mnt = vzalloc(sizeof(struct v_mount));
18     if (!mnt) {
19         return NULL;
20     }
21
22     llist_init_head(&mnt->submnts);
23     llist_init_head(&mnt->sibmnts);
24     llist_append(&all_mnts, &mnt->list);
25     mutex_init(&mnt->lock);
26
27     mnt->parent = parent;
28     mnt->mnt_point = mnt_point;
29     vfs_vmnt_assign_sb(mnt, mnt_point->super_block);
30
31     if (parent) {
32         mnt_mkbusy(parent);
33         mutex_lock(&mnt->parent->lock);
34         llist_append(&parent->submnts, &mnt->sibmnts);
35         mutex_unlock(&mnt->parent->lock);
36     }
37     
38     atomic_fetch_add(&mnt_point->ref_count, 1);
39
40     return mnt;
41 }
42
43 void
44 __vfs_release_vmnt(struct v_mount* mnt)
45 {
46     assert(llist_empty(&mnt->submnts));
47
48     if (mnt->parent) {
49         mnt_chillax(mnt->parent);
50     }
51
52     llist_delete(&mnt->sibmnts);
53     llist_delete(&mnt->list);
54     atomic_fetch_sub(&mnt->mnt_point->ref_count, 1);
55     vfree(mnt);
56 }
57
58 int
59 __vfs_do_unmount(struct v_mount* mnt)
60 {
61     int errno = 0;
62     struct v_superblock* sb = mnt->super_block;
63
64     if ((errno = sb->fs->unmount(sb))) {
65         return errno;
66     }
67
68     // detached the inodes from cache, and let lru policy to recycle them
69     for (size_t i = 0; i < VFS_HASHTABLE_SIZE; i++) {
70         struct hbucket* bucket = &sb->i_cache[i];
71         if (!bucket->head) {
72             continue;
73         }
74         bucket->head->pprev = 0;
75     }
76
77     mnt->mnt_point->mnt = mnt->parent;
78
79     vfs_sb_free(sb);
80     __vfs_release_vmnt(mnt);
81
82     return errno;
83 }
84
85 void
86 mnt_mkbusy(struct v_mount* mnt)
87 {
88     mutex_lock(&mnt->lock);
89     mnt->busy_counter++;
90     mutex_unlock(&mnt->lock);
91 }
92
93 void
94 mnt_chillax(struct v_mount* mnt)
95 {
96     mutex_lock(&mnt->lock);
97     mnt->busy_counter--;
98     mutex_unlock(&mnt->lock);
99 }
100
101 int
102 vfs_mount_root(const char* fs_name, struct device* device)
103 {
104     extern struct v_dnode* vfs_sysroot;
105     int errno = 0;
106     if (vfs_sysroot->mnt && (errno = vfs_unmount_at(vfs_sysroot))) {
107         return errno;
108     }
109     return vfs_mount_at(fs_name, device, vfs_sysroot, 0);
110 }
111
112 int
113 vfs_mount(const char* target,
114           const char* fs_name,
115           struct device* device,
116           int options)
117 {
118     int errno;
119     struct v_dnode* mnt;
120
121     if (!(errno =
122             vfs_walk(__current->cwd, target, &mnt, NULL, VFS_WALK_MKPARENT))) {
123         errno = vfs_mount_at(fs_name, device, mnt, options);
124     }
125
126     return errno;
127 }
128
129 int
130 vfs_unmount(const char* target)
131 {
132     int errno;
133     struct v_dnode* mnt;
134
135     if (!(errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) {
136         errno = vfs_unmount_at(mnt);
137     }
138
139     return errno;
140 }
141
142 static int
143 vfs_mount_fsat(struct filesystem* fs,
144                struct device* device,
145                struct v_dnode* mnt_point,
146                int options)
147 {
148
149     if (device && device->dev_type != DEV_IFVOL) {
150         return ENOTBLK;
151     }
152
153     if (mnt_point->inode && !check_directory_node(mnt_point->inode)) {
154         return ENOTDIR;
155     }
156
157     if ((fs->types & FSTYPE_ROFS)) {
158         options |= MNT_RO;
159     }
160
161     if (!(fs->types & FSTYPE_PSEUDO) && !device) {
162         return ENODEV;
163     }
164
165     int errno = 0;
166     char* dev_name = "sys";
167     char* fsname = HSTR_VAL(fs->fs_name);
168
169     struct v_mount* parent_mnt = mnt_point->mnt;
170     struct v_superblock *sb = vfs_sb_alloc(), 
171                         *old_sb = mnt_point->super_block;
172
173     if (device) {
174         dev_name = device->name_val;
175     }
176
177     // prepare v_superblock for fs::mount invoke
178     sb->dev = device;
179     sb->fs = fs;
180     sb->root = mnt_point;
181     vfs_d_assign_sb(mnt_point, sb);
182
183     if (!(mnt_point->mnt = vfs_create_mount(parent_mnt, mnt_point))) {
184         errno = ENOMEM;
185         goto cleanup;
186     }
187
188     mnt_point->mnt->flags = options;
189     if (!(errno = fs->mount(sb, mnt_point))) {
190         kprintf("mount: dev=%s, fs=%s, mode=%d", 
191                     dev_name, fsname, options);
192     } else {
193         goto cleanup;
194     }
195
196     vfs_sb_free(old_sb);
197     return errno;
198
199 cleanup:
200     ERROR("failed mount: dev=%s, fs=%s, mode=%d, err=%d",
201             dev_name, fsname, options, errno);
202
203     vfs_d_assign_sb(mnt_point, old_sb);
204     vfs_sb_free(sb);
205     __vfs_release_vmnt(mnt_point->mnt);
206
207     mnt_point->mnt = parent_mnt;
208
209     return errno;
210 }
211
212 int
213 vfs_mount_at(const char* fs_name,
214              struct device* device,
215              struct v_dnode* mnt_point,
216              int options)
217 {
218     if (fs_name) {
219         struct filesystem* fs = fsm_get(fs_name);
220         if (!fs) {
221             return ENODEV;
222         }
223
224         return vfs_mount_fsat(fs, device, mnt_point, options);
225     }
226
227     int errno = ENODEV;
228     struct fs_iter fsi;
229
230     fsm_itbegin(&fsi);
231     while (fsm_itnext(&fsi))
232     {
233         if ((fsi.fs->types & FSTYPE_PSEUDO)) {
234             continue;
235         }
236
237         INFO("mount attempt: %s", HSTR_VAL(fsi.fs->fs_name));
238         errno = vfs_mount_fsat(fsi.fs, device, mnt_point, options);
239         if (!errno) {
240             break;
241         }
242     }
243
244     return errno;
245 }
246
247 int
248 vfs_unmount_at(struct v_dnode* mnt_point)
249 {
250     int errno = 0;
251     struct v_superblock* sb = mnt_point->super_block;
252     if (!sb) {
253         return EINVAL;
254     }
255
256     if (sb->root != mnt_point) {
257         return EINVAL;
258     }
259
260     if (mnt_point->mnt->busy_counter) {
261         return EBUSY;
262     }
263
264     if (!(errno = __vfs_do_unmount(mnt_point->mnt))) {
265         atomic_fetch_sub(&mnt_point->ref_count, 1);
266     }
267
268     return errno;
269 }
270
271 int
272 vfs_check_writable(struct v_dnode* dnode)
273 {
274     if ((dnode->mnt->flags & MNT_RO)) {
275         return EROFS;
276     }
277     return 0;
278 }
279
280 __DEFINE_LXSYSCALL4(int,
281                     mount,
282                     const char*,
283                     source,
284                     const char*,
285                     target,
286                     const char*,
287                     fstype,
288                     int,
289                     options)
290 {
291     struct device* device = NULL;
292     struct v_dnode *dev = NULL, *mnt = NULL;
293     int errno = 0;
294
295     // It is fine if source is not exist, as some mounting don't require it
296     vfs_walk(__current->cwd, source, &dev, NULL, 0);
297
298     if ((errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) {
299         goto done;
300     }
301
302     if (mnt->ref_count > 1) {
303         errno = EBUSY;
304         goto done;
305     }
306
307     if (mnt->mnt->mnt_point == mnt) {
308         errno = EBUSY;
309         goto done;
310     }
311
312     if (dev) {
313         if (!check_voldev_node(dev->inode)) {
314             errno = ENOTDEV;
315             goto done;
316         }
317
318         device = resolve_device(dev->inode->data);
319         assert(device);
320     }
321
322     errno = vfs_mount_at(fstype, device, mnt, options);
323
324 done:
325     return DO_STATUS(errno);
326 }
327
328 __DEFINE_LXSYSCALL1(int, unmount, const char*, target)
329 {
330     return vfs_unmount(target);
331 }