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