direct.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  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. *keyp = lastkey;
  180. return 0;
  181. }
  182. static int nilfs_direct_check_insert(const struct nilfs_bmap *bmap, __u64 key)
  183. {
  184. return key > NILFS_DIRECT_KEY_MAX;
  185. }
  186. static int nilfs_direct_gather_data(struct nilfs_bmap *bmap,
  187. __u64 *keys, __u64 *ptrs, int nitems)
  188. {
  189. struct nilfs_direct *direct;
  190. __u64 key;
  191. __u64 ptr;
  192. int n;
  193. direct = (struct nilfs_direct *)bmap;
  194. if (nitems > NILFS_DIRECT_NBLOCKS)
  195. nitems = NILFS_DIRECT_NBLOCKS;
  196. n = 0;
  197. for (key = 0; key < nitems; key++) {
  198. ptr = nilfs_direct_get_ptr(direct, key);
  199. if (ptr != NILFS_BMAP_INVALID_PTR) {
  200. keys[n] = key;
  201. ptrs[n] = ptr;
  202. n++;
  203. }
  204. }
  205. return n;
  206. }
  207. int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap,
  208. __u64 key, __u64 *keys, __u64 *ptrs,
  209. int n, __u64 low, __u64 high)
  210. {
  211. struct nilfs_direct *direct;
  212. __le64 *dptrs;
  213. int ret, i, j;
  214. /* no need to allocate any resource for conversion */
  215. /* delete */
  216. ret = bmap->b_ops->bop_delete(bmap, key);
  217. if (ret < 0)
  218. return ret;
  219. /* free resources */
  220. if (bmap->b_ops->bop_clear != NULL)
  221. bmap->b_ops->bop_clear(bmap);
  222. /* convert */
  223. direct = (struct nilfs_direct *)bmap;
  224. dptrs = nilfs_direct_dptrs(direct);
  225. for (i = 0, j = 0; i < NILFS_DIRECT_NBLOCKS; i++) {
  226. if ((j < n) && (i == keys[j])) {
  227. dptrs[i] = (i != key) ?
  228. nilfs_bmap_ptr_to_dptr(ptrs[j]) :
  229. NILFS_BMAP_INVALID_PTR;
  230. j++;
  231. } else
  232. dptrs[i] = NILFS_BMAP_INVALID_PTR;
  233. }
  234. nilfs_direct_init(bmap, low, high);
  235. return 0;
  236. }
  237. static int nilfs_direct_propagate_v(struct nilfs_direct *direct,
  238. struct buffer_head *bh)
  239. {
  240. union nilfs_bmap_ptr_req oldreq, newreq;
  241. __u64 key;
  242. __u64 ptr;
  243. int ret;
  244. key = nilfs_bmap_data_get_key(&direct->d_bmap, bh);
  245. ptr = nilfs_direct_get_ptr(direct, key);
  246. if (!buffer_nilfs_volatile(bh)) {
  247. oldreq.bpr_ptr = ptr;
  248. newreq.bpr_ptr = ptr;
  249. ret = nilfs_bmap_prepare_update(&direct->d_bmap, &oldreq,
  250. &newreq);
  251. if (ret < 0)
  252. return ret;
  253. nilfs_bmap_commit_update(&direct->d_bmap, &oldreq, &newreq);
  254. set_buffer_nilfs_volatile(bh);
  255. nilfs_direct_set_ptr(direct, key, newreq.bpr_ptr);
  256. } else
  257. ret = nilfs_bmap_mark_dirty(&direct->d_bmap, ptr);
  258. return ret;
  259. }
  260. static int nilfs_direct_propagate(const struct nilfs_bmap *bmap,
  261. struct buffer_head *bh)
  262. {
  263. struct nilfs_direct *direct;
  264. direct = (struct nilfs_direct *)bmap;
  265. return (direct->d_ops->dop_propagate != NULL) ?
  266. direct->d_ops->dop_propagate(direct, bh) :
  267. 0;
  268. }
  269. static int nilfs_direct_assign_v(struct nilfs_direct *direct,
  270. __u64 key, __u64 ptr,
  271. struct buffer_head **bh,
  272. sector_t blocknr,
  273. union nilfs_binfo *binfo)
  274. {
  275. union nilfs_bmap_ptr_req req;
  276. int ret;
  277. req.bpr_ptr = ptr;
  278. ret = direct->d_bmap.b_pops->bpop_prepare_start_ptr(
  279. &direct->d_bmap, &req);
  280. if (ret < 0)
  281. return ret;
  282. direct->d_bmap.b_pops->bpop_commit_start_ptr(&direct->d_bmap,
  283. &req, blocknr);
  284. binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr);
  285. binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key);
  286. return 0;
  287. }
  288. static int nilfs_direct_assign_p(struct nilfs_direct *direct,
  289. __u64 key, __u64 ptr,
  290. struct buffer_head **bh,
  291. sector_t blocknr,
  292. union nilfs_binfo *binfo)
  293. {
  294. nilfs_direct_set_ptr(direct, key, blocknr);
  295. binfo->bi_dat.bi_blkoff = nilfs_bmap_key_to_dkey(key);
  296. binfo->bi_dat.bi_level = 0;
  297. return 0;
  298. }
  299. static int nilfs_direct_assign(struct nilfs_bmap *bmap,
  300. struct buffer_head **bh,
  301. sector_t blocknr,
  302. union nilfs_binfo *binfo)
  303. {
  304. struct nilfs_direct *direct;
  305. __u64 key;
  306. __u64 ptr;
  307. direct = (struct nilfs_direct *)bmap;
  308. key = nilfs_bmap_data_get_key(bmap, *bh);
  309. if (unlikely(key > NILFS_DIRECT_KEY_MAX)) {
  310. printk(KERN_CRIT "%s: invalid key: %llu\n", __func__,
  311. (unsigned long long)key);
  312. return -EINVAL;
  313. }
  314. ptr = nilfs_direct_get_ptr(direct, key);
  315. if (unlikely(ptr == NILFS_BMAP_INVALID_PTR)) {
  316. printk(KERN_CRIT "%s: invalid pointer: %llu\n", __func__,
  317. (unsigned long long)ptr);
  318. return -EINVAL;
  319. }
  320. return direct->d_ops->dop_assign(direct, key, ptr, bh,
  321. blocknr, binfo);
  322. }
  323. static const struct nilfs_bmap_operations nilfs_direct_ops = {
  324. .bop_lookup = nilfs_direct_lookup,
  325. .bop_insert = nilfs_direct_insert,
  326. .bop_delete = nilfs_direct_delete,
  327. .bop_clear = NULL,
  328. .bop_propagate = nilfs_direct_propagate,
  329. .bop_lookup_dirty_buffers = NULL,
  330. .bop_assign = nilfs_direct_assign,
  331. .bop_mark = NULL,
  332. .bop_last_key = nilfs_direct_last_key,
  333. .bop_check_insert = nilfs_direct_check_insert,
  334. .bop_check_delete = NULL,
  335. .bop_gather_data = nilfs_direct_gather_data,
  336. };
  337. static const struct nilfs_direct_operations nilfs_direct_ops_v = {
  338. .dop_find_target = nilfs_direct_find_target_v,
  339. .dop_set_target = nilfs_direct_set_target_v,
  340. .dop_propagate = nilfs_direct_propagate_v,
  341. .dop_assign = nilfs_direct_assign_v,
  342. };
  343. static const struct nilfs_direct_operations nilfs_direct_ops_p = {
  344. .dop_find_target = NULL,
  345. .dop_set_target = NULL,
  346. .dop_propagate = NULL,
  347. .dop_assign = nilfs_direct_assign_p,
  348. };
  349. int nilfs_direct_init(struct nilfs_bmap *bmap, __u64 low, __u64 high)
  350. {
  351. struct nilfs_direct *direct;
  352. direct = (struct nilfs_direct *)bmap;
  353. bmap->b_ops = &nilfs_direct_ops;
  354. bmap->b_low = low;
  355. bmap->b_high = high;
  356. switch (bmap->b_inode->i_ino) {
  357. case NILFS_DAT_INO:
  358. direct->d_ops = &nilfs_direct_ops_p;
  359. break;
  360. default:
  361. direct->d_ops = &nilfs_direct_ops_v;
  362. break;
  363. }
  364. return 0;
  365. }