PageRenderTime 51ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/sys/fs/nandfs/nandfs_cleaner.c

https://bitbucket.org/freebsd/freebsd-head/
C | 620 lines | 491 code | 95 blank | 34 comment | 81 complexity | bb1b30e522dfa42348b0f78a19d26ec9 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.0, LGPL-2.1, BSD-2-Clause, 0BSD, JSON, AGPL-1.0, GPL-2.0
  1. /*-
  2. * Copyright (c) 2010-2012 Semihalf.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. * SUCH DAMAGE.
  25. */
  26. #include <sys/cdefs.h>
  27. __FBSDID("$FreeBSD$");
  28. #include <sys/param.h>
  29. #include <sys/systm.h>
  30. #include <sys/conf.h>
  31. #include <sys/kernel.h>
  32. #include <sys/lock.h>
  33. #include <sys/malloc.h>
  34. #include <sys/mount.h>
  35. #include <sys/mutex.h>
  36. #include <sys/buf.h>
  37. #include <sys/namei.h>
  38. #include <sys/vnode.h>
  39. #include <sys/bio.h>
  40. #include <fs/nandfs/nandfs_mount.h>
  41. #include <fs/nandfs/nandfs.h>
  42. #include <fs/nandfs/nandfs_subr.h>
  43. #define NANDFS_CLEANER_KILL 1
  44. static void nandfs_cleaner(struct nandfs_device *);
  45. static int nandfs_cleaner_clean_segments(struct nandfs_device *,
  46. struct nandfs_vinfo *, uint32_t, struct nandfs_period *, uint32_t,
  47. struct nandfs_bdesc *, uint32_t, uint64_t *, uint32_t);
  48. static int
  49. nandfs_process_bdesc(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd,
  50. uint64_t nmembs);
  51. static void
  52. nandfs_wakeup_wait_cleaner(struct nandfs_device *fsdev, int reason)
  53. {
  54. mtx_lock(&fsdev->nd_clean_mtx);
  55. if (reason == NANDFS_CLEANER_KILL)
  56. fsdev->nd_cleaner_exit = 1;
  57. if (fsdev->nd_cleaning == 0) {
  58. fsdev->nd_cleaning = 1;
  59. wakeup(&fsdev->nd_cleaning);
  60. }
  61. cv_wait(&fsdev->nd_clean_cv, &fsdev->nd_clean_mtx);
  62. mtx_unlock(&fsdev->nd_clean_mtx);
  63. }
  64. int
  65. nandfs_start_cleaner(struct nandfs_device *fsdev)
  66. {
  67. int error;
  68. MPASS(fsdev->nd_cleaner == NULL);
  69. fsdev->nd_cleaner_exit = 0;
  70. error = kthread_add((void(*)(void *))nandfs_cleaner, fsdev, NULL,
  71. &fsdev->nd_cleaner, 0, 0, "nandfs_cleaner");
  72. if (error)
  73. printf("nandfs: could not start cleaner: %d\n", error);
  74. return (error);
  75. }
  76. int
  77. nandfs_stop_cleaner(struct nandfs_device *fsdev)
  78. {
  79. MPASS(fsdev->nd_cleaner != NULL);
  80. nandfs_wakeup_wait_cleaner(fsdev, NANDFS_CLEANER_KILL);
  81. fsdev->nd_cleaner = NULL;
  82. DPRINTF(CLEAN, ("cleaner stopped\n"));
  83. return (0);
  84. }
  85. static int
  86. nandfs_cleaner_finished(struct nandfs_device *fsdev)
  87. {
  88. int exit;
  89. mtx_lock(&fsdev->nd_clean_mtx);
  90. fsdev->nd_cleaning = 0;
  91. if (!fsdev->nd_cleaner_exit) {
  92. DPRINTF(CLEAN, ("%s: sleep\n", __func__));
  93. msleep(&fsdev->nd_cleaning, &fsdev->nd_clean_mtx, PRIBIO, "-",
  94. hz * nandfs_cleaner_interval);
  95. }
  96. exit = fsdev->nd_cleaner_exit;
  97. cv_broadcast(&fsdev->nd_clean_cv);
  98. mtx_unlock(&fsdev->nd_clean_mtx);
  99. if (exit) {
  100. DPRINTF(CLEAN, ("%s: no longer active\n", __func__));
  101. return (1);
  102. }
  103. return (0);
  104. }
  105. static void
  106. print_suinfo(struct nandfs_suinfo *suinfo, int nsegs)
  107. {
  108. int i;
  109. for (i = 0; i < nsegs; i++) {
  110. DPRINTF(CLEAN, ("%jx %jd %c%c%c %10u\n",
  111. suinfo[i].nsi_num, suinfo[i].nsi_lastmod,
  112. (suinfo[i].nsi_flags &
  113. (NANDFS_SEGMENT_USAGE_ACTIVE) ? 'a' : '-'),
  114. (suinfo[i].nsi_flags &
  115. (NANDFS_SEGMENT_USAGE_DIRTY) ? 'd' : '-'),
  116. (suinfo[i].nsi_flags &
  117. (NANDFS_SEGMENT_USAGE_ERROR) ? 'e' : '-'),
  118. suinfo[i].nsi_blocks));
  119. }
  120. }
  121. static int
  122. nandfs_cleaner_vblock_is_alive(struct nandfs_device *fsdev,
  123. struct nandfs_vinfo *vinfo, struct nandfs_cpinfo *cp, uint32_t ncps)
  124. {
  125. int64_t idx, min, max;
  126. if (vinfo->nvi_end >= fsdev->nd_last_cno)
  127. return (1);
  128. if (ncps == 0)
  129. return (0);
  130. if (vinfo->nvi_end < cp[0].nci_cno ||
  131. vinfo->nvi_start > cp[ncps - 1].nci_cno)
  132. return (0);
  133. idx = min = 0;
  134. max = ncps - 1;
  135. while (min <= max) {
  136. idx = (min + max) / 2;
  137. if (vinfo->nvi_start == cp[idx].nci_cno)
  138. return (1);
  139. if (vinfo->nvi_start < cp[idx].nci_cno)
  140. max = idx - 1;
  141. else
  142. min = idx + 1;
  143. }
  144. return (vinfo->nvi_end >= cp[idx].nci_cno);
  145. }
  146. static void
  147. nandfs_cleaner_vinfo_mark_alive(struct nandfs_device *fsdev,
  148. struct nandfs_vinfo *vinfo, uint32_t nmembs, struct nandfs_cpinfo *cp,
  149. uint32_t ncps)
  150. {
  151. uint32_t i;
  152. for (i = 0; i < nmembs; i++)
  153. vinfo[i].nvi_alive =
  154. nandfs_cleaner_vblock_is_alive(fsdev, &vinfo[i], cp, ncps);
  155. }
  156. static int
  157. nandfs_cleaner_bdesc_is_alive(struct nandfs_device *fsdev,
  158. struct nandfs_bdesc *bdesc)
  159. {
  160. int alive;
  161. alive = bdesc->bd_oblocknr == bdesc->bd_blocknr;
  162. if (!alive)
  163. MPASS(abs(bdesc->bd_oblocknr - bdesc->bd_blocknr) > 2);
  164. return (alive);
  165. }
  166. static void
  167. nandfs_cleaner_bdesc_mark_alive(struct nandfs_device *fsdev,
  168. struct nandfs_bdesc *bdesc, uint32_t nmembs)
  169. {
  170. uint32_t i;
  171. for (i = 0; i < nmembs; i++)
  172. bdesc[i].bd_alive = nandfs_cleaner_bdesc_is_alive(fsdev,
  173. &bdesc[i]);
  174. }
  175. static void
  176. nandfs_cleaner_iterate_psegment(struct nandfs_device *fsdev,
  177. struct nandfs_segment_summary *segsum, union nandfs_binfo *binfo,
  178. nandfs_daddr_t blk, struct nandfs_vinfo **vipp, struct nandfs_bdesc **bdpp)
  179. {
  180. int i;
  181. DPRINTF(CLEAN, ("%s nbinfos %x\n", __func__, segsum->ss_nbinfos));
  182. for (i = 0; i < segsum->ss_nbinfos; i++) {
  183. if (binfo[i].bi_v.bi_ino == NANDFS_DAT_INO) {
  184. (*bdpp)->bd_oblocknr = blk + segsum->ss_nblocks -
  185. segsum->ss_nbinfos + i;
  186. /*
  187. * XXX Hack
  188. */
  189. if (segsum->ss_flags & NANDFS_SS_SR)
  190. (*bdpp)->bd_oblocknr--;
  191. (*bdpp)->bd_level = binfo[i].bi_dat.bi_level;
  192. (*bdpp)->bd_offset = binfo[i].bi_dat.bi_blkoff;
  193. (*bdpp)++;
  194. } else {
  195. (*vipp)->nvi_ino = binfo[i].bi_v.bi_ino;
  196. (*vipp)->nvi_vblocknr = binfo[i].bi_v.bi_vblocknr;
  197. (*vipp)++;
  198. }
  199. }
  200. }
  201. static int
  202. nandfs_cleaner_iterate_segment(struct nandfs_device *fsdev, uint64_t segno,
  203. struct nandfs_vinfo **vipp, struct nandfs_bdesc **bdpp, int *select)
  204. {
  205. struct nandfs_segment_summary *segsum;
  206. union nandfs_binfo *binfo;
  207. struct buf *bp;
  208. uint32_t nblocks;
  209. nandfs_daddr_t curr, start, end;
  210. int error = 0;
  211. nandfs_get_segment_range(fsdev, segno, &start, &end);
  212. DPRINTF(CLEAN, ("%s: segno %jx start %jx end %jx\n", __func__, segno,
  213. start, end));
  214. *select = 0;
  215. for (curr = start; curr < end; curr += nblocks) {
  216. error = nandfs_dev_bread(fsdev, curr, NOCRED, 0, &bp);
  217. if (error) {
  218. brelse(bp);
  219. nandfs_error("%s: couldn't load segment summary of %jx: %d\n",
  220. __func__, segno, error);
  221. return (error);
  222. }
  223. segsum = (struct nandfs_segment_summary *)bp->b_data;
  224. binfo = (union nandfs_binfo *)(bp->b_data + segsum->ss_bytes);
  225. if (!nandfs_segsum_valid(segsum)) {
  226. brelse(bp);
  227. nandfs_error("nandfs: invalid summary of segment %jx\n", segno);
  228. return (error);
  229. }
  230. DPRINTF(CLEAN, ("%s: %jx magic %x bytes %x nblocks %x nbinfos "
  231. "%x\n", __func__, segno, segsum->ss_magic, segsum->ss_bytes,
  232. segsum->ss_nblocks, segsum->ss_nbinfos));
  233. nandfs_cleaner_iterate_psegment(fsdev, segsum, binfo, curr,
  234. vipp, bdpp);
  235. nblocks = segsum->ss_nblocks;
  236. brelse(bp);
  237. }
  238. if (error == 0)
  239. *select = 1;
  240. return (error);
  241. }
  242. static int
  243. nandfs_cleaner_choose_segment(struct nandfs_device *fsdev, uint64_t **segpp,
  244. uint64_t nsegs, uint64_t *rseg)
  245. {
  246. struct nandfs_suinfo *suinfo;
  247. uint64_t i, ssegs;
  248. int error;
  249. suinfo = malloc(sizeof(*suinfo) * nsegs, M_NANDFSTEMP,
  250. M_ZERO | M_WAITOK);
  251. if (*rseg >= fsdev->nd_fsdata.f_nsegments)
  252. *rseg = 0;
  253. retry:
  254. error = nandfs_get_segment_info_filter(fsdev, suinfo, nsegs, *rseg,
  255. &ssegs, NANDFS_SEGMENT_USAGE_DIRTY,
  256. NANDFS_SEGMENT_USAGE_ACTIVE | NANDFS_SEGMENT_USAGE_ERROR |
  257. NANDFS_SEGMENT_USAGE_GC);
  258. if (error) {
  259. nandfs_error("%s:%d", __FILE__, __LINE__);
  260. goto out;
  261. }
  262. if (ssegs == 0 && *rseg != 0) {
  263. *rseg = 0;
  264. goto retry;
  265. }
  266. if (ssegs > 0) {
  267. print_suinfo(suinfo, ssegs);
  268. for (i = 0; i < ssegs; i++) {
  269. (**segpp) = suinfo[i].nsi_num;
  270. (*segpp)++;
  271. }
  272. *rseg = suinfo[i - 1].nsi_num + 1;
  273. }
  274. out:
  275. free(suinfo, M_NANDFSTEMP);
  276. return (error);
  277. }
  278. static int
  279. nandfs_cleaner_body(struct nandfs_device *fsdev, uint64_t *rseg)
  280. {
  281. struct nandfs_vinfo *vinfo, *vip, *vipi;
  282. struct nandfs_bdesc *bdesc, *bdp, *bdpi;
  283. struct nandfs_cpstat cpstat;
  284. struct nandfs_cpinfo *cpinfo = NULL;
  285. uint64_t *segnums, *segp;
  286. int select, selected;
  287. int error = 0;
  288. int nsegs;
  289. int i;
  290. nsegs = nandfs_cleaner_segments;
  291. vip = vinfo = malloc(sizeof(*vinfo) *
  292. fsdev->nd_fsdata.f_blocks_per_segment * nsegs, M_NANDFSTEMP,
  293. M_ZERO | M_WAITOK);
  294. bdp = bdesc = malloc(sizeof(*bdesc) *
  295. fsdev->nd_fsdata.f_blocks_per_segment * nsegs, M_NANDFSTEMP,
  296. M_ZERO | M_WAITOK);
  297. segp = segnums = malloc(sizeof(*segnums) * nsegs, M_NANDFSTEMP,
  298. M_WAITOK);
  299. error = nandfs_cleaner_choose_segment(fsdev, &segp, nsegs, rseg);
  300. if (error) {
  301. nandfs_error("%s:%d", __FILE__, __LINE__);
  302. goto out;
  303. }
  304. if (segnums == segp)
  305. goto out;
  306. selected = 0;
  307. for (i = 0; i < segp - segnums; i++) {
  308. error = nandfs_cleaner_iterate_segment(fsdev, segnums[i], &vip,
  309. &bdp, &select);
  310. if (error) {
  311. /*
  312. * XXX deselect (see below)?
  313. */
  314. goto out;
  315. }
  316. if (!select)
  317. segnums[i] = NANDFS_NOSEGMENT;
  318. else {
  319. error = nandfs_markgc_segment(fsdev, segnums[i]);
  320. if (error) {
  321. nandfs_error("%s:%d\n", __FILE__, __LINE__);
  322. goto out;
  323. }
  324. selected++;
  325. }
  326. }
  327. if (selected == 0) {
  328. MPASS(vinfo == vip);
  329. MPASS(bdesc == bdp);
  330. goto out;
  331. }
  332. error = nandfs_get_cpstat(fsdev->nd_cp_node, &cpstat);
  333. if (error) {
  334. nandfs_error("%s:%d\n", __FILE__, __LINE__);
  335. goto out;
  336. }
  337. if (cpstat.ncp_nss != 0) {
  338. cpinfo = malloc(sizeof(struct nandfs_cpinfo) * cpstat.ncp_nss,
  339. M_NANDFSTEMP, M_WAITOK);
  340. error = nandfs_get_cpinfo(fsdev->nd_cp_node, 1, NANDFS_SNAPSHOT,
  341. cpinfo, cpstat.ncp_nss, NULL);
  342. if (error) {
  343. nandfs_error("%s:%d\n", __FILE__, __LINE__);
  344. goto out_locked;
  345. }
  346. }
  347. NANDFS_WRITELOCK(fsdev);
  348. DPRINTF(CLEAN, ("%s: got lock\n", __func__));
  349. error = nandfs_get_dat_vinfo(fsdev, vinfo, vip - vinfo);
  350. if (error) {
  351. nandfs_error("%s:%d\n", __FILE__, __LINE__);
  352. goto out_locked;
  353. }
  354. nandfs_cleaner_vinfo_mark_alive(fsdev, vinfo, vip - vinfo, cpinfo,
  355. cpstat.ncp_nss);
  356. error = nandfs_get_dat_bdescs(fsdev, bdesc, bdp - bdesc);
  357. if (error) {
  358. nandfs_error("%s:%d\n", __FILE__, __LINE__);
  359. goto out_locked;
  360. }
  361. nandfs_cleaner_bdesc_mark_alive(fsdev, bdesc, bdp - bdesc);
  362. DPRINTF(CLEAN, ("got:\n"));
  363. for (vipi = vinfo; vipi < vip; vipi++) {
  364. DPRINTF(CLEAN, ("v ino %jx vblocknr %jx start %jx end %jx "
  365. "alive %d\n", vipi->nvi_ino, vipi->nvi_vblocknr,
  366. vipi->nvi_start, vipi->nvi_end, vipi->nvi_alive));
  367. }
  368. for (bdpi = bdesc; bdpi < bdp; bdpi++) {
  369. DPRINTF(CLEAN, ("b oblocknr %jx blocknr %jx offset %jx "
  370. "alive %d\n", bdpi->bd_oblocknr, bdpi->bd_blocknr,
  371. bdpi->bd_offset, bdpi->bd_alive));
  372. }
  373. DPRINTF(CLEAN, ("end list\n"));
  374. error = nandfs_cleaner_clean_segments(fsdev, vinfo, vip - vinfo, NULL,
  375. 0, bdesc, bdp - bdesc, segnums, segp - segnums);
  376. if (error)
  377. nandfs_error("%s:%d\n", __FILE__, __LINE__);
  378. out_locked:
  379. NANDFS_WRITEUNLOCK(fsdev);
  380. out:
  381. free(cpinfo, M_NANDFSTEMP);
  382. free(segnums, M_NANDFSTEMP);
  383. free(bdesc, M_NANDFSTEMP);
  384. free(vinfo, M_NANDFSTEMP);
  385. return (error);
  386. }
  387. static void
  388. nandfs_cleaner(struct nandfs_device *fsdev)
  389. {
  390. uint64_t checked_seg = 0;
  391. int error;
  392. while (!nandfs_cleaner_finished(fsdev)) {
  393. if (!nandfs_cleaner_enable || rebooting)
  394. continue;
  395. DPRINTF(CLEAN, ("%s: run started\n", __func__));
  396. fsdev->nd_cleaning = 1;
  397. error = nandfs_cleaner_body(fsdev, &checked_seg);
  398. DPRINTF(CLEAN, ("%s: run finished error %d\n", __func__,
  399. error));
  400. }
  401. DPRINTF(CLEAN, ("%s: exiting\n", __func__));
  402. kthread_exit();
  403. }
  404. static int
  405. nandfs_cleaner_clean_segments(struct nandfs_device *nffsdev,
  406. struct nandfs_vinfo *vinfo, uint32_t nvinfo,
  407. struct nandfs_period *pd, uint32_t npd,
  408. struct nandfs_bdesc *bdesc, uint32_t nbdesc,
  409. uint64_t *segments, uint32_t nsegs)
  410. {
  411. struct nandfs_node *gc;
  412. struct buf *bp;
  413. uint32_t i;
  414. int error = 0;
  415. gc = nffsdev->nd_gc_node;
  416. DPRINTF(CLEAN, ("%s: enter\n", __func__));
  417. VOP_LOCK(NTOV(gc), LK_EXCLUSIVE);
  418. for (i = 0; i < nvinfo; i++) {
  419. if (!vinfo[i].nvi_alive)
  420. continue;
  421. DPRINTF(CLEAN, ("%s: read vblknr:%#jx blk:%#jx\n",
  422. __func__, (uintmax_t)vinfo[i].nvi_vblocknr,
  423. (uintmax_t)vinfo[i].nvi_blocknr));
  424. error = nandfs_bread(nffsdev->nd_gc_node, vinfo[i].nvi_blocknr,
  425. NULL, 0, &bp);
  426. if (error) {
  427. nandfs_error("%s:%d", __FILE__, __LINE__);
  428. VOP_UNLOCK(NTOV(gc), 0);
  429. goto out;
  430. }
  431. nandfs_vblk_set(bp, vinfo[i].nvi_vblocknr);
  432. nandfs_buf_set(bp, NANDFS_VBLK_ASSIGNED);
  433. nandfs_dirty_buf(bp, 1);
  434. }
  435. VOP_UNLOCK(NTOV(gc), 0);
  436. /* Delete checkpoints */
  437. for (i = 0; i < npd; i++) {
  438. DPRINTF(CLEAN, ("delete checkpoint: %jx\n",
  439. (uintmax_t)pd[i].p_start));
  440. error = nandfs_delete_cp(nffsdev->nd_cp_node, pd[i].p_start,
  441. pd[i].p_end);
  442. if (error) {
  443. nandfs_error("%s:%d", __FILE__, __LINE__);
  444. goto out;
  445. }
  446. }
  447. /* Update vblocks */
  448. for (i = 0; i < nvinfo; i++) {
  449. if (vinfo[i].nvi_alive)
  450. continue;
  451. DPRINTF(CLEAN, ("freeing vblknr: %jx\n", vinfo[i].nvi_vblocknr));
  452. error = nandfs_vblock_free(nffsdev, vinfo[i].nvi_vblocknr);
  453. if (error) {
  454. nandfs_error("%s:%d", __FILE__, __LINE__);
  455. goto out;
  456. }
  457. }
  458. error = nandfs_process_bdesc(nffsdev, bdesc, nbdesc);
  459. if (error) {
  460. nandfs_error("%s:%d", __FILE__, __LINE__);
  461. goto out;
  462. }
  463. /* Add segments to clean */
  464. if (nffsdev->nd_free_count) {
  465. nffsdev->nd_free_base = realloc(nffsdev->nd_free_base,
  466. (nffsdev->nd_free_count + nsegs) * sizeof(uint64_t),
  467. M_NANDFSTEMP, M_WAITOK | M_ZERO);
  468. memcpy(&nffsdev->nd_free_base[nffsdev->nd_free_count], segments,
  469. nsegs * sizeof(uint64_t));
  470. nffsdev->nd_free_count += nsegs;
  471. } else {
  472. nffsdev->nd_free_base = malloc(nsegs * sizeof(uint64_t),
  473. M_NANDFSTEMP, M_WAITOK|M_ZERO);
  474. memcpy(nffsdev->nd_free_base, segments,
  475. nsegs * sizeof(uint64_t));
  476. nffsdev->nd_free_count = nsegs;
  477. }
  478. out:
  479. DPRINTF(CLEAN, ("%s: exit error %d\n", __func__, error));
  480. return (error);
  481. }
  482. static int
  483. nandfs_process_bdesc(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd,
  484. uint64_t nmembs)
  485. {
  486. struct nandfs_node *dat_node;
  487. struct buf *bp;
  488. uint64_t i;
  489. int error;
  490. dat_node = nffsdev->nd_dat_node;
  491. VOP_LOCK(NTOV(dat_node), LK_EXCLUSIVE);
  492. for (i = 0; i < nmembs; i++) {
  493. if (!bd[i].bd_alive)
  494. continue;
  495. DPRINTF(CLEAN, ("%s: idx %jx offset %jx\n",
  496. __func__, i, bd[i].bd_offset));
  497. if (bd[i].bd_level) {
  498. error = nandfs_bread_meta(dat_node, bd[i].bd_offset,
  499. NULL, 0, &bp);
  500. if (error) {
  501. nandfs_error("%s: cannot read dat node "
  502. "level:%d\n", __func__, bd[i].bd_level);
  503. brelse(bp);
  504. VOP_UNLOCK(NTOV(dat_node), 0);
  505. return (error);
  506. }
  507. nandfs_dirty_buf_meta(bp, 1);
  508. nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1);
  509. } else {
  510. error = nandfs_bread(dat_node, bd[i].bd_offset, NULL,
  511. 0, &bp);
  512. if (error) {
  513. nandfs_error("%s: cannot read dat node\n",
  514. __func__);
  515. brelse(bp);
  516. VOP_UNLOCK(NTOV(dat_node), 0);
  517. return (error);
  518. }
  519. nandfs_dirty_buf(bp, 1);
  520. }
  521. DPRINTF(CLEAN, ("%s: bp: %p\n", __func__, bp));
  522. }
  523. VOP_UNLOCK(NTOV(dat_node), 0);
  524. return (0);
  525. }