RT-Thread RTOS 1.2.0
An open source embedded real-time operating system
载入中...
搜索中...
未找到
dfs_fs.c 文件参考
#include <dfs_fs.h>
#include <dfs_file.h>
#include <dfs_dentry.h>
#include <dfs_mnt.h>
#include "dfs_private.h"
#include <rtdbg.h>
+ dfs_fs.c 的引用(Include)关系图:

浏览该文件的源代码.

宏定义

#define DBG_TAG   "DFS.fs"
 
#define DBG_LVL   DBG_INFO
 
#define REMNT_UNSUPP_FLAGS   (~(MS_REMOUNT | MS_RMT_MASK))
 
#define DPT_ADDRESS   0x1be /* device partition offset in Boot Sector */
 
#define DPT_ITEM_SIZE   16 /* partition item size */
 

函数

struct dfs_filesystem_typedfs_filesystems (void)
 
int dfs_register (struct dfs_filesystem_type *fs)
 
int dfs_unregister (struct dfs_filesystem_type *fs)
 
int dfs_remount (const char *path, rt_ubase_t flags, void *data)
 
int dfs_mount (const char *device_name, const char *path, const char *filesystemtype, unsigned long rwflag, const void *data)
 
int dfs_umount (const char *specialfile, int flags)
 
int dfs_unmount (const char *specialfile)
 
int dfs_is_mounted (struct dfs_mnt *mnt)
 
int dfs_mkfs (const char *fs_name, const char *device_name)
 
int dfs_statfs (const char *path, struct statfs *buffer)
 
const char * dfs_filesystem_get_mounted_path (struct rt_device *device)
 
int dfs_filesystem_get_partition (struct dfs_partition *part, uint8_t *buf, uint32_t pindex)
 

变量

rt_list_t _mnt_list
 

宏定义说明

◆ DBG_TAG

#define DBG_TAG   "DFS.fs"

在文件 dfs_fs.c26 行定义.

◆ DBG_LVL

#define DBG_LVL   DBG_INFO

在文件 dfs_fs.c27 行定义.

◆ REMNT_UNSUPP_FLAGS

#define REMNT_UNSUPP_FLAGS   (~(MS_REMOUNT | MS_RMT_MASK))

在文件 dfs_fs.c98 行定义.

◆ DPT_ADDRESS

#define DPT_ADDRESS   0x1be /* device partition offset in Boot Sector */

◆ DPT_ITEM_SIZE

#define DPT_ITEM_SIZE   16 /* partition item size */

函数说明

◆ dfs_filesystems()

struct dfs_filesystem_type * dfs_filesystems ( void )

在文件 dfs_fs.c50 行定义.

51{
52 return file_systems;
53}

◆ dfs_register()

int dfs_register ( struct dfs_filesystem_type * fs)

在文件 dfs_fs.c55 行定义.

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}
#define LOG_D(...)
const char * name
const struct dfs_filesystem_ops * fs_ops

引用了 dfs_filesystem_type::fs_ops, LOG_D , 以及 dfs_filesystem_ops::name.

◆ dfs_unregister()

int dfs_unregister ( struct dfs_filesystem_type * fs)

在文件 dfs_fs.c74 行定义.

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}
struct dfs_filesystem_type * next

引用了 dfs_filesystem_type::fs_ops, LOG_D, dfs_filesystem_ops::name , 以及 dfs_filesystem_type::next.

◆ dfs_remount()

int dfs_remount ( const char * path,
rt_ubase_t flags,
void * data )

在文件 dfs_fs.c99 行定义.

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}
rt_err_t dfs_lock(void)
定义 dfs.c:120
void dfs_unlock(void)
定义 dfs.c:137
int dfs_file_stat(const char *path, struct stat *buf)
#define REMNT_UNSUPP_FLAGS
int dfs_mnt_setflags(struct dfs_mnt *mnt, int flags)
struct dfs_mnt * dfs_mnt_lookup(const char *fullpath)
char * dfs_normalize_path(const char *directory, const char *filename)
定义 dfs.c:779
int stat(const char *file, struct stat *buf)
#define DLOG(...)
定义 rtdbg.h:53
#define RT_NULL
char * fullpath

引用了 dfs_file_stat(), dfs_lock(), dfs_mnt_lookup(), dfs_mnt_setflags(), dfs_normalize_path(), dfs_unlock(), DLOG, dfs_mnt::flags, dfs_mnt::fullpath, REMNT_UNSUPP_FLAGS, RT_NULL , 以及 stat().

+ 函数调用图:

◆ dfs_mount()

int dfs_mount ( const char * device_name,
const char * path,
const char * filesystemtype,
unsigned long rwflag,
const void * data )

在文件 dfs_fs.c152 行定义.

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}
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)
#define FS_NEED_DEVICE
int dfs_mnt_insert(struct dfs_mnt *mnt, struct dfs_mnt *child)
int dfs_mnt_unref(struct dfs_mnt *mnt)
int dfs_mnt_destroy(struct dfs_mnt *mnt)
struct dfs_mnt * dfs_mnt_create(const char *path)
#define MNT_IS_MOUNTED
rt_device_t rt_device_find(const char *name)
struct rt_device * rt_device_t
rt_weak void rt_free(void *ptr)
This function will release the previously allocated memory block by rt_malloc. The released memory bl...
#define LOG_W(...)
#define LOG_E(fmt,...)
int(* mount)(struct dfs_mnt *mnt, unsigned long rwflag, const void *data)
rt_device_t dev_id
const struct dfs_filesystem_ops * fs_ops

