dfs_mnt.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. /*
  2. * Copyright (c) 2006-2025 RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-05-05 Bernard Implement mnt in dfs v2.0
  9. */
  10. #include <rtthread.h>
  11. #include "dfs_private.h"
  12. #include <dfs.h>
  13. #include <dfs_dentry.h>
  14. #include <dfs_mnt.h>
  15. #include <dfs_pcache.h>
  16. #define DBG_TAG "DFS.mnt"
  17. #define DBG_LVL DBG_WARNING
  18. #include <rtdbg.h>
  19. static struct dfs_mnt *_root_mnt = RT_NULL;
  20. RT_OBJECT_HOOKLIST_DEFINE(dfs_mnt_umnt);
  21. /*
  22. * mnt tree structure
  23. *
  24. * mnt_root <----------------------------------------+
  25. * | (child) +----------+ |
  26. * v (sibling) v | |
  27. * mnt_child0 -> mnt_child1 | |
  28. * | (child) | |
  29. * v / (parent) | (root)
  30. * mnt_child10 ---/
  31. *
  32. */
  33. /**
  34. * @brief Create a new dfs_mnt structure instance.
  35. *
  36. * This function allocates memory to create a new dfs_mnt structure instance and initializes it.
  37. * If the memory allocation is successful, it copies the input path string into the instance and initializes related lists and flags.
  38. *
  39. * @param[in] path The path string to be mounted. This path information will be copied to the newly created dfs_mnt instance.
  40. *
  41. * @return If the memory allocation is successful, returns a pointer to the newly created dfs_mnt structure;
  42. * if the memory allocation fails, returns RT_NULL.
  43. */
  44. struct dfs_mnt *dfs_mnt_create(const char *path)
  45. {
  46. struct dfs_mnt *mnt = rt_calloc(1, sizeof(struct dfs_mnt));
  47. if (mnt)
  48. {
  49. LOG_I("create mnt at %s", path);
  50. mnt->fullpath = rt_strdup(path);
  51. rt_list_init(&mnt->sibling);
  52. rt_list_init(&mnt->child);
  53. mnt->flags |= MNT_IS_ALLOCED;
  54. rt_atomic_store(&(mnt->ref_count), 1);
  55. }
  56. else
  57. {
  58. rt_set_errno(-ENOMEM);
  59. }
  60. return mnt;
  61. }
  62. /**
  63. * @brief Insert a child mount point into the mount tree.
  64. *
  65. * This function inserts a child mount point into the specified parent mount point's child list.
  66. * If the parent mount point is not provided, it will try to find the appropriate mount point based on the child's path.
  67. * If the child mount point is the root, it will update the global root mount point accordingly.
  68. *
  69. * @param[in,out] mnt Pointer to the parent dfs_mnt structure. If NULL, it will be updated to the appropriate mount point.
  70. * @param[in] child Pointer to the child dfs_mnt structure to be inserted.
  71. *
  72. * @return Always returns 0 to indicate success.
  73. */
  74. int dfs_mnt_insert(struct dfs_mnt* mnt, struct dfs_mnt* child)
  75. {
  76. if (child)
  77. {
  78. if (mnt == RT_NULL)
  79. {
  80. /* insert into root */
  81. mnt = dfs_mnt_lookup(child->fullpath);
  82. if (mnt == RT_NULL || (strcmp(child->fullpath, "/") == 0))
  83. {
  84. /* it's root mnt */
  85. mnt = child;
  86. mnt->flags |= MNT_IS_LOCKED;
  87. /* ref to gobal root */
  88. if (_root_mnt)
  89. {
  90. child = _root_mnt;
  91. rt_atomic_sub(&(_root_mnt->parent->ref_count), 1);
  92. rt_atomic_sub(&(_root_mnt->ref_count), 1);
  93. _root_mnt->flags &= ~MNT_IS_LOCKED;
  94. _root_mnt = dfs_mnt_ref(mnt);
  95. mnt->parent = dfs_mnt_ref(mnt);
  96. mnt->flags |= MNT_IS_ADDLIST;
  97. mkdir("/dev", 0777);
  98. }
  99. else
  100. {
  101. _root_mnt = dfs_mnt_ref(mnt);
  102. }
  103. }
  104. }
  105. if (mnt)
  106. {
  107. child->flags |= MNT_IS_ADDLIST;
  108. if (child != mnt)
  109. {
  110. /* not the root, insert into the child list */
  111. rt_list_insert_before(&mnt->child, &child->sibling);
  112. /* child ref self */
  113. dfs_mnt_ref(child);
  114. }
  115. /* parent ref parent */
  116. child->parent = dfs_mnt_ref(mnt);
  117. }
  118. }
  119. return 0;
  120. }
  121. /**
  122. * @brief Remove a mount point from the mount tree.
  123. *
  124. * This function attempts to remove a specified mount point from the mount tree.
  125. * It can only remove a mount point if it has no child mount points. If the mount point
  126. * has children, it logs a warning message instead of performing the removal.
  127. *
  128. * @param[in] mnt Pointer to the dfs_mnt structure representing the mount point to be removed.
  129. *
  130. * @return Returns RT_EOK if the mount point is successfully removed.
  131. * Returns -RT_ERROR if the mount point has child mount points and cannot be removed.
  132. */
  133. int dfs_mnt_remove(struct dfs_mnt* mnt)
  134. {
  135. int ret = -RT_ERROR;
  136. if (rt_list_isempty(&mnt->child))
  137. {
  138. rt_list_remove(&mnt->sibling);
  139. if (mnt->parent)
  140. {
  141. /* parent unref parent */
  142. rt_atomic_sub(&(mnt->parent->ref_count), 1);
  143. }
  144. ret = RT_EOK;
  145. }
  146. else
  147. {
  148. LOG_W("remove a mnt point:%s with child.", mnt->fullpath);
  149. }
  150. return ret;
  151. }
  152. /**
  153. * @brief Recursively search for a mount point associated with a specific device ID in the mount tree.
  154. *
  155. * This function traverses the mount tree starting from the given mount point `mnt` to find
  156. * a mount point that is associated with the specified device ID `dev_id`. It uses a depth-first
  157. * search algorithm to iterate through the child mount points.
  158. *
  159. * @param[in] mnt Pointer to the root dfs_mnt structure from which the search will start.
  160. * @param[in] dev_id Pointer to the device ID to search for.
  161. *
  162. * @return If a mount point associated with the given device ID is found, returns a pointer to the corresponding dfs_mnt structure.
  163. * Otherwise, returns RT_NULL.
  164. */
  165. static struct dfs_mnt *_dfs_mnt_dev_lookup(struct dfs_mnt *mnt, rt_device_t dev_id)
  166. {
  167. struct dfs_mnt *ret = RT_NULL, *iter = RT_NULL;
  168. rt_list_for_each_entry(iter, &mnt->child, sibling)
  169. {
  170. if (iter->dev_id == dev_id)
  171. {
  172. ret = iter;
  173. break;
  174. }
  175. else
  176. {
  177. ret = _dfs_mnt_dev_lookup(iter, dev_id);
  178. if (ret)
  179. {
  180. break;
  181. }
  182. }
  183. }
  184. return ret;
  185. }
  186. /**
  187. * @brief Search for a mount point associated with a specific device ID in the mount tree.
  188. *
  189. * This function initiates a search for a mount point that is associated with the specified
  190. * device ID `dev_id` starting from the root mount point. It first checks the root mount point
  191. * directly, and if not found, it recursively searches the entire mount tree using the
  192. * internal helper function `_dfs_mnt_dev_lookup`.
  193. *
  194. * @param[in] dev_id Pointer to the device ID to search for.
  195. *
  196. * @return If a mount point associated with the given device ID is found, returns a pointer to the corresponding dfs_mnt structure.
  197. * Otherwise, returns RT_NULL.
  198. */
  199. struct dfs_mnt *dfs_mnt_dev_lookup(rt_device_t dev_id)
  200. {
  201. struct dfs_mnt *mnt = _root_mnt;
  202. struct dfs_mnt *ret = RT_NULL;
  203. if (mnt)
  204. {
  205. dfs_lock();
  206. if (mnt->dev_id == dev_id)
  207. {
  208. dfs_unlock();
  209. return mnt;
  210. }
  211. ret = _dfs_mnt_dev_lookup(mnt, dev_id);
  212. dfs_unlock();
  213. }
  214. return ret;
  215. }
  216. /**
  217. * @brief Look up the mount point associated with a given full path.
  218. *
  219. * This function searches the mount tree starting from the root mount point to find
  220. * the most specific mount point that matches the given full path. It traverses down
  221. * the mount tree to identify the deepest mount point that is a prefix of the given path.
  222. *
  223. * @param[in] fullpath The full path string for which to find the associated mount point.
  224. *
  225. * @return If a matching mount point is found, returns a pointer to the corresponding dfs_mnt structure.
  226. * Otherwise, returns RT_NULL.
  227. */
  228. struct dfs_mnt *dfs_mnt_lookup(const char *fullpath)
  229. {
  230. struct dfs_mnt *mnt = _root_mnt;
  231. struct dfs_mnt *iter = RT_NULL;
  232. if (mnt)
  233. {
  234. int mnt_len = rt_strlen(mnt->fullpath);
  235. dfs_lock();
  236. if ((strncmp(mnt->fullpath, fullpath, mnt_len) == 0) &&
  237. (mnt_len == 1 || (fullpath[mnt_len] == '\0') || (fullpath[mnt_len] == '/')))
  238. {
  239. while (!rt_list_isempty(&mnt->child))
  240. {
  241. rt_list_for_each_entry(iter, &mnt->child, sibling)
  242. {
  243. mnt_len = rt_strlen(iter->fullpath);
  244. if ((strncmp(iter->fullpath, fullpath, mnt_len) == 0) &&
  245. ((fullpath[mnt_len] == '\0') || (fullpath[mnt_len] == '/')))
  246. {
  247. mnt = iter;
  248. break;
  249. }
  250. }
  251. if (mnt != iter) break;
  252. }
  253. }
  254. else
  255. {
  256. mnt = RT_NULL;
  257. }
  258. dfs_unlock();
  259. if (mnt)
  260. {
  261. LOG_D("mnt_lookup: %s path @ mount point %p", fullpath, mnt);
  262. DLOG(note, "mnt", "found mnt(%s)", mnt->fs_ops->name);
  263. }
  264. }
  265. return mnt;
  266. }
  267. /**
  268. * @brief Increase the reference count of a dfs_mnt structure instance.
  269. *
  270. * This function increments the reference count of the specified dfs_mnt structure.
  271. * The reference count is used to track how many parts of the system are currently
  272. * using this mount point.
  273. *
  274. * @param[in,out] mnt Pointer to the dfs_mnt structure whose reference count is to be increased.
  275. * If the pointer is valid, the reference count within the structure will be modified.
  276. * @return Returns the same pointer to the dfs_mnt structure that was passed in.
  277. * If the input pointer is NULL, it simply returns NULL.
  278. */
  279. struct dfs_mnt* dfs_mnt_ref(struct dfs_mnt* mnt)
  280. {
  281. if (mnt)
  282. {
  283. rt_atomic_add(&(mnt->ref_count), 1);
  284. DLOG(note, "mnt", "mnt(%s),ref_count=%d", mnt->fs_ops->name, rt_atomic_load(&(mnt->ref_count)));
  285. }
  286. return mnt;
  287. }
  288. /**
  289. * @brief Decrease the reference count of a dfs_mnt structure instance and free it if necessary.
  290. *
  291. * This function decrements the reference count of the specified dfs_mnt structure.
  292. * If the reference count reaches zero after the decrement, it will perform the unmount operation,
  293. * trigger the unmount hook, free the allocated path memory, and finally free the dfs_mnt structure itself.
  294. *
  295. * @param[in,out] mnt Pointer to the dfs_mnt structure whose reference count is to be decreased.
  296. * If the reference count reaches zero, the structure will be freed.
  297. *
  298. * @return returns RT_EOK to indicate success.
  299. */
  300. int dfs_mnt_unref(struct dfs_mnt *mnt)
  301. {
  302. rt_err_t ret = RT_EOK;
  303. rt_base_t ref_count;
  304. if (mnt)
  305. {
  306. ref_count = rt_atomic_sub(&(mnt->ref_count), 1) - 1;
  307. if (ref_count == 0)
  308. {
  309. dfs_lock();
  310. if (mnt->flags & MNT_IS_UMOUNT)
  311. {
  312. mnt->fs_ops->umount(mnt);
  313. RT_OBJECT_HOOKLIST_CALL(dfs_mnt_umnt, (mnt));
  314. }
  315. /* free full path */
  316. rt_free(mnt->fullpath);
  317. mnt->fullpath = RT_NULL;
  318. /* destroy self and the ref_count should be 0 */
  319. DLOG(msg, "mnt", "mnt", DLOG_MSG, "free mnt(%s)", mnt->fs_ops->name);
  320. rt_free(mnt);
  321. dfs_unlock();
  322. }
  323. else
  324. {
  325. DLOG(note, "mnt", "mnt(%s),ref_count=%d", mnt->fs_ops->name, rt_atomic_load(&(mnt->ref_count)));
  326. }
  327. }
  328. return ret;
  329. }
  330. /**
  331. * @brief Set specific flags for a dfs_mnt structure instance.
  332. *
  333. * This function sets specific flags for the given dfs_mnt structure.
  334. * If the MS_RDONLY flag is included in the input flags, it sets the MNT_RDONLY flag
  335. * for the mount point and cleans the page cache if the page cache feature is enabled.
  336. *
  337. * @param[in,out] mnt Pointer to the dfs_mnt structure for which flags are to be set.
  338. * The structure's `flags` member will be modified if necessary.
  339. * @param[in] flags The flags to be set for the mount point. This includes the MS_RDONLY flag.
  340. *
  341. * @return returns 0 to indicate success.
  342. */
  343. int dfs_mnt_setflags(struct dfs_mnt *mnt, int flags)
  344. {
  345. int error = 0;
  346. if (flags & MS_RDONLY)
  347. {
  348. mnt->flags |= MNT_RDONLY;
  349. #ifdef RT_USING_PAGECACHE
  350. dfs_pcache_clean(mnt);
  351. #endif
  352. }
  353. return error;
  354. }
  355. /**
  356. * @brief Destroy a dfs_mnt structure instance and unmount it if necessary.
  357. *
  358. * This function attempts to destroy the specified dfs_mnt structure instance.
  359. * If the mount point is currently mounted, it marks the mount point as unmounted,
  360. * sets the unmount flag, and removes it from the mount list if it was added.
  361. * Finally, it decreases the reference count of the mount point and frees the
  362. * structure if the reference count reaches zero.
  363. *
  364. * @param[in,out] mnt Pointer to the dfs_mnt structure to be destroyed.
  365. *
  366. * @return Returns RT_EOK to indicate success.
  367. */
  368. int dfs_mnt_destroy(struct dfs_mnt* mnt)
  369. {
  370. rt_err_t ret = RT_EOK;
  371. if (mnt)
  372. {
  373. if (mnt->flags & MNT_IS_MOUNTED)
  374. {
  375. mnt->flags &= ~MNT_IS_MOUNTED;
  376. mnt->flags |= MNT_IS_UMOUNT;
  377. /* remote it from mnt list */
  378. if (mnt->flags & MNT_IS_ADDLIST)
  379. {
  380. dfs_mnt_remove(mnt);
  381. }
  382. }
  383. dfs_mnt_unref(mnt);
  384. }
  385. return ret;
  386. }
  387. /**
  388. * @brief Recursively traverse the mount point tree and apply a callback function.
  389. *
  390. * This function performs a depth-first traversal of the mount point tree starting from the given mount point.
  391. * It applies the specified callback function to each mount point in the tree. If the callback function returns
  392. * a non-NULL pointer, the traversal stops and the result is returned immediately.
  393. *
  394. * @param[in] mnt Pointer to the root dfs_mnt structure from which the traversal will start.
  395. * If NULL, the function will return RT_NULL without performing any traversal.
  396. * @param[in] func Pointer to the callback function to be applied to each mount point.
  397. * The callback function takes a pointer to a dfs_mnt structure and a generic parameter,
  398. * and returns a pointer to a dfs_mnt structure or RT_NULL.
  399. * @param[in] parameter Generic pointer to a parameter that will be passed to the callback function.
  400. *
  401. * @return If the callback function returns a non-NULL pointer during the traversal, returns that pointer.
  402. * Otherwise, returns RT_NULL.
  403. */
  404. static struct dfs_mnt* _dfs_mnt_foreach(struct dfs_mnt *mnt, struct dfs_mnt* (*func)(struct dfs_mnt *mnt, void *parameter), void *parameter)
  405. {
  406. struct dfs_mnt *iter, *ret = NULL;
  407. if (mnt)
  408. {
  409. ret = func(mnt, parameter);
  410. if (ret == RT_NULL)
  411. {
  412. if (!rt_list_isempty(&mnt->child))
  413. {
  414. /* for each in mount point list */
  415. rt_list_for_each_entry(iter, &mnt->child, sibling)
  416. {
  417. ret = _dfs_mnt_foreach(iter, func, parameter);
  418. if (ret != RT_NULL)
  419. {
  420. break;
  421. }
  422. }
  423. }
  424. }
  425. }
  426. else
  427. {
  428. ret = RT_NULL;
  429. }
  430. return ret;
  431. }
  432. /**
  433. * @brief Compare a mount point's device ID with a given device object.
  434. *
  435. * This function checks if the device ID associated with a specified mount point
  436. * matches the given device object. If a match is found, it returns a pointer to
  437. * the corresponding dfs_mnt structure; otherwise, it returns RT_NULL.
  438. *
  439. * @param[in] mnt Pointer to the dfs_mnt structure representing the mount point to be checked.
  440. * @param[in] device Pointer to the device object to compare against the mount point's device ID.
  441. *
  442. * @return If the device ID of the mount point matches the given device object, returns a pointer to the dfs_mnt structure.
  443. * Otherwise, returns RT_NULL.
  444. */
  445. static struct dfs_mnt* _mnt_cmp_devid(struct dfs_mnt *mnt, void *device)
  446. {
  447. struct dfs_mnt *ret = RT_NULL;
  448. struct rt_device *dev = (struct rt_device*)device;
  449. if (dev && mnt)
  450. {
  451. if (mnt->dev_id == dev)
  452. {
  453. ret = mnt;
  454. }
  455. }
  456. return ret;
  457. }
  458. /**
  459. * this function will return the mounted path for specified device.
  460. *
  461. * @param[in] device the device object which is mounted.
  462. *
  463. * @return the mounted path or NULL if none device mounted.
  464. */
  465. const char *dfs_mnt_get_mounted_path(struct rt_device *device)
  466. {
  467. const char* path = RT_NULL;
  468. if (_root_mnt)
  469. {
  470. struct dfs_mnt* mnt;
  471. dfs_lock();
  472. mnt = _dfs_mnt_foreach(_root_mnt, _mnt_cmp_devid, device);
  473. dfs_unlock();
  474. if (mnt) path = mnt->fullpath;
  475. }
  476. return path;
  477. }
  478. /**
  479. * @brief Print information about a mount point to the console.
  480. *
  481. * This function is designed to be used as a callback in the mount point tree traversal.
  482. * It prints the file system name, device name (or `(NULL)` if no device is associated),
  483. * mount path, and reference count of the specified mount point to the console using `rt_kprintf`.
  484. *
  485. * @param[in] mnt Pointer to the dfs_mnt structure representing the mount point to be printed.
  486. * If NULL, the function does nothing.
  487. * @param[in] parameter A generic pointer to a parameter. This parameter is not used in this function.
  488. *
  489. * @return Always returns RT_NULL as it is a callback function mainly used for side - effects (printing).
  490. */
  491. static struct dfs_mnt* _mnt_dump(struct dfs_mnt *mnt, void *parameter)
  492. {
  493. if (mnt)
  494. {
  495. if (mnt->dev_id)
  496. {
  497. rt_kprintf("%-10s %-6s %-10s %d\n",
  498. mnt->fs_ops->name, mnt->dev_id->parent.name, mnt->fullpath, rt_atomic_load(&(mnt->ref_count)));
  499. }
  500. else
  501. {
  502. rt_kprintf("%-10s (NULL) %-10s %d\n",
  503. mnt->fs_ops->name, mnt->fullpath, rt_atomic_load(&(mnt->ref_count)));
  504. }
  505. }
  506. return RT_NULL;
  507. }
  508. /**
  509. * @brief Compare a mount point's full path with a given path.
  510. *
  511. * This function is designed to be used as a callback in the mount point tree traversal.
  512. * It compares the full path of the specified mount point with the given path.
  513. * If the mount point's full path starts with the given path, it returns a pointer to the dfs_mnt structure;
  514. * otherwise, it returns RT_NULL.
  515. *
  516. * @param[in] mnt Pointer to the dfs_mnt structure representing the mount point to be checked.
  517. * If NULL, the function will not perform the comparison and return RT_NULL.
  518. * @param[in] parameter A generic pointer to a parameter, which should be cast to a `const char*`
  519. * representing the path to compare against the mount point's full path.
  520. *
  521. * @return If the mount point's full path starts with the given path, returns a pointer to the dfs_mnt structure.
  522. * Otherwise, returns RT_NULL.
  523. */
  524. static struct dfs_mnt* _mnt_cmp_path(struct dfs_mnt* mnt, void *parameter)
  525. {
  526. const char* fullpath = (const char*)parameter;
  527. struct dfs_mnt *ret = RT_NULL;
  528. if (strncmp(mnt->fullpath, fullpath, rt_strlen(fullpath)) == 0)
  529. {
  530. ret = mnt;
  531. }
  532. return ret;
  533. }
  534. /**
  535. * @brief Check if a mount point has a child mount point matching the given path.
  536. *
  537. * This function checks whether the specified mount point has a child mount point
  538. * whose full path starts with the given path. It uses a depth-first traversal of
  539. * the mount point tree starting from the provided mount point and applies the
  540. * `_mnt_cmp_path` callback function to each mount point.
  541. *
  542. * @param[in] mnt Pointer to the root dfs_mnt structure from which the search will start.
  543. * If NULL, the function will return RT_FALSE without performing any search.
  544. * @param[in] fullpath The full path string to compare against the child mount points' paths.
  545. * If NULL, the function will return RT_FALSE without performing any search.
  546. *
  547. * @return Returns RT_TRUE if a child mount point with a matching path is found.
  548. * Returns RT_FALSE if no matching child mount point is found, or if either input parameter is NULL.
  549. */
  550. rt_bool_t dfs_mnt_has_child_mnt(struct dfs_mnt *mnt, const char* fullpath)
  551. {
  552. int ret = RT_FALSE;
  553. if (mnt && fullpath)
  554. {
  555. struct dfs_mnt *m = RT_NULL;
  556. dfs_lock();
  557. m = _dfs_mnt_foreach(mnt, _mnt_cmp_path, (void*)fullpath);
  558. dfs_unlock();
  559. if (m)
  560. {
  561. ret = RT_TRUE;
  562. }
  563. }
  564. return ret;
  565. }
  566. /**
  567. * @brief List all mount points starting from a specified mount point.
  568. *
  569. * This function lists information about all mount points in the mount point tree,
  570. * starting from the specified mount point. If the input mount point is NULL,
  571. * it starts from the root mount point. It uses the `_dfs_mnt_foreach` function
  572. * with the `_mnt_dump` callback to print mount point information.
  573. *
  574. * @param[in] mnt Pointer to the dfs_mnt structure from which to start listing mount points.
  575. * If NULL, the function will start from the root mount point.
  576. *
  577. * @return Always returns 0 to indicate success.
  578. */
  579. int dfs_mnt_list(struct dfs_mnt *mnt)
  580. {
  581. if (!mnt) mnt = _root_mnt;
  582. /* lock file system */
  583. dfs_lock();
  584. _dfs_mnt_foreach(mnt, _mnt_dump, RT_NULL);
  585. /* unlock file system */
  586. dfs_unlock();
  587. return 0;
  588. }
  589. /**
  590. * @brief Traverse all mount points in the mount tree and apply a callback function.
  591. *
  592. * @param[in] func Pointer to the callback function to be applied to each mount point.
  593. * The callback function takes a pointer to a `dfs_mnt` structure and a generic parameter,
  594. * and returns a pointer to a `dfs_mnt` structure or `RT_NULL`.
  595. * @param[in] parameter Generic pointer to a parameter that will be passed to the callback function.
  596. *
  597. * @return Always returns 0.
  598. */
  599. int dfs_mnt_foreach(struct dfs_mnt* (*func)(struct dfs_mnt *mnt, void *parameter), void *parameter)
  600. {
  601. /* lock file system */
  602. dfs_lock();
  603. _dfs_mnt_foreach(_root_mnt, func, parameter);
  604. /* unlock file system */
  605. dfs_unlock();
  606. return 0;
  607. }