dfs_fs.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  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. #include <dfs_fs.h>
  16. #include <dfs_file.h>
  17. #include <dfs_dentry.h>
  18. #include <dfs_mnt.h>
  19. #include "dfs_private.h"
  20. #ifdef RT_USING_PAGECACHE
  21. #include "dfs_pcache.h"
  22. #endif
  23. #define DBG_TAG "DFS.fs"
  24. #define DBG_LVL DBG_INFO
  25. #include <rtdbg.h>
  26. static struct dfs_filesystem_type *file_systems = NULL;
  27. extern rt_list_t _mnt_list;
  28. /**
  29. * @addtogroup FsApi
  30. */
  31. /*@{*/
  32. static struct dfs_filesystem_type **_find_filesystem(const char *name)
  33. {
  34. struct dfs_filesystem_type **type;
  35. for (type = &file_systems; *type; type = &(*type)->next)
  36. {
  37. if (strcmp((*type)->fs_ops->name, name) == 0)
  38. break;
  39. }
  40. return type;
  41. }
  42. struct dfs_filesystem_type *dfs_filesystems(void)
  43. {
  44. return file_systems;
  45. }
  46. int dfs_register(struct dfs_filesystem_type *fs)
  47. {
  48. int ret = 0;
  49. struct dfs_filesystem_type **type = _find_filesystem(fs->fs_ops->name);
  50. LOG_D("register %s file system.", fs->fs_ops->name);
  51. if (*type)
  52. {
  53. ret = -EBUSY;
  54. }
  55. else
  56. {
  57. *type = fs;
  58. }
  59. return ret;
  60. }
  61. int dfs_unregister(struct dfs_filesystem_type *fs)
  62. {
  63. int ret = 0;
  64. struct dfs_filesystem_type **type;
  65. if (fs)
  66. {
  67. LOG_D("unregister %s file system.", fs->fs_ops->name);
  68. for (type = &file_systems; *type; type = &(*type)->next)
  69. {
  70. if (strcmp((*type)->fs_ops->name, fs->fs_ops->name) == 0)
  71. {
  72. *type = (*type)->next;
  73. break;
  74. }
  75. }
  76. if (!*type) ret = -EINVAL;
  77. }
  78. return ret;
  79. }
  80. /*
  81. * parent(mount path)
  82. * mnt_parent <- - - - - - - +
  83. * | |
  84. * |- mnt_child <- - - - - -+ (1 refcount)
  85. * | |
  86. * |- parent - - + (1 refcount)
  87. */
  88. int dfs_mount(const char *device_name,
  89. const char *path,
  90. const char *filesystemtype,
  91. unsigned long rwflag,
  92. const void *data)
  93. {
  94. int ret = RT_EOK;
  95. char *fullpath = RT_NULL;
  96. rt_device_t dev_id = RT_NULL;
  97. struct dfs_mnt *mnt_parent = RT_NULL, *mnt_child = RT_NULL;
  98. struct dfs_dentry *mntpoint_dentry = RT_NULL;
  99. struct dfs_filesystem_type *type = *_find_filesystem(filesystemtype);
  100. if (type)
  101. {
  102. fullpath = dfs_normalize_path(RT_NULL, path);
  103. if (!fullpath)
  104. {
  105. rt_set_errno(EPERM);
  106. ret = -1;
  107. }
  108. }
  109. else
  110. {
  111. rt_set_errno(ENOENT);
  112. ret = -1;
  113. }
  114. if (fullpath)
  115. {
  116. DLOG(note, "mnt", "mount %s(%s) on path: %s", device_name, filesystemtype, fullpath);
  117. /* open specific device */
  118. if (device_name) dev_id = rt_device_find(device_name);
  119. if (!(type->fs_ops->flags & FS_NEED_DEVICE) ||
  120. ((type->fs_ops->flags & FS_NEED_DEVICE) && dev_id))
  121. {
  122. DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt_parent = dfs_mnt_lookup(%s)", fullpath);
  123. mnt_parent = dfs_mnt_lookup(fullpath);
  124. if ((!mnt_parent && (strcmp(fullpath, "/") == 0 || strcmp(fullpath, "/dev") == 0))
  125. || (mnt_parent && strcmp(fullpath, "/") == 0 && strcmp(mnt_parent->fullpath, fullpath) != 0))
  126. {
  127. LOG_D("no mnt found @ mount point %s, should be root.", fullpath);
  128. DLOG(msg, "mnt", "dfs", DLOG_MSG_RET, "no mnt");
  129. /* it's the root file system */
  130. /* the mount point dentry is the same as root dentry. */
  131. DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt_parent = dfs_mnt_create(path)");
  132. mnt_parent = dfs_mnt_create(fullpath); /* mnt->ref_count should be 1. */
  133. if (mnt_parent)
  134. {
  135. DLOG(msg, "mnt", "dfs", DLOG_MSG_RET, "return mnt, ref_count=1");
  136. mnt_parent->fs_ops = type->fs_ops;
  137. mnt_parent->dev_id = dev_id;
  138. if (mnt_parent->fs_ops->mount)
  139. {
  140. DLOG(msg, "dfs", type->fs_ops->name, DLOG_MSG, "fs_ops->mount(mnt_parent, rwflag, data)");
  141. ret = mnt_parent->fs_ops->mount(mnt_parent, rwflag, data);
  142. if (ret == RT_EOK)
  143. {
  144. DLOG(msg, type->fs_ops->name, "dfs", DLOG_MSG_RET, "mount OK, ret root_dentry");
  145. mnt_child = mnt_parent;
  146. mnt_child->flags |= MNT_IS_MOUNTED;
  147. DLOG(note_right, "mnt", "mount sucessfully");
  148. DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_insert(, mnt_child)");
  149. dfs_mnt_insert(RT_NULL, mnt_child);
  150. /* unref it, because the ref_count = 1 when create */
  151. DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_unref(mnt_parent)");
  152. dfs_mnt_unref(mnt_parent);
  153. /*
  154. * About root mnt:
  155. * There are two ref_count:
  156. * 1. the gobal root reference.
  157. * 1. the mnt->parent reference.
  158. */
  159. }
  160. else
  161. {
  162. LOG_W("mount %s failed with file system type: %s", fullpath, type->fs_ops->name);
  163. DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_destroy(mnt_parent)");
  164. dfs_mnt_destroy(mnt_parent);
  165. mnt_parent = RT_NULL;
  166. rt_set_errno(EPERM);
  167. ret = -1;
  168. }
  169. }
  170. else
  171. {
  172. LOG_W("no mount method on file system type: %s", type->fs_ops->name);
  173. DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_destroy(mnt_parent), no mount method");
  174. dfs_mnt_destroy(mnt_parent);
  175. mnt_parent = RT_NULL;
  176. rt_set_errno(EIO);
  177. ret = -1;
  178. }
  179. }
  180. else
  181. {
  182. LOG_E("create a mnt point failed.");
  183. rt_set_errno(ENOMEM);
  184. ret = -1;
  185. }
  186. }
  187. else if (mnt_parent && (strcmp(mnt_parent->fullpath, fullpath) != 0))
  188. {
  189. DLOG(msg, "dfs", "dentry", DLOG_MSG, "mntpoint_dentry = dfs_dentry_lookup(mnt_parent, %s, 0)", fullpath);
  190. mntpoint_dentry = dfs_dentry_lookup(mnt_parent, fullpath, 0);
  191. if (mntpoint_dentry)
  192. {
  193. DLOG(msg, "dentry", "dfs", DLOG_MSG_RET, "dentry exist");
  194. DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt_child = dfs_mnt_create(path)");
  195. mnt_child = dfs_mnt_create(fullpath);
  196. if (mnt_child)
  197. {
  198. LOG_D("create mnt point %p", mnt_child);
  199. mnt_child->fs_ops = type->fs_ops;
  200. mnt_child->dev_id = dev_id;
  201. if (mnt_child->fs_ops->mount)
  202. {
  203. DLOG(msg, "dfs", type->fs_ops->name, DLOG_MSG, "root_dentry = fs_ops->mount(mnt_child, rwflag, data)");
  204. ret = mnt_child->fs_ops->mount(mnt_child, rwflag, data);
  205. if (ret == RT_EOK)
  206. {
  207. mnt_child->flags |= MNT_IS_MOUNTED;
  208. LOG_D("mount %s sucessfully", fullpath);
  209. DLOG(msg, mnt_child->fs_ops->name, "dfs", DLOG_MSG_RET, "mount OK");
  210. DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_insert(mnt_parent, mnt_child)");
  211. dfs_mnt_insert(mnt_parent, mnt_child);
  212. /* unref it, because the ref_count = 1 when create */
  213. DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_unref(mnt_child)");
  214. dfs_mnt_unref(mnt_child);
  215. }
  216. else
  217. {
  218. LOG_W("mount %s failed with file system type: %s", fullpath, type->fs_ops->name);
  219. DLOG(msg, mnt_child->fs_ops->name, "dfs", DLOG_MSG_RET, "mount failed");
  220. dfs_mnt_destroy(mnt_child);
  221. rt_set_errno(EPERM);
  222. ret = -1;
  223. }
  224. }
  225. else
  226. {
  227. LOG_W("no mount method on file system type: %s", type->fs_ops->name);
  228. dfs_mnt_destroy(mnt_child);
  229. rt_set_errno(EIO);
  230. ret = -1;
  231. }
  232. }
  233. else
  234. {
  235. LOG_E("create a mnt point failed.");
  236. rt_set_errno(ENOMEM);
  237. ret = -1;
  238. }
  239. dfs_dentry_unref(mntpoint_dentry);
  240. }
  241. else
  242. {
  243. LOG_W("no mount point (%s) in file system: %s", fullpath, mnt_parent->fullpath);
  244. rt_set_errno(ENOTDIR);
  245. ret = -1;
  246. }
  247. }
  248. else
  249. {
  250. LOG_E("mount point (%s) already mounted!", fullpath);
  251. rt_set_errno(EEXIST);
  252. ret = -1;
  253. }
  254. }
  255. else
  256. {
  257. LOG_E("No device found for this file system.");
  258. rt_set_errno(ENODEV);
  259. ret = -1;
  260. }
  261. rt_free(fullpath);
  262. }
  263. return ret;
  264. }
  265. int dfs_umount(const char *specialfile, int flags)
  266. {
  267. int ret = -RT_ERROR;
  268. char *fullpath = RT_NULL;
  269. struct dfs_mnt *mnt = RT_NULL;
  270. fullpath = dfs_normalize_path(NULL, specialfile);
  271. if (fullpath)
  272. {
  273. DLOG(msg, "dfs", "mnt", DLOG_MSG, "mnt = dfs_mnt_lookup(%s)", fullpath);
  274. mnt = dfs_mnt_lookup(fullpath);
  275. if (mnt)
  276. {
  277. if (strcmp(mnt->fullpath, fullpath) == 0)
  278. {
  279. /* is the mount point */
  280. rt_atomic_t ref_count = rt_atomic_load(&(mnt->ref_count));
  281. if (!(mnt->flags & MNT_IS_LOCKED) && rt_list_isempty(&mnt->child) && (ref_count == 1 || (flags & MNT_FORCE)))
  282. {
  283. #ifdef RT_USING_PAGECACHE
  284. dfs_pcache_unmount(mnt);
  285. #endif
  286. /* destroy this mount point */
  287. DLOG(msg, "dfs", "mnt", DLOG_MSG, "dfs_mnt_destroy(mnt)");
  288. ret = dfs_mnt_destroy(mnt);
  289. }
  290. else
  291. {
  292. LOG_E("the file system is busy!");
  293. }
  294. }
  295. else
  296. {
  297. LOG_E("the path:%s is not a mountpoint!", fullpath);
  298. }
  299. }
  300. else
  301. {
  302. LOG_E("no filesystem found.");
  303. }
  304. rt_free(fullpath);
  305. }
  306. else
  307. {
  308. rt_set_errno(-ENOTDIR);
  309. }
  310. return ret;
  311. }
  312. /* for compatibility */
  313. int dfs_unmount(const char *specialfile)
  314. {
  315. return dfs_umount(specialfile, 0);
  316. }
  317. int dfs_is_mounted(struct dfs_mnt *mnt)
  318. {
  319. int ret = 0;
  320. if (mnt && !(mnt->flags & MNT_IS_MOUNTED))
  321. {
  322. ret = -1;
  323. }
  324. return ret;
  325. }
  326. int dfs_mkfs(const char *fs_name, const char *device_name)
  327. {
  328. rt_device_t dev_id = NULL;
  329. struct dfs_filesystem_type *type;
  330. int ret = -RT_ERROR;
  331. type = *_find_filesystem(fs_name);
  332. if (!type)
  333. {
  334. rt_kprintf("no file system: %s found!\n", fs_name);
  335. return ret;
  336. }
  337. else
  338. {
  339. if (type->fs_ops->flags & FS_NEED_DEVICE)
  340. {
  341. /* check device name, and it should not be NULL */
  342. if (device_name != NULL)
  343. dev_id = rt_device_find(device_name);
  344. if (dev_id == NULL)
  345. {
  346. rt_set_errno(-ENODEV);
  347. rt_kprintf("Device (%s) was not found", device_name);
  348. return ret;
  349. }
  350. }
  351. else
  352. {
  353. dev_id = RT_NULL;
  354. }
  355. }
  356. if (type->fs_ops->mkfs)
  357. {
  358. ret = type->fs_ops->mkfs(dev_id, type->fs_ops->name);
  359. #ifdef RT_USING_PAGECACHE
  360. if (ret == RT_EOK)
  361. {
  362. struct dfs_mnt *mnt = RT_NULL;
  363. mnt = dfs_mnt_dev_lookup(dev_id);
  364. if (mnt)
  365. {
  366. dfs_pcache_unmount(mnt);
  367. }
  368. }
  369. #endif
  370. }
  371. return ret;
  372. }
  373. int dfs_statfs(const char *path, struct statfs *buffer)
  374. {
  375. struct dfs_mnt *mnt;
  376. char *fullpath;
  377. int ret = -RT_ERROR;
  378. fullpath = dfs_normalize_path(NULL, path);
  379. if (!fullpath)
  380. {
  381. return ret;
  382. }
  383. DLOG(msg, "dfs_file", "mnt", DLOG_MSG, "dfs_mnt_lookup(%s)", fullpath);
  384. mnt = dfs_mnt_lookup(fullpath);
  385. if (mnt)
  386. {
  387. if (mnt->fs_ops->statfs)
  388. {
  389. if (dfs_is_mounted(mnt) == 0)
  390. {
  391. ret = mnt->fs_ops->statfs(mnt, buffer);
  392. }
  393. }
  394. }
  395. return ret;
  396. }
  397. /**
  398. * this function will return the mounted path for specified device.
  399. *
  400. * @param device the device object which is mounted.
  401. *
  402. * @return the mounted path or NULL if none device mounted.
  403. */
  404. const char *dfs_filesystem_get_mounted_path(struct rt_device *device)
  405. {
  406. const char *path = NULL;
  407. return path;
  408. }
  409. /**
  410. * this function will fetch the partition table on specified buffer.
  411. *
  412. * @param part the returned partition structure.
  413. * @param buf the buffer contains partition table.
  414. * @param pindex the index of partition table to fetch.
  415. *
  416. * @return RT_EOK on successful or -RT_ERROR on failed.
  417. */
  418. int dfs_filesystem_get_partition(struct dfs_partition *part,
  419. uint8_t *buf,
  420. uint32_t pindex)
  421. {
  422. #define DPT_ADDRESS 0x1be /* device partition offset in Boot Sector */
  423. #define DPT_ITEM_SIZE 16 /* partition item size */
  424. uint8_t *dpt;
  425. uint8_t type;
  426. RT_ASSERT(part != NULL);
  427. RT_ASSERT(buf != NULL);
  428. dpt = buf + DPT_ADDRESS + pindex * DPT_ITEM_SIZE;
  429. /* check if it is a valid partition table */
  430. if ((*dpt != 0x80) && (*dpt != 0x00))
  431. return -EIO;
  432. /* get partition type */
  433. type = *(dpt + 4);
  434. if (type == 0)
  435. return -EIO;
  436. /* set partition information
  437. * size is the number of 512-Byte */
  438. part->type = type;
  439. part->offset = *(dpt + 8) | *(dpt + 9) << 8 | *(dpt + 10) << 16 | *(dpt + 11) << 24;
  440. part->size = *(dpt + 12) | *(dpt + 13) << 8 | *(dpt + 14) << 16 | *(dpt + 15) << 24;
  441. rt_kprintf("found part[%d], begin: %ld, size: ",
  442. pindex, part->offset * 512);
  443. if ((part->size >> 11) == 0)
  444. rt_kprintf("%ld%s", part->size >> 1, "KB\n"); /* KB */
  445. else
  446. {
  447. unsigned int part_size;
  448. part_size = part->size >> 11; /* MB */
  449. if ((part_size >> 10) == 0)
  450. rt_kprintf("%d.%ld%s", part_size, (part->size >> 1) & 0x3FF, "MB\n");
  451. else
  452. rt_kprintf("%d.%d%s", part_size >> 10, part_size & 0x3FF, "GB\n");
  453. }
  454. return RT_EOK;
  455. }
  456. /* @} */