引用了 dfs_mnt::dev_id, dfs_dentry_lookup(), dfs_dentry_unref(), dfs_mnt_create(), dfs_mnt_destroy(), dfs_mnt_insert(), dfs_mnt_lookup(), dfs_mnt_unref(), dfs_normalize_path(), DLOG, dfs_filesystem_ops::flags, dfs_mnt::flags, FS_NEED_DEVICE, dfs_filesystem_type::fs_ops, dfs_mnt::fs_ops, dfs_mnt::fullpath, LOG_D, LOG_E, LOG_W, MNT_IS_MOUNTED, dfs_filesystem_ops::mount, dfs_filesystem_ops::name, rt_device_find(), rt_free() , 以及 RT_NULL.

+ 函数调用图:

◆ dfs_umount()

int dfs_umount ( const char * specialfile,
int flags )

在文件 dfs_fs.c347 行定义.

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}
#define MNT_FORCE
#define MNT_IS_LOCKED
rt_inline int rt_list_isempty(const rt_list_t *l)
tests whether a list is empty
#define rt_atomic_load(ptr)
#define LOG_I(...)
rt_int32_t rt_base_t
rt_list_t child
rt_atomic_t ref_count

引用了 dfs_mnt::child, dfs_mnt_destroy(), dfs_mnt_lookup(), dfs_normalize_path(), DLOG, dfs_mnt::flags, dfs_mnt::fullpath, LOG_I, MNT_FORCE, MNT_IS_LOCKED, dfs_mnt::ref_count, rt_atomic_load, rt_free(), rt_list_isempty() , 以及 RT_NULL.

+ 函数调用图:
+ 这是这个函数的调用关系图:

◆ dfs_unmount()

int dfs_unmount ( const char * specialfile)

在文件 dfs_fs.c401 行定义.

402{
403 return dfs_umount(specialfile, 0);
404}
int dfs_umount(const char *specialfile, int flags)

引用了 dfs_umount().

+ 函数调用图:

◆ dfs_is_mounted()

int dfs_is_mounted ( struct dfs_mnt * mnt)

在文件 dfs_fs.c406 行定义.

407{
408 int ret = 0;
409
410 if (mnt && !(mnt->flags & MNT_IS_MOUNTED))
411 {
412 ret = -1;
413 }
414
415 return ret;
416}

引用了 dfs_mnt::flags , 以及 MNT_IS_MOUNTED.

◆ dfs_mkfs()

int dfs_mkfs ( const char * fs_name,
const char * device_name )

在文件 dfs_fs.c418 行定义.

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}
struct dfs_mnt * dfs_mnt_dev_lookup(rt_device_t dev_id)
#define rt_kprintf(...)
int(* mkfs)(rt_device_t devid, const char *fs_name)

引用了 dfs_mnt::dev_id, dfs_mnt_dev_lookup(), dfs_filesystem_ops::flags, FS_NEED_DEVICE, dfs_filesystem_type::fs_ops, dfs_filesystem_ops::mkfs, dfs_filesystem_ops::name, rt_device_find(), rt_kprintf , 以及 RT_NULL.

+ 函数调用图:

◆ dfs_statfs()

int dfs_statfs ( const char * path,
struct statfs * buffer )

在文件 dfs_fs.c471 行定义.

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}
int dfs_is_mounted(struct dfs_mnt *mnt)
int(* statfs)(struct dfs_mnt *mnt, struct statfs *buf)

引用了 dfs_is_mounted(), dfs_mnt_lookup(), dfs_normalize_path(), DLOG, dfs_mnt::fs_ops, dfs_mnt::fullpath, dfs_filesystem_ops::statfs , 以及 statfs().

+ 函数调用图:
+ 这是这个函数的调用关系图:

◆ dfs_filesystem_get_mounted_path()

const char * dfs_filesystem_get_mounted_path ( struct rt_device * device)

this function will return the mounted path for specified device.

参数
devicethe device object which is mounted.
返回
the mounted path or NULL if none device mounted.

在文件 dfs_fs.c506 行定义.

507{
508 const char *path = NULL;
509
510 return path;
511}

◆ dfs_filesystem_get_partition()

int dfs_filesystem_get_partition ( struct dfs_partition * part,
uint8_t * buf,
uint32_t pindex )

this function will fetch the partition table on specified buffer.

参数
partthe returned partition structure.
bufthe buffer contains partition table.
pindexthe index of partition table to fetch.
返回
RT_EOK on successful or -RT_ERROR on failed.

在文件 dfs_fs.c522 行定义.

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}
#define DPT_ADDRESS
#define DPT_ITEM_SIZE
#define RT_ASSERT(EX)

引用了 DPT_ADDRESS, DPT_ITEM_SIZE, dfs_partition::offset, RT_ASSERT, rt_kprintf, dfs_partition::size , 以及 dfs_partition::type.

变量说明

◆ _mnt_list

rt_list_t _mnt_list
extern