dfs_dentry.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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. * 2022-10-10 Bernard The first version of rewrite dfs
  9. */
  10. #include <rtthread.h>
  11. #include "dfs.h"
  12. #include "dfs_file.h"
  13. #include "dfs_private.h"
  14. #include "dfs_dentry.h"
  15. #include "dfs_mnt.h"
  16. #define DBG_TAG "DFS.dentry"
  17. #define DBG_LVL DBG_WARNING
  18. #include <rtdbg.h>
  19. #define DFS_DENTRY_HASH_NR 32
  20. struct dentry_hash_head
  21. {
  22. rt_list_t head[DFS_DENTRY_HASH_NR];
  23. };
  24. static struct dentry_hash_head hash_head;
  25. static uint32_t _dentry_hash(struct dfs_mnt *mnt, const char *path)
  26. {
  27. uint32_t val = 0;
  28. if (path)
  29. {
  30. while (*path)
  31. {
  32. val = ((val << 5) + val) + *path++;
  33. }
  34. }
  35. return (val ^ (unsigned long) mnt) & (DFS_DENTRY_HASH_NR - 1);
  36. }
  37. static struct dfs_dentry *_dentry_create(struct dfs_mnt *mnt, char *path, rt_bool_t is_rela_path)
  38. {
  39. struct dfs_dentry *dentry = RT_NULL;
  40. if (mnt == RT_NULL || path == RT_NULL)
  41. {
  42. return dentry;
  43. }
  44. dentry = (struct dfs_dentry *)rt_calloc(1, sizeof(struct dfs_dentry));
  45. if (dentry)
  46. {
  47. char *dentry_path = path;
  48. if (!is_rela_path)
  49. {
  50. int mntpoint_len = strlen(mnt->fullpath);
  51. if (rt_strncmp(mnt->fullpath, dentry_path, mntpoint_len) == 0)
  52. {
  53. dentry_path += mntpoint_len;
  54. }
  55. }
  56. dentry->pathname = strlen(dentry_path) ? rt_strdup(dentry_path) : rt_strdup(path);
  57. dentry->mnt = dfs_mnt_ref(mnt);
  58. rt_atomic_store(&(dentry->ref_count), 1);
  59. dentry->flags |= DENTRY_IS_ALLOCED;
  60. LOG_I("create a dentry:%p for %s", dentry, fullpath);
  61. }
  62. return dentry;
  63. }
  64. struct dfs_dentry *dfs_dentry_create(struct dfs_mnt *mnt, char *fullpath)
  65. {
  66. return _dentry_create(mnt, fullpath, RT_FALSE);
  67. }
  68. struct dfs_dentry *dfs_dentry_create_rela(struct dfs_mnt *mnt, char *rela_path)
  69. {
  70. return _dentry_create(mnt, rela_path, RT_TRUE);;
  71. }
  72. struct dfs_dentry * dfs_dentry_ref(struct dfs_dentry *dentry)
  73. {
  74. if (dentry)
  75. {
  76. int ret = dfs_file_lock();
  77. if (ret == RT_EOK)
  78. {
  79. rt_atomic_add(&(dentry->ref_count), 1);
  80. if (dentry->vnode)
  81. {
  82. rt_atomic_add(&(dentry->vnode->ref_count), 1);
  83. }
  84. dfs_file_unlock();
  85. }
  86. }
  87. return dentry;
  88. }
  89. struct dfs_dentry *dfs_dentry_unref(struct dfs_dentry *dentry)
  90. {
  91. rt_err_t ret = RT_EOK;
  92. if (dentry)
  93. {
  94. ret = dfs_file_lock();
  95. if (ret == RT_EOK)
  96. {
  97. if (dentry->flags & DENTRY_IS_ALLOCED)
  98. {
  99. rt_atomic_sub(&(dentry->ref_count), 1);
  100. }
  101. if (rt_atomic_load(&(dentry->ref_count)) == 0)
  102. {
  103. DLOG(msg, "dentry", "dentry", DLOG_MSG, "free dentry, ref_count=0");
  104. if (dentry->flags & DENTRY_IS_ADDHASH)
  105. {
  106. rt_list_remove(&dentry->hashlist);
  107. }
  108. /* release vnode */
  109. if (dentry->vnode)
  110. {
  111. dfs_vnode_unref(dentry->vnode);
  112. }
  113. /* release mnt */
  114. DLOG(msg, "dentry", "mnt", DLOG_MSG, "dfs_mnt_unref(dentry->mnt)");
  115. if (dentry->mnt)
  116. {
  117. dfs_mnt_unref(dentry->mnt);
  118. }
  119. dfs_file_unlock();
  120. LOG_I("free a dentry: %p", dentry);
  121. rt_free(dentry->pathname);
  122. rt_free(dentry);
  123. dentry = RT_NULL;
  124. }
  125. else
  126. {
  127. if (dentry->vnode)
  128. {
  129. rt_atomic_sub(&(dentry->vnode->ref_count), 1);
  130. }
  131. dfs_file_unlock();
  132. DLOG(note, "dentry", "dentry ref_count=%d", rt_atomic_load(&(dentry->ref_count)));
  133. }
  134. }
  135. }
  136. return dentry;
  137. }
  138. static struct dfs_dentry *_dentry_hash_lookup(struct dfs_mnt *mnt, const char *path)
  139. {
  140. rt_err_t ret = RT_EOK;
  141. struct dfs_dentry *entry = RT_NULL;
  142. ret = dfs_file_lock();
  143. if (ret == RT_EOK)
  144. {
  145. rt_list_for_each_entry(entry, &hash_head.head[_dentry_hash(mnt, path)], hashlist)
  146. {
  147. if (entry->mnt == mnt && !strcmp(entry->pathname, path))
  148. {
  149. dfs_dentry_ref(entry);
  150. dfs_file_unlock();
  151. return entry;
  152. }
  153. }
  154. dfs_file_unlock();
  155. }
  156. return RT_NULL;
  157. }
  158. void dfs_dentry_insert(struct dfs_dentry *dentry)
  159. {
  160. dfs_file_lock();
  161. rt_list_insert_after(&hash_head.head[_dentry_hash(dentry->mnt, dentry->pathname)], &dentry->hashlist);
  162. dentry->flags |= DENTRY_IS_ADDHASH;
  163. dfs_file_unlock();
  164. }
  165. /*
  166. * lookup a dentry, return this dentry and increase refcount if exist, otherwise return NULL
  167. */
  168. struct dfs_dentry *dfs_dentry_lookup(struct dfs_mnt *mnt, const char *path, uint32_t flags)
  169. {
  170. struct dfs_dentry *dentry;
  171. struct dfs_vnode *vnode = RT_NULL;
  172. int mntpoint_len = strlen(mnt->fullpath);
  173. if (rt_strncmp(mnt->fullpath, path, mntpoint_len) == 0)
  174. {
  175. path += mntpoint_len;
  176. if ((*path) == '\0')
  177. {
  178. /* root */
  179. path = "/";
  180. }
  181. }
  182. dfs_file_lock();
  183. dentry = _dentry_hash_lookup(mnt, path);
  184. if (!dentry)
  185. {
  186. if (mnt->fs_ops->lookup)
  187. {
  188. DLOG(activate, "dentry");
  189. /* not in hash table, create it */
  190. DLOG(msg, "dentry", "dentry", DLOG_MSG, "dfs_dentry_create_rela(mnt=%s, path=%s)", mnt->fullpath, path);
  191. dentry = dfs_dentry_create_rela(mnt, (char*)path);
  192. if (dentry)
  193. {
  194. DLOG(msg, "dentry", mnt->fs_ops->name, DLOG_MSG, "vnode=fs_ops->lookup(dentry)");
  195. if (dfs_is_mounted(mnt) == 0)
  196. {
  197. vnode = mnt->fs_ops->lookup(dentry);
  198. }
  199. if (vnode)
  200. {
  201. DLOG(msg, mnt->fs_ops->name, "dentry", DLOG_MSG_RET, "return vnode");
  202. dentry->vnode = vnode; /* the refcount of created vnode is 1. no need to reference */
  203. dfs_file_lock();
  204. rt_list_insert_after(&hash_head.head[_dentry_hash(mnt, path)], &dentry->hashlist);
  205. dentry->flags |= DENTRY_IS_ADDHASH;
  206. dfs_file_unlock();
  207. if (dentry->flags & (DENTRY_IS_ALLOCED | DENTRY_IS_ADDHASH)
  208. && !(dentry->flags & DENTRY_IS_OPENED))
  209. {
  210. rt_err_t ret = dfs_file_lock();
  211. if (ret == RT_EOK)
  212. {
  213. dentry->flags |= DENTRY_IS_OPENED;
  214. dfs_file_unlock();
  215. }
  216. }
  217. }
  218. else
  219. {
  220. DLOG(msg, mnt->fs_ops->name, "dentry", DLOG_MSG_RET, "no dentry");
  221. DLOG(msg, "dentry", "dentry", DLOG_MSG, "dfs_dentry_unref(dentry)");
  222. dfs_dentry_unref(dentry);
  223. dentry = RT_NULL;
  224. }
  225. }
  226. DLOG(deactivate, "dentry");
  227. }
  228. }
  229. else
  230. {
  231. DLOG(note, "dentry", "found dentry");
  232. }
  233. dfs_file_unlock();
  234. return dentry;
  235. }
  236. char* dfs_dentry_full_path(struct dfs_dentry* dentry)
  237. {
  238. char *path = NULL;
  239. if (dentry && dentry->mnt)
  240. {
  241. int mnt_len = strlen(dentry->mnt->fullpath);
  242. int path_len = strlen(dentry->pathname);
  243. path = (char *) rt_malloc(mnt_len + path_len + 3);
  244. if (path)
  245. {
  246. if (dentry->pathname[0] == '/' || dentry->mnt->fullpath[mnt_len - 1] == '/')
  247. {
  248. rt_snprintf(path, mnt_len + path_len + 2, "%s%s", dentry->mnt->fullpath,
  249. dentry->pathname);
  250. }
  251. else
  252. {
  253. rt_snprintf(path, mnt_len + path_len + 2, "%s/%s", dentry->mnt->fullpath,
  254. dentry->pathname);
  255. }
  256. }
  257. }
  258. return path;
  259. }
  260. char* dfs_dentry_pathname(struct dfs_dentry* dentry)
  261. {
  262. char *pathname = RT_NULL;
  263. char *index = RT_NULL;
  264. index = strrchr(dentry->pathname, '/');
  265. if (index)
  266. {
  267. int length = index - dentry->pathname;
  268. int path_length = strlen(dentry->mnt->fullpath) + length + 3;
  269. pathname = (char*) rt_malloc(path_length);
  270. if (pathname)
  271. {
  272. if (dentry->pathname[0] == '/')
  273. {
  274. rt_snprintf(pathname, path_length - 1, "%s%.*s", dentry->mnt->fullpath,
  275. length, dentry->pathname);
  276. }
  277. else
  278. {
  279. rt_snprintf(pathname, path_length - 1, "%s/%.*s", dentry->mnt->fullpath,
  280. length, dentry->pathname);
  281. }
  282. }
  283. }
  284. else
  285. {
  286. pathname = rt_strdup(dentry->mnt->fullpath);
  287. }
  288. return pathname;
  289. }
  290. uint32_t dfs_dentry_full_path_crc32(struct dfs_dentry* dentry)
  291. {
  292. uint32_t crc32 = 0xFFFFFFFF;
  293. char *fullpath = dfs_dentry_full_path(dentry);
  294. if (fullpath)
  295. {
  296. int i = 0;
  297. while(fullpath[i] != '\0')
  298. {
  299. for (uint8_t b = 1; b; b <<= 1)
  300. {
  301. crc32 ^= (fullpath[i] & b) ? 1 : 0;
  302. crc32 = (crc32 & 1) ? crc32 >> 1 ^ 0xEDB88320 : crc32 >> 1;
  303. }
  304. i ++;
  305. }
  306. rt_free(fullpath);
  307. }
  308. return crc32;
  309. }
  310. int dfs_dentry_init(void)
  311. {
  312. int i = 0;
  313. for(i = 0; i < DFS_DENTRY_HASH_NR; i++)
  314. {
  315. rt_list_init(&hash_head.head[i]);
  316. }
  317. return 0;
  318. }
  319. int dfs_dentry_dump(int argc, char** argv)
  320. {
  321. int index = 0;
  322. struct dfs_dentry *entry = RT_NULL;
  323. dfs_lock();
  324. for (index = 0; index < DFS_DENTRY_HASH_NR; index ++)
  325. {
  326. rt_list_for_each_entry(entry, &hash_head.head[index], hashlist)
  327. {
  328. printf("dentry: %s%s @ %p, ref_count = %zd\n", entry->mnt->fullpath, entry->pathname, entry, (size_t)rt_atomic_load(&entry->ref_count));
  329. }
  330. }
  331. dfs_unlock();
  332. return 0;
  333. }
  334. MSH_CMD_EXPORT_ALIAS(dfs_dentry_dump, dentry_dump, dump dentry in the system);