direct.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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. direct->d_bmap.b_pops->bpop_commit_alloc_ptr(&direct->d_bmap, req);
  99. nilfs_direct_set_ptr(direct, key, req->bpr_ptr);
  100. if (!nilfs_bmap_dirty(&direct->d_bmap))
  101. nilfs_bmap_set_dirty(&direct->d_bmap);
  102. if (direct->d_ops->dop_set_target != NULL)
  103. direct->d_ops->dop_set_target(direct, key, req->bpr_ptr);
  104. }
  105. static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr)
  106. {
  107. struct nilfs_direct *direct;
  108. union nilfs_bmap_ptr_req req;
  109. struct nilfs_bmap_stats stats;
  110. int ret;
  111. direct = (struct nilfs_direct *)bmap;
  112. if (key > NILFS_DIRECT_KEY_MAX)
  113. return -ENOENT;
  114. if (nilfs_direct_get_ptr(direct, key) != NILFS_BMAP_INVALID_PTR)
  115. return -EEXIST;
  116. ret = nilfs_direct_prepare_insert(direct, key, &req, &stats);
  117. if (ret < 0)
  118. return ret;
  119. nilfs_direct_commit_insert(direct, &req, key, ptr);
  120. nilfs_bmap_add_blocks(bmap, stats.bs_nblocks);
  121. return 0;
  122. }
  123. static int nilfs_direct_prepare_delete(struct nilfs_direct *direct,
  124. union nilfs_bmap_ptr_req *req,
  125. __u64 key,
  126. struct nilfs_bmap_stats *stats)
  127. {
  128. int ret;
  129. if (direct->d_bmap.b_pops->bpop_prepare_end_ptr != NULL) {
  130. req->bpr_ptr = nilfs_direct_get_ptr(direct, key);
  131. ret = direct->d_bmap.b_pops->bpop_prepare_end_ptr(
  132. &direct->d_bmap, req);
  133. if (ret < 0)
  134. return ret;
  135. }
  136. stats->bs_nblocks = 1;
  137. return 0;
  138. }
  139. static void nilfs_direct_commit_delete(struct nilfs_direct *direct,
  140. union nilfs_bmap_ptr_req *req,
  141. __u64 key)
  142. {
  143. if (direct->d_bmap.b_pops->bpop_commit_end_ptr != NULL)
  144. direct->d_bmap.b_pops->bpop_commit_end_ptr(
  145. &direct->d_bmap, req);
  146. nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR);
  147. }
  148. static int nilfs_direct_delete(struct nilfs_bmap *bmap, __u64 key)
  149. {
  150. struct nilfs_direct *direct;
  151. union nilfs_bmap_ptr_req req;
  152. struct nilfs_bmap_stats stats;
  153. int ret;
  154. direct = (struct nilfs_direct *)bmap;
  155. if ((key > NILFS_DIRECT_KEY_MAX) ||
  156. nilfs_direct_get_ptr(direct, key) == NILFS_BMAP_INVALID_PTR)
  157. return -ENOENT;
  158. ret = nilfs_direct_prepare_delete(direct, &req, key, &stats);
  159. if (ret < 0)
  160. return ret;
  161. nilfs_direct_commit_delete(direct, &req, key);
  162. nilfs_bmap_sub_blocks(bmap, stats.bs_nblocks);
  163. return 0;
  164. }
  165. static int nilfs_direct_last_key(const struct nilfs_bmap *bmap, __u64 *keyp)
  166. {
  167. struct nilfs_direct *direct;
  168. __u64 key, lastkey;
  169. direct = (struct nilfs_direct *)bmap;
  170. lastkey = NILFS_DIRECT_KEY_MAX + 1;
  171. for (key = NILFS_DIRECT_KEY_MIN; key <= NILFS_DIRECT_KEY_MAX; key++)
  172. if (nilfs_direct_get_ptr(direct, key) !=
  173. NILFS_BMAP_INVALID_PTR)
  174. lastkey = key;
  175. if (lastkey == NILFS_DIRECT_KEY_MAX + 1)
  176. return -ENOENT;
  177. *keyp = lastkey;
  178. return 0;
  179. }
  180. static int nilfs_direct_check_insert(const struct nilfs_bmap *bmap, __u64 key)
  181. {
  182. return key > NILFS_DIRECT_KEY_MAX;
  183. }
  184. static int nilfs_direct_gather_data(struct nilfs_bmap *bmap,
  185. __u64 *keys, __u64 *ptrs, int nitems)
  186. {
  187. struct nilfs_direct *direct;
  188. __u64 key;
  189. __u64 ptr;
  190. int n;
  191. direct = (struct nilfs_direct *)bmap;
  192. if (nitems > NILFS_DIRECT_NBLOCKS)
  193. nitems = NILFS_DIRECT_NBLOCKS;
  194. n = 0;
  195. for (key = 0; key < nitems; key++) {
  196. ptr = nilfs_direct_get_ptr(direct, key);
  197. if (ptr != NILFS_BMAP_INVALID_PTR) {
  198. keys[n] = key;
  199. ptrs[n] = ptr;
  200. n++;
  201. }
  202. }
  203. return n;
  204. }
  205. int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap,
  206. __u64 key, __u64 *keys, __u64 *ptrs, int n)
  207. {
  208. struct nilfs_direct *direct;
  209. __le64 *dptrs;
  210. int ret, i, j;
  211. /* no need to allocate any resource for conversion */
  212. /* delete */
  213. ret = bmap->b_ops->bop_delete(bmap, key);
  214. if (ret < 0)
  215. return ret;
  216. /* free resources */
  217. if (bmap->b_ops->bop_clear != NULL)
  218. bmap->b_ops->bop_clear(bmap);
  219. /* convert */
  220. direct = (struct nilfs_direct *)bmap;
  221. dptrs = nilfs_direct_dptrs(direct);
  222. for (i = 0, j = 0; i < NILFS_DIRECT_NBLOCKS; i++) {
  223. if ((j < n) && (i == keys[j])) {
  224. dptrs[i] = (i != key) ?
  225. nilfs_bmap_ptr_to_dptr(ptrs[j]) :
  226. NILFS_BMAP_INVALID_PTR;
  227. j++;
  228. } else
  229. dptrs[i] = NILFS_BMAP_INVALID_PTR;
  230. }
  231. nilfs_direct_init(bmap);
  232. return 0;
  233. }
  234. static int nilfs_direct_propagate_v(struct nilfs_direct *direct,
  235. struct buffer_head *bh)
  236. {
  237. union nilfs_bmap_ptr_req oldreq, newreq;
  238. __u64 key;
  239. __u64 ptr;
  240. int ret;
  241. key = nilfs_bmap_data_get_key(&direct->d_bmap, bh);
  242. ptr = nilfs_direct_get_ptr(direct, key);
  243. if (!buffer_nilfs_volatile(bh)) {
  244. oldreq.bpr_ptr = ptr;
  245. newreq.bpr_ptr = ptr;
  246. ret = nilfs_bmap_prepare_update(&direct->d_bmap, &oldreq,
  247. &newreq);
  248. if (ret < 0)
  249. return ret;
  250. nilfs_bmap_commit_update(&direct->d_bmap, &oldreq, &newreq);
  251. set_buffer_nilfs_volatile(bh);
  252. nilfs_direct_set_ptr(direct, key, newreq.bpr_ptr);
  253. } else
  254. ret = nilfs_bmap_mark_dirty(&direct->d_bmap, ptr);
  255. return ret;
  256. }
  257. static int nilfs_direct_propagate(const struct nilfs_bmap *bmap,
  258. struct buffer_head *bh)
  259. {
  260. struct nilfs_direct *direct;
  261. direct = (struct nilfs_direct *)bmap;
  262. return (direct->d_ops->dop_propagate != NULL) ?
  263. direct->d_ops->dop_propagate(direct, bh) :
  264. 0;
  265. }
  266. static int nilfs_direct_assign_v(struct nilfs_direct *direct,
  267. __u64 key, __u64 ptr,
  268. struct buffer_head **bh,
  269. sector_t blocknr,
  270. union nilfs_binfo *binfo)
  271. {
  272. union nilfs_bmap_ptr_req req;
  273. int ret;
  274. req.bpr_ptr = ptr;
  275. ret = nilfs_bmap_start_v(&direct->d_bmap, &req, blocknr);
  276. if (unlikely(ret < 0))
  277. return ret;
  278. binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr);
  279. binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key);
  280. return 0;
  281. }
  282. static int nilfs_direct_assign_p(struct nilfs_direct *direct,
  283. __u64 key, __u64 ptr,
  284. struct buffer_head **bh,
  285. sector_t blocknr,
  286. union nilfs_binfo *binfo)
  287. {
  288. nilfs_direct_set_ptr(direct, key, blocknr);
  289. binfo->bi_dat.bi_blkoff = nilfs_bmap_key_to_dkey(key);
  290. binfo->bi_dat.bi_level = 0;
  291. return 0;
  292. }
  293. static int nilfs_direct_assign(struct nilfs_bmap *bmap,
  294. struct buffer_head **bh,
  295. sector_t blocknr,
  296. union nilfs_binfo *binfo)
  297. {
  298. struct nilfs_direct *direct;
  299. __u64 key;
  300. __u64 ptr;
  301. direct = (struct nilfs_direct *)bmap;
  302. key = nilfs_bmap_data_get_key(bmap, *bh);
  303. if (unlikely(key > NILFS_DIRECT_KEY_MAX)) {
  304. printk(KERN_CRIT "%s: invalid key: %llu\n", __func__,
  305. (unsigned long long)key);
  306. return -EINVAL;
  307. }
  308. ptr = nilfs_direct_get_ptr(direct, key);
  309. if (unlikely(ptr == NILFS_BMAP_INVALID_PTR)) {
  310. printk(KERN_CRIT "%s: invalid pointer: %llu\n", __func__,
  311. (unsigned long long)ptr);
  312. return -EINVAL;
  313. }
  314. return direct->d_ops->dop_assign(direct, key, ptr, bh,
  315. blocknr, binfo);
  316. }
  317. static const struct nilfs_bmap_operations nilfs_direct_ops = {
  318. .bop_lookup = nilfs_direct_lookup,
  319. .bop_insert = nilfs_direct_insert,
  320. .bop_delete = nilfs_direct_delete,
  321. .bop_clear = NULL,
  322. .bop_propagate = nilfs_direct_propagate,
  323. .bop_lookup_dirty_buffers = NULL,
  324. .bop_assign = nilfs_direct_assign,
  325. .bop_mark = NULL,
  326. .bop_last_key = nilfs_direct_last_key,
  327. .bop_check_insert = nilfs_direct_check_insert,
  328. .bop_check_delete = NULL,
  329. .bop_gather_data = nilfs_direct_gather_data,
  330. };
  331. static const struct nilfs_direct_operations nilfs_direct_ops_v = {
  332. .dop_find_target = nilfs_direct_find_target_v,
  333. .dop_set_target = nilfs_direct_set_target_v,
  334. .dop_propagate = nilfs_direct_propagate_v,
  335. .dop_assign = nilfs_direct_assign_v,
  336. };
  337. static const struct nilfs_direct_operations nilfs_direct_ops_p = {
  338. .dop_find_target = NULL,
  339. .dop_set_target = NULL,
  340. .dop_propagate = NULL,
  341. .dop_assign = nilfs_direct_assign_p,
  342. };
  343. int nilfs_direct_init(struct nilfs_bmap *bmap)
  344. {
  345. struct nilfs_direct *direct = (struct nilfs_direct *)bmap;
  346. bmap->b_ops = &nilfs_direct_ops;
  347. switch (bmap->b_inode->i_ino) {
  348. case NILFS_DAT_INO:
  349. direct->d_ops = &nilfs_direct_ops_p;
  350. break;
  351. default:
  352. direct->d_ops = &nilfs_direct_ops_v;
  353. break;
  354. }
  355. return 0;
  356. }