direct.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. /*
  2. * direct.c - NILFS direct block pointer.
  3. *
  4. * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  19. *
  20. * Written by Koji Sato <koji@osrg.net>.
  21. */
  22. #include <linux/errno.h>
  23. #include "nilfs.h"
  24. #include "page.h"
  25. #include "direct.h"
  26. #include "alloc.h"
  27. static inline __le64 *nilfs_direct_dptrs(const struct nilfs_direct *direct)
  28. {
  29. return (__le64 *)
  30. ((struct nilfs_direct_node *)direct->d_bmap.b_u.u_data + 1);
  31. }
  32. static inline __u64
  33. nilfs_direct_get_ptr(const struct nilfs_direct *direct, __u64 key)
  34. {
  35. return nilfs_bmap_dptr_to_ptr(*(nilfs_direct_dptrs(direct) + key));
  36. }
  37. static inline void nilfs_direct_set_ptr(struct nilfs_direct *direct,
  38. __u64 key, __u64 ptr)
  39. {
  40. *(nilfs_direct_dptrs(direct) + key) = nilfs_bmap_ptr_to_dptr(ptr);
  41. }
  42. static int nilfs_direct_lookup(const struct nilfs_bmap *bmap,
  43. __u64 key, int level, __u64 *ptrp)
  44. {
  45. struct nilfs_direct *direct;
  46. __u64 ptr;
  47. direct = (struct nilfs_direct *)bmap;
  48. if ((key > NILFS_DIRECT_KEY_MAX) ||
  49. (level != 1) || /* XXX: use macro for level 1 */
  50. ((ptr = nilfs_direct_get_ptr(direct, key)) ==
  51. NILFS_BMAP_INVALID_PTR))
  52. return -ENOENT;
  53. if (ptrp != NULL)
  54. *ptrp = ptr;
  55. return 0;
  56. }
  57. static __u64
  58. nilfs_direct_find_target_v(const struct nilfs_direct *direct, __u64 key)
  59. {
  60. __u64 ptr;
  61. ptr = nilfs_bmap_find_target_seq(&direct->d_bmap, key);
  62. if (ptr != NILFS_BMAP_INVALID_PTR)
  63. /* sequential access */
  64. return ptr;
  65. else
  66. /* block group */
  67. return nilfs_bmap_find_target_in_group(&direct->d_bmap);
  68. }
  69. static void nilfs_direct_set_target_v(struct nilfs_direct *direct,
  70. __u64 key, __u64 ptr)
  71. {
  72. direct->d_bmap.b_last_allocated_key = key;
  73. direct->d_bmap.b_last_allocated_ptr = ptr;
  74. }
  75. static int nilfs_direct_prepare_insert(struct nilfs_direct *direct,
  76. __u64 key,
  77. union nilfs_bmap_ptr_req *req,
  78. struct nilfs_bmap_stats *stats)
  79. {
  80. int ret;
  81. if (direct->d_ops->dop_find_target != NULL)
  82. req->bpr_ptr = direct->d_ops->dop_find_target(direct, key);
  83. ret = direct->d_bmap.b_pops->bpop_prepare_alloc_ptr(&direct->d_bmap,
  84. req);
  85. if (ret < 0)
  86. return ret;
  87. stats->bs_nblocks = 1;
  88. return 0;
  89. }
  90. static void nilfs_direct_commit_insert(struct nilfs_direct *direct,
  91. union nilfs_bmap_ptr_req *req,
  92. __u64 key, __u64 ptr)
  93. {
  94. struct buffer_head *bh;
  95. /* ptr must be a pointer to a buffer head. */
  96. bh = (struct buffer_head *)((unsigned long)ptr);
  97. set_buffer_nilfs_volatile(bh);
  98. if (direct->d_bmap.b_pops->bpop_commit_alloc_ptr != NULL)
  99. direct->d_bmap.b_pops->bpop_commit_alloc_ptr(
  100. &direct->d_bmap, req);
  101. nilfs_direct_set_ptr(direct, key, req->bpr_ptr);
  102. if (!nilfs_bmap_dirty(&direct->d_bmap))
  103. nilfs_bmap_set_dirty(&direct->d_bmap);
  104. if (direct->d_ops->dop_set_target != NULL)
  105. direct->d_ops->dop_set_target(direct, key, req->bpr_ptr);
  106. }
  107. static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
  108. {
  109. struct nilfs_direct *direct;
  110. union nilfs_bmap_ptr_req req;
  111. struct nilfs_bmap_stats stats;
  112. int ret;
  113. direct = (struct nilfs_direct *)bmap;
  114. if (key > NILFS_DIRECT_KEY_MAX)
  115. return -ENOENT;
  116. if (nilfs_direct_get_ptr(direct, key) != NILFS_BMAP_INVALID_PTR)
  117. return -EEXIST;
  118. ret = nilfs_direct_prepare_insert(direct, key, &req, &stats);
  119. if (ret < 0)
  120. return ret;
  121. nilfs_direct_commit_insert(direct, &req, key, ptr);
  122. nilfs_bmap_add_blocks(bmap, stats.bs_nblocks);
  123. return 0;
  124. }
  125. static int nilfs_direct_prepare_delete(struct nilfs_direct *direct,
  126. union nilfs_bmap_ptr_req *req,
  127. __u64 key,
  128. struct nilfs_bmap_stats *stats)
  129. {
  130. int ret;
  131. if (direct->d_bmap.b_pops->bpop_prepare_end_ptr != NULL) {
  132. req->bpr_ptr = nilfs_direct_get_ptr(direct, key);
  133. ret = direct->d_bmap.b_pops->bpop_prepare_end_ptr(
  134. &direct->d_bmap, req);
  135. if (ret < 0)
  136. return ret;
  137. }
  138. stats->bs_nblocks = 1;
  139. return 0;
  140. }
  141. static void nilfs_direct_commit_delete(struct nilfs_direct *direct,
  142. union nilfs_bmap_ptr_req *req,
  143. __u64 key)
  144. {
  145. if (direct->d_bmap.b_pops->bpop_commit_end_ptr != NULL)
  146. direct->d_bmap.b_pops->bpop_commit_end_ptr(
  147. &direct->d_bmap, req);
  148. nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR);
  149. }
  150. static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key)
  151. {
  152. struct nilfs_direct *direct;
  153. union nilfs_bmap_ptr_req req;
  154. struct nilfs_bmap_stats stats;
  155. int ret;
  156. direct = (struct nilfs_direct *)bmap;
  157. if ((key > NILFS_DIRECT_KEY_MAX) ||
  158. nilfs_direct_get_ptr(direct, key) == NILFS_BMAP_INVALID_PTR)
  159. return -ENOENT;
  160. ret = nilfs_direct_prepare_delete(direct, &req, key, &stats);
  161. if (ret < 0)
  162. return ret;
  163. nilfs_direct_commit_delete(direct, &req, key);
  164. nilfs_bmap_sub_blocks(bmap, stats.bs_nblocks);
  165. return 0;
  166. }
  167. static int nilfs_direct_last_key(const struct nilfs_bmap *bmap, __u64 *keyp)
  168. {
  169. struct nilfs_direct *direct;
  170. __u64 key, lastkey;
  171. direct = (struct nilfs_direct *)bmap;
  172. lastkey = NILFS_DIRECT_KEY_MAX + 1;
  173. for (key = NILFS_DIRECT_KEY_MIN; key <= NILFS_DIRECT_KEY_MAX; key++)
  174. if (nilfs_direct_get_ptr(direct, key) !=
  175. NILFS_BMAP_INVALID_PTR)
  176. lastkey = key;
  177. if (lastkey == NILFS_DIRECT_KEY_MAX + 1)
  178. return -ENOENT;
  179. BUG_ON(keyp == NULL);
  180. *keyp = lastkey;
  181. return 0;
  182. }
  183. static int nilfs_direct_check_insert(const struct nilfs_bmap *bmap, __u64 key)
  184. {
  185. return key > NILFS_DIRECT_KEY_MAX;
  186. }
  187. static int nilfs_direct_gather_data(struct nilfs_bmap *bmap,
  188. __u64 *keys, __u64 *ptrs, int nitems)
  189. {
  190. struct nilfs_direct *direct;
  191. __u64 key;
  192. __u64 ptr;
  193. int n;
  194. direct = (struct nilfs_direct *)bmap;
  195. if (nitems > NILFS_DIRECT_NBLOCKS)
  196. nitems = NILFS_DIRECT_NBLOCKS;
  197. n = 0;
  198. for (key = 0; key < nitems; key++) {
  199. ptr = nilfs_direct_get_ptr(direct, key);
  200. if (ptr != NILFS_BMAP_INVALID_PTR) {
  201. keys[n] = key;
  202. ptrs[n] = ptr;
  203. n++;
  204. }
  205. }
  206. return n;
  207. }
  208. int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap,
  209. __u64 key, __u64 *keys, __u64 *ptrs,
  210. int n, __u64 low, __u64 high)
  211. {
  212. struct nilfs_direct *direct;
  213. __le64 *dptrs;
  214. int ret, i, j;
  215. /* no need to allocate any resource for conversion */
  216. /* delete */
  217. ret = bmap->b_ops->bop_delete(bmap, key);
  218. if (ret < 0)
  219. return ret;
  220. /* free resources */
  221. if (bmap->b_ops->bop_clear != NULL)
  222. bmap->b_ops->bop_clear(bmap);
  223. /* convert */
  224. direct = (struct nilfs_direct *)bmap;
  225. dptrs = nilfs_direct_dptrs(direct);
  226. for (i = 0, j = 0; i < NILFS_DIRECT_NBLOCKS; i++) {
  227. if ((j < n) && (i == keys[j])) {
  228. dptrs[i] = (i != key) ?
  229. nilfs_bmap_ptr_to_dptr(ptrs[j]) :
  230. NILFS_BMAP_INVALID_PTR;
  231. j++;
  232. } else
  233. dptrs[i] = NILFS_BMAP_INVALID_PTR;
  234. }
  235. nilfs_direct_init(bmap, low, high);
  236. return 0;
  237. }
  238. static int nilfs_direct_propagate_v(struct nilfs_direct *direct,
  239. struct buffer_head *bh)
  240. {
  241. union nilfs_bmap_ptr_req oldreq, newreq;
  242. __u64 key;
  243. __u64 ptr;
  244. int ret;
  245. key = nilfs_bmap_data_get_key(&direct->d_bmap, bh);
  246. ptr = nilfs_direct_get_ptr(direct, key);
  247. if (!buffer_nilfs_volatile(bh)) {
  248. oldreq.bpr_ptr = ptr;
  249. newreq.bpr_ptr = ptr;
  250. ret = nilfs_bmap_prepare_update(&direct->d_bmap, &oldreq,
  251. &newreq);
  252. if (ret < 0)
  253. return ret;
  254. nilfs_bmap_commit_update(&direct->d_bmap, &oldreq, &newreq);
  255. set_buffer_nilfs_volatile(bh);
  256. nilfs_direct_set_ptr(direct, key, newreq.bpr_ptr);
  257. } else
  258. ret = nilfs_bmap_mark_dirty(&direct->d_bmap, ptr);
  259. return ret;
  260. }
  261. static int nilfs_direct_propagate(const struct nilfs_bmap *bmap,
  262. struct buffer_head *bh)
  263. {
  264. struct nilfs_direct *direct;
  265. direct = (struct nilfs_direct *)bmap;
  266. return (direct->d_ops->dop_propagate != NULL) ?
  267. direct->d_ops->dop_propagate(direct, bh) :
  268. 0;
  269. }
  270. static int nilfs_direct_assign_v(struct nilfs_direct *direct,
  271. __u64 key, __u64 ptr,
  272. struct buffer_head **bh,
  273. sector_t blocknr,
  274. union nilfs_binfo *binfo)
  275. {
  276. union nilfs_bmap_ptr_req req;
  277. int ret;
  278. req.bpr_ptr = ptr;
  279. ret = direct->d_bmap.b_pops->bpop_prepare_start_ptr(
  280. &direct->d_bmap, &req);
  281. if (ret < 0)
  282. return ret;
  283. direct->d_bmap.b_pops->bpop_commit_start_ptr(&direct->d_bmap,
  284. &req, blocknr);
  285. binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr);
  286. binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key);
  287. return 0;
  288. }
  289. static int nilfs_direct_assign_p(struct nilfs_direct *direct,
  290. __u64 key, __u64 ptr,
  291. struct buffer_head **bh,
  292. sector_t blocknr,
  293. union nilfs_binfo *binfo)
  294. {
  295. nilfs_direct_set_ptr(direct, key, blocknr);
  296. binfo->bi_dat.bi_blkoff = nilfs_bmap_key_to_dkey(key);
  297. binfo->bi_dat.bi_level = 0;
  298. return 0;
  299. }
  300. static int nilfs_direct_assign(struct nilfs_bmap *bmap,
  301. struct buffer_head **bh,
  302. sector_t blocknr,
  303. union nilfs_binfo *binfo)
  304. {
  305. struct nilfs_direct *direct;
  306. __u64 key;
  307. __u64 ptr;
  308. direct = (struct nilfs_direct *)bmap;
  309. key = nilfs_bmap_data_get_key(bmap, *bh);
  310. BUG_ON(key > NILFS_DIRECT_KEY_MAX);
  311. ptr = nilfs_direct_get_ptr(direct, key);
  312. BUG_ON(ptr == NILFS_BMAP_INVALID_PTR);
  313. return direct->d_ops->dop_assign(direct, key, ptr, bh,
  314. blocknr, binfo);
  315. }
  316. static const struct nilfs_bmap_operations nilfs_direct_ops = {
  317. .bop_lookup = nilfs_direct_lookup,
  318. .bop_insert = nilfs_direct_insert,
  319. .bop_delete = nilfs_direct_delete,
  320. .bop_clear = NULL,
  321. .bop_propagate = nilfs_direct_propagate,
  322. .bop_lookup_dirty_buffers = NULL,
  323. .bop_assign = nilfs_direct_assign,
  324. .bop_mark = NULL,
  325. .bop_last_key = nilfs_direct_last_key,
  326. .bop_check_insert = nilfs_direct_check_insert,
  327. .bop_check_delete = NULL,
  328. .bop_gather_data = nilfs_direct_gather_data,
  329. };
  330. static const struct nilfs_direct_operations nilfs_direct_ops_v = {
  331. .dop_find_target = nilfs_direct_find_target_v,
  332. .dop_set_target = nilfs_direct_set_target_v,
  333. .dop_propagate = nilfs_direct_propagate_v,
  334. .dop_assign = nilfs_direct_assign_v,
  335. };
  336. static const struct nilfs_direct_operations nilfs_direct_ops_p = {
  337. .dop_find_target = NULL,
  338. .dop_set_target = NULL,
  339. .dop_propagate = NULL,
  340. .dop_assign = nilfs_direct_assign_p,
  341. };
  342. int nilfs_direct_init(struct nilfs_bmap *bmap, __u64 low, __u64 high)
  343. {
  344. struct nilfs_direct *direct;
  345. direct = (struct nilfs_direct *)bmap;
  346. bmap->b_ops = &nilfs_direct_ops;
  347. bmap->b_low = low;
  348. bmap->b_high = high;
  349. switch (bmap->b_inode->i_ino) {
  350. case NILFS_DAT_INO:
  351. direct->d_ops = &nilfs_direct_ops_p;
  352. break;
  353. default:
  354. direct->d_ops = &nilfs_direct_ops_v;
  355. break;
  356. }
  357. return 0;
  358. }