RT-Thread RTOS 1.2.0
An open source embedded real-time operating system
载入中...
搜索中...
未找到
dfs_fs.c
浏览该文件的文档.
1/*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2005-02-22 Bernard The first version.
9 * 2010-06-30 Bernard Optimize for RT-Thread RTOS
10 * 2011-03-12 Bernard fix the filesystem lookup issue.
11 * 2017-11-30 Bernard fix the filesystem_operation_table issue.
12 * 2017-12-05 Bernard fix the fs type search issue in mkfs.
13 * 2023-05-05 Bernard change to dfs v2.0
14 */
15
16#include <dfs_fs.h>
17#include <dfs_file.h>
18#include <dfs_dentry.h>
19#include <dfs_mnt.h>
20#include "dfs_private.h"
21
22#ifdef RT_USING_PAGECACHE
23#include "dfs_pcache.h"
24#endif
25
26#define DBG_TAG "DFS.fs"
27#define DBG_LVL DBG_INFO
28#include <rtdbg.h>
29
30static struct dfs_filesystem_type *file_systems = NULL;
31extern rt_list_t _mnt_list;
32
37
38static struct dfs_filesystem_type **_find_filesystem(const char *name)
39{
40 struct dfs_filesystem_type **type;
41 for (type = &file_systems; *type; type = &(*type)->next)
42 {
43 if (strcmp((*type)->fs_ops->name, name) == 0)
44 break;
45 }
46
47 return type;
48}
49
51{
52 return file_systems;
53}
54
56{
57 int ret = 0;
58 struct dfs_filesystem_type **type = _find_filesystem(fs->fs_ops->name);
59
60 LOG_D("register %s file system.", fs->fs_ops->name);
61
62 if (*type)
63 {
64 ret = -EBUSY;
65 }
66 else
67 {
68 *type = fs;
69 }
70
71 return ret;
72}
73
75{
76 int ret = 0;
77 struct dfs_filesystem_type **type;
78
79 if (fs)
80 {
81 LOG_D("unregister %s file system.", fs->fs_ops->name);
82
83 for (type = &file_systems; *type; type = &(*type)->next)
84 {
85 if (strcmp((*type)->fs_ops->name, fs->fs_ops->name) == 0)
86 {
87 *type = (*type)->next;
88 break;
89 }
90 }
91
92 if (!*type) ret = -EINVAL;
93 }
94
95 return ret;
96}
97
98#define REMNT_UNSUPP_FLAGS (~(MS_REMOUNT | MS_RMT_MASK))
99int dfs_remount(const char *path, rt_ubase_t flags, void *data)
100{
101 int rc = 0;
102 char *fullpath = RT_NULL;
103 struct dfs_mnt *mnt = RT_NULL;
104
106 {
107 return -EINVAL;
108 }
109
111 if (!fullpath)
112 {
113 rc = -ENOENT;
114 }
115 else
116 {
117 DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt = dfs_mnt_lookup(%s)", fullpath);
119 if (mnt)
120 {
121 dfs_lock();
123 dfs_unlock();
124 }
125 else
126 {
127 struct stat buf = {0};
128 if (dfs_file_stat(fullpath, &buf) == 0 && S_ISBLK(buf.st_mode))
129 {
130 /* path was not already mounted on target */
131 rc = -EINVAL;
132 }
133 else
134 {
135 /* path is not a directory */
136 rc = -ENOTDIR;
137 }
138 }
139 }
140
141 return rc;
142}
143
144/*
145 * parent(mount path)
146 * mnt_parent <- - - - - - - +
147 * | |
148 * |- mnt_child <- - - - - -+ (1 refcount)
149 * | |
150 * |- parent - - + (1 refcount)
151 */
152int dfs_mount(const char *device_name,
153 const char *path,
154 const char *filesystemtype,
155 unsigned long rwflag,
156 const void *data)
157{
158 int ret = RT_EOK;
159 char *fullpath = RT_NULL;
160 rt_device_t dev_id = RT_NULL;
161 struct dfs_mnt *mnt_parent = RT_NULL, *mnt_child = RT_NULL;
162 struct dfs_dentry *mntpoint_dentry = RT_NULL;
163 struct dfs_filesystem_type *type = *_find_filesystem(filesystemtype);
164
165 if (type)
166 {
167 fullpath = dfs_normalize_path(RT_NULL, path);
168 if (!fullpath)
169 {
170 rt_set_errno(EPERM);
171 ret = -1;
172 }
173 }
174 else
175 {
176 rt_set_errno(ENODEV);
177 ret = -1;
178 }
179
180 if (fullpath)
181 {
182 DLOG(note, "mnt", "mount %s(%s) on path: %s", device_name, filesystemtype, fullpath);
183
184 /* open specific device */
185 if (device_name) dev_id = rt_device_find(device_name);
186
187 if (!(type->fs_ops->flags & FS_NEED_DEVICE) ||
188 ((type->fs_ops->flags & FS_NEED_DEVICE) && dev_id))
189 {
190 DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt_parent = dfs_mnt_lookup(%s)", fullpath);
191 mnt_parent = dfs_mnt_lookup(fullpath);
192 if ((!mnt_parent && (strcmp(fullpath, "/") == 0 || strcmp(fullpath, "/dev") == 0))
193 || (mnt_parent && strcmp(fullpath, "/") == 0 && strcmp(mnt_parent->fullpath, fullpath) != 0))
194 {
195 LOG_D("no mnt found @ mount point %s, should be root.", fullpath);
196 DLOG(msg, "mnt", "dfs", DLOG_MSG_RET, "no mnt");
197
198 /* it's the root file system */
199 /* the mount point dentry is the same as root dentry. */
200
201 DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt_parent = dfs_mnt_create(path)");
202 mnt_parent = dfs_mnt_create(fullpath); /* mnt->ref_count should be 1. */
203 if (mnt_parent)
204 {
205 DLOG(msg, "mnt", "dfs", DLOG_MSG_RET, "return mnt, ref_count=1");
206
207 mnt_parent->fs_ops = type->fs_ops;
208 mnt_parent->dev_id = dev_id;
209 if (mnt_parent->fs_ops->mount)
210 {
211 DLOG(msg, "dfs", type->fs_ops->name, DLOG_MSG, "fs_ops->mount(mnt_parent, rwflag, data)");
212 ret = mnt_parent->fs_ops->mount(mnt_parent, rwflag, data);
213 if (ret == RT_EOK)
214 {
215 DLOG(msg, type->fs_ops->name, "dfs", DLOG_MSG_RET, "mount OK, ret root_dentry");
216
217 mnt_child = mnt_parent;
218 mnt_child->flags |= MNT_IS_MOUNTED;
219
220 DLOG(note_right, "mnt", "mount sucessfully");
221 DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_insert(, mnt_child)");
222 dfs_mnt_insert(RT_NULL, mnt_child);
223
224 /* unref it, because the ref_count = 1 when create */
225 DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_unref(mnt_parent)");
226 dfs_mnt_unref(mnt_parent);
227
228 /*
229 * About root mnt:
230 * There are two ref_count:
231 * 1. the gobal root reference.
232 * 1. the mnt->parent reference.
233 */
234 }
235 else
236 {
237 LOG_W("mount %s failed with file system type: %s", fullpath, type->fs_ops->name);
238 DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_destroy(mnt_parent)");
239 dfs_mnt_destroy(mnt_parent);
240 mnt_parent = RT_NULL;
241 rt_set_errno(EPERM);
242 ret = -1;
243 }
244 }
245 else
246 {
247 LOG_W("no mount method on file system type: %s", type->fs_ops->name);
248 DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_destroy(mnt_parent), no mount method");
249 dfs_mnt_destroy(mnt_parent);
250 mnt_parent = RT_NULL;
251 rt_set_errno(EIO);
252 ret = -1;
253 }
254 }
255 else
256 {
257 LOG_E("create a mnt point failed.");
258 rt_set_errno(ENOMEM);
259 ret = -1;
260 }
261 }
262 else if (mnt_parent && (strcmp(mnt_parent->fullpath, fullpath) != 0))
263 {
264 DLOG(msg, "dfs", "dentry", DLOG_MSG, "mntpoint_dentry = dfs_dentry_lookup(mnt_parent, %s, 0)", fullpath);
265 mntpoint_dentry = dfs_dentry_lookup(mnt_parent, fullpath, 0);
266 if (mntpoint_dentry)
267 {
268 DLOG(msg, "dentry", "dfs", DLOG_MSG_RET, "dentry exist");
269 DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt_child = dfs_mnt_create(path)");
270 mnt_child = dfs_mnt_create(fullpath);
271 if (mnt_child)
272 {
273 LOG_D("create mnt point %p", mnt_child);
274
275 mnt_child->fs_ops = type->fs_ops;
276 mnt_child->dev_id = dev_id;
277
278 if (mnt_child->fs_ops->mount)
279 {
280 DLOG(msg, "dfs", type->fs_ops->name, DLOG_MSG, "root_dentry = fs_ops->mount(mnt_child, rwflag, data)");
281 ret = mnt_child->fs_ops->mount(mnt_child, rwflag, data);
282 if (ret == RT_EOK)
283 {
284 mnt_child->flags |= MNT_IS_MOUNTED;
285
286 LOG_D("mount %s sucessfully", fullpath);
287 DLOG(msg, mnt_child->fs_ops->name, "dfs", DLOG_MSG_RET, "mount OK");
288
289 DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_insert(mnt_parent, mnt_child)");
290 dfs_mnt_insert(mnt_parent, mnt_child);
291
292 /* unref it, because the ref_count = 1 when create */
293 DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_unref(mnt_child)");
294 dfs_mnt_unref(mnt_child);
295 }
296 else
297 {
298 LOG_W("mount %s failed with file system type: %s", fullpath, type->fs_ops->name);
299 DLOG(msg, mnt_child->fs_ops->name, "dfs", DLOG_MSG_RET, "mount failed");
300 dfs_mnt_destroy(mnt_child);
301 rt_set_errno(EPERM);
302 ret = -1;
303 }
304 }
305 else
306 {
307 LOG_W("no mount method on file system type: %s", type->fs_ops->name);
308 dfs_mnt_destroy(mnt_child);
309 rt_set_errno(EIO);
310 ret = -1;
311 }
312 }
313 else
314 {
315 LOG_E("create a mnt point failed.");
316 rt_set_errno(ENOMEM);
317 ret = -1;
318 }
319 dfs_dentry_unref(mntpoint_dentry);
320 }
321 else
322 {
323 LOG_W("no mount point (%s) in file system: %s", fullpath, mnt_parent->fullpath);
324 rt_set_errno(ENOTDIR);
325 ret = -1;
326 }
327 }
328 else
329 {
330 LOG_E("mount point (%s) already mounted!", fullpath);
331 rt_set_errno(EEXIST);
332 ret = -1;
333 }
334 }
335 else
336 {
337 LOG_E("No device found for this file system.");
338 rt_set_errno(ENODEV);
339 ret = -1;
340 }
341 rt_free(fullpath);
342 }
343
344 return ret;
345}
346
347int dfs_umount(const char *specialfile, int flags)
348{
349 int ret = -1;
350 char *fullpath = RT_NULL;
351 struct dfs_mnt *mnt = RT_NULL;
352
353 fullpath = dfs_normalize_path(NULL, specialfile);
354 if (fullpath)
355 {
356 DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt = dfs_mnt_lookup(%s)", fullpath);
358 if (mnt)
359 {
360 if (strcmp(mnt->fullpath, fullpath) == 0)
361 {
362 /* is the mount point */
364
365 if (!(mnt->flags & MNT_IS_LOCKED) && rt_list_isempty(&mnt->child) && (ref_count == 1 || (flags & MNT_FORCE)))
366 {
367#ifdef RT_USING_PAGECACHE
368 dfs_pcache_unmount(mnt);
369#endif
370 /* destroy this mount point */
371 DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_destroy(mnt)");
372 ret = dfs_mnt_destroy(mnt);
373 }
374 else
375 {
376 LOG_I("the file system is busy!");
377 ret = -EBUSY;
378 }
379 }
380 else
381 {
382 LOG_I("the path:%s is not a mountpoint!", fullpath);
383 ret = -EINVAL;
384 }
385 }
386 else
387 {
388 LOG_I("no filesystem found.");
389 }
391 }
392 else
393 {
394 rt_set_errno(-ENOTDIR);
395 }
396
397 return ret;
398}
399
400/* for compatibility */
401int dfs_unmount(const char *specialfile)
402{
403 return dfs_umount(specialfile, 0);
404}
405
406int dfs_is_mounted(struct dfs_mnt *mnt)
407{
408 int ret = 0;
409
410 if (mnt && !(mnt->flags & MNT_IS_MOUNTED))
411 {
412 ret = -1;
413 }
414
415 return ret;
416}
417
418int dfs_mkfs(const char *fs_name, const char *device_name)
419{
420 rt_device_t dev_id = NULL;
421 struct dfs_filesystem_type *type;
422 int ret = -RT_ERROR;
423
424 type = *_find_filesystem(fs_name);
425 if (!type)
426 {
427 rt_kprintf("no file system: %s found!\n", fs_name);
428 return ret;
429 }
430 else
431 {
432 if (type->fs_ops->flags & FS_NEED_DEVICE)
433 {
434 /* check device name, and it should not be NULL */
435 if (device_name != NULL)
436 dev_id = rt_device_find(device_name);
437
438 if (dev_id == NULL)
439 {
440 rt_set_errno(-ENODEV);
441 rt_kprintf("Device (%s) was not found", device_name);
442 return ret;
443 }
444 }
445 else
446 {
447 dev_id = RT_NULL;
448 }
449 }
450
451 if (type->fs_ops->mkfs)
452 {
453 ret = type->fs_ops->mkfs(dev_id, type->fs_ops->name);
454#ifdef RT_USING_PAGECACHE
455 if (ret == RT_EOK)
456 {
457 struct dfs_mnt *mnt = RT_NULL;
458
460 if (mnt)
461 {
462 dfs_pcache_unmount(mnt);
463 }
464 }
465#endif
466 }
467
468 return ret;
469}
470
471int dfs_statfs(const char *path, struct statfs *buffer)
472{
473 struct dfs_mnt *mnt;
474 char *fullpath;
475 int ret = -RT_ERROR;
476
477 fullpath = dfs_normalize_path(NULL, path);
478 if (!fullpath)
479 {
480 return ret;
481 }
482
483 DLOG(msg, "dfs_file", "mnt", DLOG_MSG, "dfs_mnt_lookup(%s)", fullpath);
485 if (mnt)
486 {
487 if (mnt->fs_ops->statfs)
488 {
489 if (dfs_is_mounted(mnt) == 0)
490 {
491 ret = mnt->fs_ops->statfs(mnt, buffer);
492 }
493 }
494 }
495
496 return ret;
497}
498
507{
508 const char *path = NULL;
509
510 return path;
511}
512
523 uint8_t *buf,
524 uint32_t pindex)
525{
526#define DPT_ADDRESS 0x1be /* device partition offset in Boot Sector */
527#define DPT_ITEM_SIZE 16 /* partition item size */
528
529 uint8_t *dpt;
530 uint8_t type;
531
532 RT_ASSERT(part != NULL);
533 RT_ASSERT(buf != NULL);
534
535 dpt = buf + DPT_ADDRESS + pindex * DPT_ITEM_SIZE;
536
537 /* check if it is a valid partition table */
538 if ((*dpt != 0x80) && (*dpt != 0x00))
539 return -EIO;
540
541 /* get partition type */
542 type = *(dpt + 4);
543 if (type == 0)
544 return -EIO;
545
546 /* set partition information
547 * size is the number of 512-Byte */
548 part->type = type;
549 part->offset = *(dpt + 8) | *(dpt + 9) << 8 | *(dpt + 10) << 16 | *(dpt + 11) << 24;
550 part->size = *(dpt + 12) | *(dpt + 13) << 8 | *(dpt + 14) << 16 | *(dpt + 15) << 24;
551
552 rt_kprintf("found part[%d], begin: %ld, size: ",
553 pindex, part->offset * 512);
554 if ((part->size >> 11) == 0)
555 rt_kprintf("%ld%s", part->size >> 1, "KB\n"); /* KB */
556 else
557 {
558 unsigned int part_size;
559 part_size = part->size >> 11; /* MB */
560 if ((part_size >> 10) == 0)
561 rt_kprintf("%d.%ld%s", part_size, (part->size >> 1) & 0x3FF, "MB\n");
562 else
563 rt_kprintf("%d.%d%s", part_size >> 10, part_size & 0x3FF, "GB\n");
564 }
565
566 return RT_EOK;
567}
568
569/* @} */
rt_err_t dfs_lock(void)
定义 dfs.c:120
void dfs_unlock(void)
定义 dfs.c:137
struct dfs_dentry * dfs_dentry_lookup(struct dfs_mnt *mnt, const char *path, uint32_t flags)
struct dfs_dentry * dfs_dentry_unref(struct dfs_dentry *dentry)
int dfs_file_stat(const char *path, struct stat *buf)
int dfs_statfs(const char *path, struct statfs *buffer)
int dfs_unregister(struct dfs_filesystem_type *fs)
rt_list_t _mnt_list
#define DPT_ADDRESS
int dfs_mkfs(const char *fs_name, const char *device_name)
#define REMNT_UNSUPP_FLAGS
int dfs_is_mounted(struct dfs_mnt *mnt)
int dfs_mount(const char *device_name, const char *path, const char *filesystemtype, unsigned long rwflag, const void *data)
#define DPT_ITEM_SIZE
const char * dfs_filesystem_get_mounted_path(struct rt_device *device)
int dfs_unmount(const char *specialfile)
int dfs_umount(const char *specialfile, int flags)
int dfs_register(struct dfs_filesystem_type *fs)
int dfs_filesystem_get_partition(struct dfs_partition *part, uint8_t *buf, uint32_t pindex)
struct dfs_filesystem_type * dfs_filesystems(void)
int dfs_remount(const char *path, rt_ubase_t flags, void *data)
#define FS_NEED_DEVICE
int dfs_mnt_insert(struct dfs_mnt *mnt, struct dfs_mnt *child)
int dfs_mnt_setflags(struct dfs_mnt *mnt, int flags)
struct dfs_mnt * dfs_mnt_dev_lookup(rt_device_t dev_id)
int dfs_mnt_unref(struct dfs_mnt *mnt)
int dfs_mnt_destroy(struct dfs_mnt *mnt)
struct dfs_mnt * dfs_mnt_lookup(const char *fullpath)
struct dfs_mnt * dfs_mnt_create(const char *path)
#define MNT_IS_MOUNTED
#define MNT_FORCE
#define MNT_IS_LOCKED
char * dfs_normalize_path(const char *directory, const char *filename)
定义 dfs.c:779
rt_device_t rt_device_find(const char *name)
struct rt_device * rt_device_t
int stat(const char *file, struct stat *buf)
int statfs(const char *path, struct statfs *buf)
rt_inline int rt_list_isempty(const rt_list_t *l)
tests whether a list is empty
#define rt_kprintf(...)
#define RT_ASSERT(EX)
rt_weak void rt_free(void *ptr)
This function will release the previously allocated memory block by rt_malloc. The released memory bl...
#define rt_atomic_load(ptr)
#define DLOG(...)
定义 rtdbg.h:53
#define LOG_W(...)
#define LOG_D(...)
#define LOG_E(fmt,...)
#define LOG_I(...)
rt_int32_t rt_base_t
struct rt_list_node rt_list_t
rt_uint32_t rt_ubase_t
#define RT_NULL
int(* mkfs)(rt_device_t devid, const char *fs_name)
int(* statfs)(struct dfs_mnt *mnt, struct statfs *buf)
const char * name
int(* mount)(struct dfs_mnt *mnt, unsigned long rwflag, const void *data)
const struct dfs_filesystem_ops * fs_ops
struct dfs_filesystem_type * next
char * fullpath
rt_device_t dev_id
const struct dfs_filesystem_ops * fs_ops
rt_list_t child
rt_atomic_t ref_count