1 #include "VFS.h"
2 #include "internal.h"
3 #include "mount.h"
4 #include <common/dirent.h>
5 #include <common/err.h>
6 #include <common/errno.h>
7 #include <common/kprint.h>
8 #include <common/string.h>
9 #include <debug/bug.h>
10 #include <filesystem/rootfs/rootfs.h>
11 #include <mm/mm.h>
12 #include <mm/slab.h>
13 #include <process/process.h>
14 #include <process/ptrace.h>
15
16 // 为filesystem_type_t结构体实例化一个链表头
17 static struct vfs_filesystem_type_t vfs_fs = {"filesystem", 0};
18 struct vfs_superblock_t *vfs_root_sb = NULL;
19
20 struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size);
21
22 /**
23 * @brief 挂载文件系统
24 *
25 * @param path 要挂载到的路径
26 * @param name 文件系统名
27 * @param blk 块设备结构体
28 * @return struct vfs_superblock_t* 挂载后,文件系统的超级块
29 */
vfs_mount_fs(const char * path,char * name,struct block_device * blk)30 struct vfs_superblock_t *vfs_mount_fs(const char *path, char *name, struct block_device *blk)
31 {
32
33 // 判断挂载点是否存在
34 struct vfs_dir_entry_t *target_dentry = NULL;
35
36 target_dentry = vfs_path_walk(path, 0);
37 if (target_dentry == NULL)
38 return NULL;
39
40 struct vfs_filesystem_type_t *p = NULL;
41 for (p = &vfs_fs; p; p = p->next)
42 {
43 if (!strcmp(p->name, name)) // 存在符合的文件系统
44 {
45 struct vfs_superblock_t *sb = p->read_superblock(blk);
46 if (strcmp(path, "/") == 0) // 如果挂载到的是'/'挂载点,则让其成为最顶层的文件系统
47 {
48 vfs_root_sb = sb;
49 }
50 else
51 {
52 kdebug("to mount %s", name);
53 // 调用mount机制,挂载文件系统
54 struct vfs_dir_entry_t *new_dentry = sb->root;
55 // 注意,umount的时候需要释放这些内存
56 new_dentry->name = kzalloc(target_dentry->name_length + 1, 0);
57 new_dentry->name_length = target_dentry->name_length;
58
59 do_mount(target_dentry, new_dentry);
60 }
61 return sb;
62 }
63 }
64
65 kdebug("unsupported fs: %s", name);
66 return NULL;
67 }
68
69 /**
70 * @brief 在VFS中注册文件系统
71 *
72 * @param fs 文件系统类型结构体
73 * @return uint64_t
74 */
vfs_register_filesystem(struct vfs_filesystem_type_t * fs)75 uint64_t vfs_register_filesystem(struct vfs_filesystem_type_t *fs)
76 {
77 struct vfs_filesystem_type_t *p = NULL;
78 for (p = &vfs_fs; p; p = p->next)
79 {
80 if (!strcmp(p->name, fs->name)) // 已经注册相同名称的文件系统
81 return -EEXIST;
82 }
83
84 fs->next = vfs_fs.next;
85 vfs_fs.next = fs;
86 return 0;
87 }
88
vfs_unregister_filesystem(struct vfs_filesystem_type_t * fs)89 uint64_t vfs_unregister_filesystem(struct vfs_filesystem_type_t *fs)
90 {
91 struct vfs_filesystem_type_t *p = &vfs_fs;
92 while (p->next)
93 {
94 if (p->next == fs)
95 {
96 p->next = p->next->next;
97 fs->next = NULL;
98 return 0;
99 }
100 else
101 p = p->next;
102 }
103 return -EINVAL;
104 }
105
106 /**
107 * @brief 在dentry的sub_dir_list中搜索指定名称的dentry
108 *
109 * @param dentry 目录项结构体dentry
110 * @param name 待搜索的dentry名称
111 * @return struct vfs_dir_entry_t* 目标dentry (无结果则返回NULL)
112 */
vfs_search_dentry_list(struct vfs_dir_entry_t * dentry,const char * name)113 static struct vfs_dir_entry_t *vfs_search_dentry_list(struct vfs_dir_entry_t *dentry, const char *name)
114 {
115 if (list_empty(&dentry->subdirs_list))
116 return NULL;
117
118 struct List *ptr = &dentry->subdirs_list;
119 struct vfs_dir_entry_t *d_ptr = NULL;
120 do
121 {
122 ptr = list_next(ptr);
123 d_ptr = container_of(ptr, struct vfs_dir_entry_t, child_node_list);
124 if (strcmp(name, d_ptr->name) == 0)
125 return d_ptr;
126 } while (list_next(ptr) != (&dentry->subdirs_list));
127
128 return NULL;
129 }
130
131 /**
132 * @brief 按照路径查找文件
133 *
134 * @param path 路径
135 * @param flags 1:返回父目录项, 0:返回结果目录项
136 * @return struct vfs_dir_entry_t* 目录项
137 */
vfs_path_walk(const char * path,uint64_t flags)138 struct vfs_dir_entry_t *vfs_path_walk(const char *path, uint64_t flags)
139 {
140
141 struct vfs_dir_entry_t *parent = vfs_root_sb->root;
142 // 去除路径前的斜杠
143 while (*path == '/')
144 ++path;
145
146 if ((!*path) || (*path == '\0'))
147 return parent;
148
149 struct vfs_dir_entry_t *dentry = NULL;
150 // kdebug("path before walk:%s", path);
151 while (true)
152 {
153 // 提取出下一级待搜索的目录名或文件名,并保存在dEntry_name中
154 const char *tmp_path = path;
155 while ((*path && *path != '\0') && (*path != '/'))
156 ++path;
157 int tmp_path_len = path - tmp_path;
158 // 搜索是否有dentry缓存
159 {
160 char *tmpname = kzalloc(tmp_path_len + 1, 0);
161 strncpy(tmpname, tmp_path, tmp_path_len);
162 tmpname[tmp_path_len] = '\0';
163 // kdebug("tmpname=%s", tmpname);
164 dentry = vfs_search_dentry_list(parent, tmpname);
165
166 kfree(tmpname);
167 }
168
169 // 如果没有找到dentry缓存,则申请新的dentry
170 if (dentry == NULL)
171 {
172 dentry = vfs_alloc_dentry(tmp_path_len + 1);
173
174 memcpy(dentry->name, (void *)tmp_path, tmp_path_len);
175 dentry->name[tmp_path_len] = '\0';
176 // kdebug("tmp_path_len=%d, dentry->name=%s", tmp_path_len, dentry->name);
177 dentry->name_length = tmp_path_len;
178
179 if (parent->dir_inode->inode_ops->lookup(parent->dir_inode, dentry) == NULL)
180 {
181 // 搜索失败
182 // kwarn("cannot find the file/dir : %s", dentry->name);
183 kfree(dentry->name);
184 kfree(dentry);
185 return NULL;
186 }
187 // 找到子目录项
188 dentry->parent = parent;
189
190 list_add(&parent->subdirs_list, &dentry->child_node_list);
191 }
192
193 while (*path == '/')
194 ++path;
195
196 if ((!*path) || (*path == '\0')) // 已经到达末尾
197 {
198 if (flags & 1) // 返回父目录
199 {
200 return parent;
201 }
202
203 return dentry;
204 }
205
206 parent = dentry;
207 }
208 }
209
210 /**
211 * @brief 填充dentry
212 *
213 * @return dirent的总大小
214 */
vfs_fill_dirent(void * buf,ino_t d_ino,char * name,int namelen,unsigned char type,off_t offset)215 int vfs_fill_dirent(void *buf, ino_t d_ino, char *name, int namelen, unsigned char type, off_t offset)
216 {
217 struct dirent *dent = (struct dirent *)buf;
218
219 // 如果尝试访问内核空间,则返回错误
220 if (!(verify_area((uint64_t)buf, sizeof(struct dirent) + namelen)))
221 return -EFAULT;
222
223 // ====== 填充dirent结构体 =====
224 memset(buf, 0, sizeof(struct dirent) + namelen);
225
226 memcpy(dent->d_name, name, namelen);
227 dent->d_name[namelen] = '\0';
228 // 暂时不显示目录下的记录数
229 dent->d_reclen = 0;
230 dent->d_ino = d_ino;
231 dent->d_off = offset;
232 dent->d_type = type;
233
234 // 返回dirent的总大小
235 return sizeof(struct dirent) + namelen;
236 }
237
238 /**
239 * @brief 创建文件夹
240 *
241 * @param path 文件夹路径
242 * @param mode 创建模式
243 * @param from_userland 该创建请求是否来自用户态
244 * @return int64_t 错误码
245 */
vfs_mkdir(const char * path,mode_t mode,bool from_userland)246 int64_t vfs_mkdir(const char *path, mode_t mode, bool from_userland)
247 {
248 uint32_t pathlen;
249 int retval = 0;
250 if (from_userland)
251 pathlen = strnlen_user(path, PAGE_4K_SIZE - 1);
252 else
253 pathlen = strnlen(path, PAGE_4K_SIZE - 1);
254
255 if (pathlen == 0)
256 return -ENOENT;
257
258 int last_slash = -1;
259
260 // 查找最后一个'/',忽略路径末尾的'/'
261 for (int i = pathlen - 2; i >= 0; --i)
262 {
263 if (path[i] == '/')
264 {
265 last_slash = i;
266 break;
267 }
268 }
269
270 // 路径格式不合法(必须使用绝对路径)
271 if (last_slash < 0)
272 return -ENOTDIR;
273
274 char *buf = (char *)kzalloc(last_slash + 2, 0);
275
276 // 拷贝字符串(不包含要被创建的部分)
277 if (from_userland)
278 strncpy_from_user(buf, path, last_slash);
279 else
280 strncpy(buf, path, last_slash);
281 buf[last_slash + 1] = '\0';
282
283 // 查找父目录
284 struct vfs_dir_entry_t *parent_dir = vfs_path_walk(buf, 0);
285
286 if (parent_dir == NULL)
287 {
288 kwarn("parent dir is NULL.");
289 kfree(buf);
290 return -ENOENT;
291 }
292 kfree(buf);
293
294 // 检查父目录中是否已经有相同的目录项
295 if (vfs_path_walk((const char *)path, 0) != NULL)
296 {
297 // 目录中已有对应的文件夹
298 kwarn("Dir '%s' aleardy exists.", path);
299 return -EEXIST;
300 }
301 spin_lock(&parent_dir->lockref.lock);
302 struct vfs_dir_entry_t *subdir_dentry = vfs_alloc_dentry(pathlen - last_slash);
303
304 if (path[pathlen - 1] == '/')
305 subdir_dentry->name_length = pathlen - last_slash - 2;
306 else
307 subdir_dentry->name_length = pathlen - last_slash - 1;
308
309 for (int i = last_slash + 1, cnt = 0; i < pathlen && cnt < subdir_dentry->name_length; ++i, ++cnt)
310 subdir_dentry->name[cnt] = path[i];
311 // 设置subdir的dentry的父路径
312 subdir_dentry->parent = parent_dir;
313
314 // kdebug("to mkdir, parent name=%s", parent_dir->name);
315 spin_lock(&parent_dir->dir_inode->lockref.lock);
316 retval = parent_dir->dir_inode->inode_ops->mkdir(parent_dir->dir_inode, subdir_dentry, 0);
317 spin_unlock(&parent_dir->dir_inode->lockref.lock);
318
319 if (retval != 0)
320 {
321 if (vfs_dentry_put(parent_dir) != 0) // 释放dentry
322 spin_unlock(&parent_dir->lockref.lock);
323 return retval;
324 }
325
326 // 获取append前一个dentry并加锁
327 struct List *target_list = &parent_dir->subdirs_list;
328 // kdebug("target_list=%#018lx target_list->prev=%#018lx",target_list,target_list->prev);
329 if (list_empty(target_list) == false)
330 {
331 struct vfs_dir_entry_t *prev_dentry = list_entry(target_list->prev, struct vfs_dir_entry_t, child_node_list);
332 // kdebug("prev_dentry%#018lx",prev_dentry);
333 spin_lock(&prev_dentry->lockref.lock);
334 list_append(&parent_dir->subdirs_list, &subdir_dentry->child_node_list);
335 // kdebug("retval = %d", retval);
336 spin_unlock(&prev_dentry->lockref.lock);
337 }
338 else
339 {
340 list_append(&parent_dir->subdirs_list, &subdir_dentry->child_node_list);
341 goto out;
342 }
343
344 out:;
345 spin_unlock(&parent_dir->lockref.lock);
346 return retval;
347 }
348
349 /**
350 * @brief 创建文件夹
351 *
352 * @param path(r8) 路径
353 * @param mode(r9) 模式
354 * @return uint64_t
355 */
sys_mkdir(struct pt_regs * regs)356 uint64_t sys_mkdir(struct pt_regs *regs)
357 {
358 const char *path = (const char *)regs->r8;
359 // kdebug("path = %s", path);
360 mode_t mode = (mode_t)regs->r9;
361
362 if (user_mode(regs))
363 return vfs_mkdir(path, mode, true);
364 else
365 return vfs_mkdir(path, mode, false);
366 }
367
368 /**
369 * @brief 打开文件
370 *
371 * @param filename 文件路径
372 * @param flags 标志位
373 * @param from_user 是否由用户态调用,1为是,0为否
374 * @return uint64_t 错误码
375 */
do_open(const char * filename,int flags,bool from_user)376 uint64_t do_open(const char *filename, int flags, bool from_user)
377 {
378 long path_len = 0;
379 if (from_user)
380 path_len = strnlen_user(filename, PAGE_4K_SIZE) + 1;
381 else
382 path_len = strnlen(filename, PAGE_4K_SIZE) + 1;
383
384 if (path_len <= 0) // 地址空间错误
385 return -EFAULT;
386 else if (path_len >= PAGE_4K_SIZE) // 名称过长
387 return -ENAMETOOLONG;
388
389 // 为待拷贝文件路径字符串分配内存空间
390 char *path = (char *)kzalloc(path_len, 0);
391 if (path == NULL)
392 return -ENOMEM;
393
394 if (from_user)
395 strncpy_from_user(path, filename, path_len);
396 else
397 strncpy(path, filename, path_len);
398
399 // 去除末尾的 '/'
400 if (path_len >= 2 && path[path_len - 2] == '/')
401 {
402 path[path_len - 2] = '\0';
403 --path_len;
404 }
405
406 // 寻找文件
407 struct vfs_dir_entry_t *dentry = vfs_path_walk(path, 0);
408 if (dentry == NULL && flags & O_CREAT)
409 {
410 // 先找到倒数第二级目录
411 int tmp_index = -1;
412 for (int i = path_len - 1; i >= 0; --i)
413 {
414 if (path[i] == '/')
415 {
416 tmp_index = i;
417 break;
418 }
419 }
420
421 struct vfs_dir_entry_t *parent_dentry = NULL;
422 // kdebug("tmp_index=%d", tmp_index);
423 if (tmp_index > 0)
424 {
425
426 path[tmp_index] = '\0';
427 parent_dentry = vfs_path_walk(path, 0);
428 if (parent_dentry == NULL)
429 {
430 kfree(path);
431 return -ENOENT;
432 }
433 }
434 else
435 {
436 parent_dentry = vfs_root_sb->root;
437 }
438 // 创建新的文件
439 dentry = vfs_alloc_dentry(path_len - tmp_index);
440
441 dentry->name_length = path_len - tmp_index - 2;
442
443 // kdebug("to create new file:%s namelen=%d", dentry->name, dentry->name_length);
444 strncpy(dentry->name, path + tmp_index + 1, dentry->name_length);
445 dentry->parent = parent_dentry;
446
447 // 对父目录项加锁
448 spin_lock(&parent_dentry->lockref.lock);
449 spin_lock(&parent_dentry->dir_inode->lockref.lock);
450 // 创建子目录项
451 uint64_t retval = parent_dentry->dir_inode->inode_ops->create(parent_dentry->dir_inode, dentry, 0);
452 spin_unlock(&parent_dentry->dir_inode->lockref.lock); // 解锁inode
453
454 if (retval != 0)
455 {
456 if (vfs_dentry_put(dentry) != 0) // 释放dentry
457 BUG_ON(1);
458 BUG_ON(1);
459 kfree(path);
460 spin_unlock(&parent_dentry->lockref.lock);
461 return retval;
462 }
463
464 // ==== 将子目录项添加到链表 ====
465 struct vfs_dir_entry_t *next_dentry = NULL;
466 // 若list非空,则对前一个dentry加锁
467 if (!list_empty(&parent_dentry->subdirs_list))
468 {
469 next_dentry = list_entry(list_next(&parent_dentry->subdirs_list), struct vfs_dir_entry_t, child_node_list);
470 spin_lock(&next_dentry->lockref.lock);
471 }
472 list_add(&parent_dentry->subdirs_list, &dentry->child_node_list);
473 if (next_dentry != NULL)
474 spin_unlock(&next_dentry->lockref.lock);
475
476 // 新建文件结束,对父目录项解锁
477 spin_unlock(&parent_dentry->lockref.lock);
478 // kdebug("created.");
479 }
480
481 kfree(path);
482 if (dentry == NULL)
483 {
484 return -ENOENT;
485 }
486 spin_lock(&dentry->lockref.lock);
487 // 要求打开文件夹而目标不是文件夹
488 if ((flags & O_DIRECTORY) && (dentry->dir_inode->attribute != VFS_IF_DIR))
489 {
490 spin_unlock(&dentry->lockref.lock);
491 return -ENOTDIR;
492 }
493 // 创建文件描述符
494 struct vfs_file_t *file_ptr = (struct vfs_file_t *)kzalloc(sizeof(struct vfs_file_t), 0);
495
496 int errcode = -1;
497
498 file_ptr->dEntry = dentry;
499 file_ptr->mode = flags;
500
501 file_ptr->file_ops = dentry->dir_inode->file_ops;
502
503 // 如果文件系统实现了打开文件的函数
504 if (file_ptr->file_ops && file_ptr->file_ops->open)
505 errcode = file_ptr->file_ops->open(dentry->dir_inode, file_ptr);
506
507 if (errcode != 0)
508 {
509 kfree(file_ptr);
510 spin_unlock(&dentry->lockref.lock);
511 return -EFAULT;
512 }
513
514 if (file_ptr->mode & O_TRUNC) // 清空文件
515 file_ptr->dEntry->dir_inode->file_size = 0;
516
517 if (file_ptr->mode & O_APPEND)
518 file_ptr->position = file_ptr->dEntry->dir_inode->file_size;
519 else
520 file_ptr->position = 0;
521
522 int fd_num = process_fd_alloc(file_ptr);
523
524 // 指针数组没有空位了
525 if (fd_num == -1)
526 {
527 kfree(file_ptr);
528 spin_unlock(&dentry->lockref.lock);
529 return -ENFILE;
530 }
531 spin_unlock(&dentry->lockref.lock);
532 return fd_num;
533 }
534
sys_open(struct pt_regs * regs)535 uint64_t sys_open(struct pt_regs *regs)
536 {
537 char *filename = (char *)(regs->r8);
538 int flags = (int)(regs->r9);
539 return do_open(filename, flags, true);
540 }
541
542 /**
543 * @brief 关闭文件
544 *
545 * @param fd_num 文件描述符
546 * @return uint64_t 错误码
547 */
vfs_close(int fd_num)548 uint64_t vfs_close(int fd_num)
549 {
550 // 校验文件描述符范围
551 if (fd_num < 0 || fd_num > PROC_MAX_FD_NUM)
552 return -EBADF;
553 // 文件描述符不存在
554 if (current_pcb->fds[fd_num] == NULL)
555 return -EBADF;
556 struct vfs_file_t *file_ptr = current_pcb->fds[fd_num];
557 uint64_t ret;
558 // If there is a valid close function
559 if (file_ptr->file_ops && file_ptr->file_ops->close)
560 ret = file_ptr->file_ops->close(file_ptr->dEntry->dir_inode, file_ptr);
561
562 kfree(file_ptr);
563 current_pcb->fds[fd_num] = NULL;
564 return 0;
565 }
566 /**
567 * @brief 动态分配dentry以及路径字符串名称
568 *
569 * @param name_size 名称字符串大小(字节)(注意考虑字符串最后需要有一个‘\0’作为结尾)
570 * @return struct vfs_dir_entry_t* 创建好的dentry
571 */
vfs_alloc_dentry(const int name_size)572 struct vfs_dir_entry_t *vfs_alloc_dentry(const int name_size)
573 {
574 if (unlikely(name_size > VFS_MAX_PATHLEN))
575 return NULL;
576 struct vfs_dir_entry_t *dentry = (struct vfs_dir_entry_t *)kzalloc(sizeof(struct vfs_dir_entry_t), 0);
577 if (unlikely(dentry == NULL))
578 return NULL;
579 if (name_size != 0)
580 dentry->name = (char *)kzalloc(name_size, 0);
581
582 // 初始化lockref
583 spin_init(&dentry->lockref.lock);
584 dentry->lockref.count = 1;
585 // 初始化链表
586 list_init(&dentry->child_node_list);
587 list_init(&dentry->subdirs_list);
588 return dentry;
589 }
590
591 /**
592 * @brief 判断是否可以删除指定的dentry
593 *
594 * 1、我们不能删除一个只读的dentry
595 * 2、我们应当对这个dentry的inode拥有写、执行权限(暂时还没有实现权限)
596 * 3、如果dentry指向的是文件夹,而isdir为false,则不能删除
597 * 3、如果dentry指向的是文件,而isdir为true,则不能删除
598 * @param dentry 将要被删除的dentry
599 * @param isdir 是否要删除文件夹
600 * @return int 错误码
601 */
vfs_may_delete(struct vfs_dir_entry_t * dentry,bool isdir)602 int vfs_may_delete(struct vfs_dir_entry_t *dentry, bool isdir)
603 {
604 // 当dentry没有inode的时候,认为是bug
605 BUG_ON(dentry->dir_inode == NULL);
606
607 // todo: 进行权限检查
608
609 if (isdir) // 要删除文件夹
610 {
611 if (!D_ISDIR(dentry))
612 return -ENOTDIR;
613 else if (IS_ROOT(dentry))
614 return -EBUSY;
615 }
616 else if (D_ISDIR(dentry)) // 要删除文件但是当前是文件夹
617 return -EISDIR;
618
619 return 0;
620 }
621
622 /**
623 * @brief 删除文件夹
624 *
625 * @param path 文件夹路径
626 * @param from_userland 请求是否来自用户态
627 * @return int64_t 错误码
628 */
vfs_rmdir(const char * path,bool from_userland)629 int64_t vfs_rmdir(const char *path, bool from_userland)
630 {
631 uint32_t pathlen;
632 int retval = 0;
633 if (from_userland)
634 pathlen = strnlen_user(path, PAGE_4K_SIZE - 1);
635 else
636 pathlen = strnlen(path, PAGE_4K_SIZE - 1);
637
638 if (pathlen == 0)
639 return -ENOENT;
640
641 int last_slash = -1;
642
643 // 去除末尾的'/'
644 for (int i = pathlen - 1; i >= 0; --i)
645 {
646 if (path[i] != '/')
647 {
648 last_slash = i + 1;
649 break;
650 }
651 }
652
653 // 路径格式不合法
654 if (last_slash < 0)
655 return -ENOTDIR;
656 else if (path[0] != '/')
657 return -EINVAL;
658
659 char *buf = (char *)kzalloc(last_slash + 2, 0);
660
661 // 拷贝字符串(不包含要被创建的部分)
662 if (from_userland)
663 strncpy_from_user(buf, path, last_slash);
664 else
665 strncpy(buf, path, last_slash);
666 buf[last_slash + 1] = '\0';
667
668 struct vfs_dir_entry_t *dentry = vfs_path_walk(buf, 0);
669
670 kfree(buf);
671
672 if (dentry == NULL)
673 {
674 retval = -ENOENT;
675 goto out0;
676 }
677
678 // todo: 检查文件夹是否为空
679
680 spin_lock(&dentry->lockref.lock);
681 retval = vfs_may_delete(dentry, true);
682 if (retval != 0)
683 goto out1;
684 // todo: 对dentry和inode加锁
685 retval = -EBUSY;
686 if (is_local_mountpoint(dentry))
687 goto out1;
688 // todo:
689 retval = dentry->dir_inode->inode_ops->rmdir(dentry->dir_inode, dentry);
690 if (retval != 0)
691 {
692 BUG_ON(1);
693 goto out1;
694 }
695
696 dentry->dir_inode->attribute |= VFS_IF_DEAD; // 将当前inode标记为dead
697 dont_mount(dentry); // 将当前dentry标记为不可被挂载
698 detach_mounts(dentry); // 清理同样挂载在该路径的所有挂载点的挂载树
699
700 // 释放dentry
701 retval = vfs_dentry_put(dentry);
702
703 if (retval != 0)
704 goto out1;
705 goto out0;
706 out2:;
707 spin_unlock(&dentry->dir_inode->lockref.lock);
708 out1:;
709 spin_unlock(&dentry->lockref.lock);
710 out0:;
711 return retval;
712 }
713
714 /**
715 * @brief unlink a filesystem object
716 *
717 * 调用者必须持有parent_inode->lockref.lock
718 *
719 * @param mnt_userns 暂时未使用 用户命名空间. 请置为NULL
720 * @param parent_inode 父目录项的inode
721 * @param dentry 要被删除的目录项
722 * @param delegated_inode 暂未使用,请置为NULL
723 * @return int
724 */
vfs_unlink(struct user_namespace * mnt_userns,struct vfs_index_node_t * parent_inode,struct vfs_dir_entry_t * dentry,struct vfs_index_node_t ** delegated_inode)725 int vfs_unlink(struct user_namespace *mnt_userns, struct vfs_index_node_t *parent_inode, struct vfs_dir_entry_t *dentry,
726 struct vfs_index_node_t **delegated_inode)
727 {
728 // 暂时不支持用户命名空间,因此发出警告
729 if (unlikely(mnt_userns != NULL))
730 {
731 WARN_ON(1);
732 return -EINVAL;
733 }
734
735 int retval = 0;
736 struct vfs_index_node_t *target = dentry->dir_inode;
737
738 retval = vfs_may_delete(dentry, false);
739 if (unlikely(retval != 0))
740 return retval;
741
742 // 没有unlink方法,则不允许删除
743 if (!parent_inode->inode_ops->unlink)
744 return -EPERM;
745
746 // 对inode加锁
747 spin_lock(&target->lockref.lock);
748
749 if (is_local_mountpoint(dentry))
750 retval = -EBUSY;
751 else
752 {
753 retval = parent_inode->inode_ops->unlink(parent_inode, dentry);
754 if (retval == 0)
755 {
756 dont_mount(dentry);
757 detach_mounts(dentry);
758 }
759 }
760
761 spin_unlock(&target->lockref.lock);
762
763 out:;
764 return retval;
765 }
766 /**
767 * @brief 取消dentry和inode之间的链接
768 *
769 * @param dfd 进程相对路径基准目录的文件描述符(fcntl.h)
770 * @param pathname 路径
771 * @param from_userland 请求是否来自用户态
772 * @return int 错误码
773 */
do_unlink_at(int dfd,const char * pathname,bool from_userland)774 int do_unlink_at(int dfd, const char *pathname, bool from_userland)
775 {
776 // 暂时不支持相对路径,只支持绝对路径
777 if (dfd & AT_FDCWD)
778 {
779 kwarn("Not support: AT_FDCWD");
780 return -EINVAL;
781 }
782
783 uint32_t pathlen;
784 int retval = 0;
785 if (from_userland)
786 pathlen = strnlen_user(pathname, PAGE_4K_SIZE - 1);
787 else
788 pathlen = strnlen(pathname, PAGE_4K_SIZE - 1);
789
790 if (pathlen == 0)
791 return -ENOENT;
792
793 int last_slash = -1;
794
795 // 去除末尾的'/'
796 for (int i = pathlen - 1; i >= 0; --i)
797 {
798 if (pathname[i] != '/')
799 {
800 last_slash = i + 1;
801 break;
802 }
803 }
804
805 // 路径格式不合法
806 if (last_slash < 0)
807 return -ENOTDIR;
808 else if (pathname[0] != '/')
809 return -EINVAL;
810
811 char *buf = (char *)kzalloc(last_slash + 1, 0);
812
813 // 拷贝字符串
814 if (from_userland)
815 strncpy_from_user(buf, pathname, last_slash);
816 else
817 strncpy(buf, pathname, last_slash);
818 buf[last_slash] = '\0';
819
820 struct vfs_dir_entry_t *dentry = vfs_path_walk(buf, 0);
821 kfree(buf);
822
823 if (dentry == NULL || dentry->parent == NULL)
824 {
825 retval = -ENOENT;
826 goto out;
827 }
828
829 struct vfs_index_node_t *p_inode = dentry->parent->dir_inode;
830 // 对父inode加锁
831 spin_lock(&p_inode->lockref.lock);
832 spin_lock(&dentry->lockref.lock);
833 retval = vfs_unlink(NULL, dentry->parent->dir_inode, dentry, NULL);
834 if (unlikely(retval != 0))
835 {
836 // kdebug("retval=%d", retval);
837 spin_unlock(&dentry->lockref.lock);
838 spin_unlock(&p_inode->lockref.lock);
839 goto out;
840 }
841 // kdebug("vfs_dentry_put=%d", retval);
842 spin_unlock(&dentry->lockref.lock);
843 spin_unlock(&p_inode->lockref.lock);
844
845 if (IS_ERR_VALUE(retval))
846 kwarn("In do_unlink_at: dentry put failed; retval=%d", retval);
847 else
848 retval = 0;
849 out:;
850 return retval;
851 }
852
853 /**
854 * @brief 删除文件夹、取消文件的链接、删除文件的系统调用
855 *
856 * @param regs->r8 dfd 进程相对路径基准目录的文件描述符(见fcntl.h)
857 * @param regs->r9 路径名称字符串
858 * @param regs->r10 flag 预留的标志位,暂时未使用,请置为0。
859 * @return uint64_t 错误码
860 */
sys_unlink_at(struct pt_regs * regs)861 uint64_t sys_unlink_at(struct pt_regs *regs)
862 {
863 int dfd = regs->r8;
864 const char *pathname = (const char *)regs->r9;
865 int flag = regs->r10;
866 bool from_user = SYSCALL_FROM_USER(regs) ? true : false;
867 if ((flag & (~AT_REMOVEDIR)) != 0)
868 return -EINVAL;
869 if (flag & AT_REMOVEDIR)
870 return vfs_rmdir(pathname, from_user);
871 // kdebug("to do_unlink_at, path=%s", pathname);
872 return do_unlink_at(dfd, pathname, from_user);
873 }
874
875 /**
876 * @brief 分配inode并将引用计数初始化为1
877 *
878 * @return struct vfs_index_node_t * 分配得到的inode
879 */
vfs_alloc_inode()880 struct vfs_index_node_t *vfs_alloc_inode()
881 {
882 struct vfs_index_node_t *inode = kzalloc(sizeof(struct vfs_index_node_t), 0);
883 spin_init(&inode->lockref.lock);
884 inode->lockref.count = 1; // 初始化引用计数为1
885 return inode;
886 }
887
888 /**
889 * @brief 初始化vfs
890 *
891 * @return int 错误码
892 */
vfs_init()893 int vfs_init()
894 {
895 mount_init();
896 rootfs_init();
897 return 0;
898 }