xref: /trueos/sys/fs/nandfs/nandfs_cleaner.c (revision ede42824618710ffa9ac08c805d8bf39bd5661ce)
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 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/conf.h>
33 #include <sys/kernel.h>
34 #include <sys/lock.h>
35 #include <sys/malloc.h>
36 #include <sys/mount.h>
37 #include <sys/mutex.h>
38 #include <sys/buf.h>
39 #include <sys/namei.h>
40 #include <sys/vnode.h>
41 #include <sys/bio.h>
42 
43 #include <fs/nandfs/nandfs_mount.h>
44 #include <fs/nandfs/nandfs.h>
45 #include <fs/nandfs/nandfs_subr.h>
46 
47 #define	NANDFS_CLEANER_KILL	1
48 
49 static void nandfs_cleaner(struct nandfs_device *);
50 static int nandfs_cleaner_clean_segments(struct nandfs_device *,
51     struct nandfs_vinfo *, uint32_t, struct nandfs_period *, uint32_t,
52     struct nandfs_bdesc *, uint32_t, uint64_t *, uint32_t);
53 
54 static int
55 nandfs_process_bdesc(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd,
56     uint64_t nmembs);
57 
58 static void
nandfs_wakeup_wait_cleaner(struct nandfs_device * fsdev,int reason)59 nandfs_wakeup_wait_cleaner(struct nandfs_device *fsdev, int reason)
60 {
61 
62 	mtx_lock(&fsdev->nd_clean_mtx);
63 	if (reason == NANDFS_CLEANER_KILL)
64 		fsdev->nd_cleaner_exit = 1;
65 	if (fsdev->nd_cleaning == 0) {
66 		fsdev->nd_cleaning = 1;
67 		wakeup(&fsdev->nd_cleaning);
68 	}
69 	cv_wait(&fsdev->nd_clean_cv, &fsdev->nd_clean_mtx);
70 	mtx_unlock(&fsdev->nd_clean_mtx);
71 }
72 
73 int
nandfs_start_cleaner(struct nandfs_device * fsdev)74 nandfs_start_cleaner(struct nandfs_device *fsdev)
75 {
76 	int error;
77 
78 	MPASS(fsdev->nd_cleaner == NULL);
79 
80 	fsdev->nd_cleaner_exit = 0;
81 
82 	error = kthread_add((void(*)(void *))nandfs_cleaner, fsdev, NULL,
83 	    &fsdev->nd_cleaner, 0, 0, "nandfs_cleaner");
84 	if (error)
85 		printf("nandfs: could not start cleaner: %d\n", error);
86 
87 	return (error);
88 }
89 
90 int
nandfs_stop_cleaner(struct nandfs_device * fsdev)91 nandfs_stop_cleaner(struct nandfs_device *fsdev)
92 {
93 
94 	MPASS(fsdev->nd_cleaner != NULL);
95 	nandfs_wakeup_wait_cleaner(fsdev, NANDFS_CLEANER_KILL);
96 	fsdev->nd_cleaner = NULL;
97 
98 	DPRINTF(CLEAN, ("cleaner stopped\n"));
99 	return (0);
100 }
101 
102 static int
nandfs_cleaner_finished(struct nandfs_device * fsdev)103 nandfs_cleaner_finished(struct nandfs_device *fsdev)
104 {
105 	int exit;
106 
107 	mtx_lock(&fsdev->nd_clean_mtx);
108 	fsdev->nd_cleaning = 0;
109 	if (!fsdev->nd_cleaner_exit) {
110 		DPRINTF(CLEAN, ("%s: sleep\n", __func__));
111 		msleep(&fsdev->nd_cleaning, &fsdev->nd_clean_mtx, PRIBIO, "-",
112 		    hz * nandfs_cleaner_interval);
113 	}
114 	exit = fsdev->nd_cleaner_exit;
115 	cv_broadcast(&fsdev->nd_clean_cv);
116 	mtx_unlock(&fsdev->nd_clean_mtx);
117 	if (exit) {
118 		DPRINTF(CLEAN, ("%s: no longer active\n", __func__));
119 		return (1);
120 	}
121 
122 	return (0);
123 }
124 
125 static void
print_suinfo(struct nandfs_suinfo * suinfo,int nsegs)126 print_suinfo(struct nandfs_suinfo *suinfo, int nsegs)
127 {
128 	int i;
129 
130 	for (i = 0; i < nsegs; i++) {
131 		DPRINTF(CLEAN, ("%jx  %jd  %c%c%c  %10u\n",
132 		    suinfo[i].nsi_num, suinfo[i].nsi_lastmod,
133 		    (suinfo[i].nsi_flags &
134 		    (NANDFS_SEGMENT_USAGE_ACTIVE) ? 'a' : '-'),
135 		    (suinfo[i].nsi_flags &
136 		    (NANDFS_SEGMENT_USAGE_DIRTY) ? 'd' : '-'),
137 		    (suinfo[i].nsi_flags &
138 		    (NANDFS_SEGMENT_USAGE_ERROR) ? 'e' : '-'),
139 		    suinfo[i].nsi_blocks));
140 	}
141 }
142 
143 static int
nandfs_cleaner_vblock_is_alive(struct nandfs_device * fsdev,struct nandfs_vinfo * vinfo,struct nandfs_cpinfo * cp,uint32_t ncps)144 nandfs_cleaner_vblock_is_alive(struct nandfs_device *fsdev,
145     struct nandfs_vinfo *vinfo, struct nandfs_cpinfo *cp, uint32_t ncps)
146 {
147 	int64_t idx, min, max;
148 
149 	if (vinfo->nvi_end >= fsdev->nd_last_cno)
150 		return (1);
151 
152 	if (ncps == 0)
153 		return (0);
154 
155 	if (vinfo->nvi_end < cp[0].nci_cno ||
156 	    vinfo->nvi_start > cp[ncps - 1].nci_cno)
157 		return (0);
158 
159 	idx = min = 0;
160 	max = ncps - 1;
161 	while (min <= max) {
162 		idx = (min + max) / 2;
163 		if (vinfo->nvi_start == cp[idx].nci_cno)
164 			return (1);
165 		if (vinfo->nvi_start < cp[idx].nci_cno)
166 			max = idx - 1;
167 		else
168 			min = idx + 1;
169 	}
170 
171 	return (vinfo->nvi_end >= cp[idx].nci_cno);
172 }
173 
174 static void
nandfs_cleaner_vinfo_mark_alive(struct nandfs_device * fsdev,struct nandfs_vinfo * vinfo,uint32_t nmembs,struct nandfs_cpinfo * cp,uint32_t ncps)175 nandfs_cleaner_vinfo_mark_alive(struct nandfs_device *fsdev,
176     struct nandfs_vinfo *vinfo, uint32_t nmembs, struct nandfs_cpinfo *cp,
177     uint32_t ncps)
178 {
179 	uint32_t i;
180 
181 	for (i = 0; i < nmembs; i++)
182 		vinfo[i].nvi_alive =
183 		    nandfs_cleaner_vblock_is_alive(fsdev, &vinfo[i], cp, ncps);
184 }
185 
186 static int
nandfs_cleaner_bdesc_is_alive(struct nandfs_device * fsdev,struct nandfs_bdesc * bdesc)187 nandfs_cleaner_bdesc_is_alive(struct nandfs_device *fsdev,
188     struct nandfs_bdesc *bdesc)
189 {
190 	int alive;
191 
192 	alive = bdesc->bd_oblocknr == bdesc->bd_blocknr;
193 	if (!alive)
194 		MPASS(abs(bdesc->bd_oblocknr - bdesc->bd_blocknr) > 2);
195 
196 	return (alive);
197 }
198 
199 static void
nandfs_cleaner_bdesc_mark_alive(struct nandfs_device * fsdev,struct nandfs_bdesc * bdesc,uint32_t nmembs)200 nandfs_cleaner_bdesc_mark_alive(struct nandfs_device *fsdev,
201     struct nandfs_bdesc *bdesc, uint32_t nmembs)
202 {
203 	uint32_t i;
204 
205 	for (i = 0; i < nmembs; i++)
206 		bdesc[i].bd_alive = nandfs_cleaner_bdesc_is_alive(fsdev,
207 		    &bdesc[i]);
208 }
209 
210 static void
nandfs_cleaner_iterate_psegment(struct nandfs_device * fsdev,struct nandfs_segment_summary * segsum,union nandfs_binfo * binfo,nandfs_daddr_t blk,struct nandfs_vinfo ** vipp,struct nandfs_bdesc ** bdpp)211 nandfs_cleaner_iterate_psegment(struct nandfs_device *fsdev,
212     struct nandfs_segment_summary *segsum, union nandfs_binfo *binfo,
213     nandfs_daddr_t blk, struct nandfs_vinfo **vipp, struct nandfs_bdesc **bdpp)
214 {
215 	int i;
216 
217 	DPRINTF(CLEAN, ("%s nbinfos %x\n", __func__, segsum->ss_nbinfos));
218 	for (i = 0; i < segsum->ss_nbinfos; i++) {
219 		if (binfo[i].bi_v.bi_ino == NANDFS_DAT_INO) {
220 			(*bdpp)->bd_oblocknr = blk + segsum->ss_nblocks -
221 			    segsum->ss_nbinfos + i;
222 			/*
223 			 * XXX Hack
224 			 */
225 			if (segsum->ss_flags & NANDFS_SS_SR)
226 				(*bdpp)->bd_oblocknr--;
227 			(*bdpp)->bd_level = binfo[i].bi_dat.bi_level;
228 			(*bdpp)->bd_offset = binfo[i].bi_dat.bi_blkoff;
229 			(*bdpp)++;
230 		} else {
231 			(*vipp)->nvi_ino = binfo[i].bi_v.bi_ino;
232 			(*vipp)->nvi_vblocknr = binfo[i].bi_v.bi_vblocknr;
233 			(*vipp)++;
234 		}
235 	}
236 }
237 
238 static int
nandfs_cleaner_iterate_segment(struct nandfs_device * fsdev,uint64_t segno,struct nandfs_vinfo ** vipp,struct nandfs_bdesc ** bdpp,int * select)239 nandfs_cleaner_iterate_segment(struct nandfs_device *fsdev, uint64_t segno,
240     struct nandfs_vinfo **vipp, struct nandfs_bdesc **bdpp, int *select)
241 {
242 	struct nandfs_segment_summary *segsum;
243 	union nandfs_binfo *binfo;
244 	struct buf *bp;
245 	uint32_t nblocks;
246 	nandfs_daddr_t curr, start, end;
247 	int error = 0;
248 
249 	nandfs_get_segment_range(fsdev, segno, &start, &end);
250 
251 	DPRINTF(CLEAN, ("%s: segno %jx start %jx end %jx\n", __func__, segno,
252 	    start, end));
253 
254 	*select = 0;
255 
256 	for (curr = start; curr < end; curr += nblocks) {
257 		error = nandfs_dev_bread(fsdev, curr, NOCRED, 0, &bp);
258 		if (error) {
259 			brelse(bp);
260 			nandfs_error("%s: couldn't load segment summary of %jx: %d\n",
261 			    __func__, segno, error);
262 			return (error);
263 		}
264 
265 		segsum = (struct nandfs_segment_summary *)bp->b_data;
266 		binfo = (union nandfs_binfo *)(bp->b_data + segsum->ss_bytes);
267 
268 		if (!nandfs_segsum_valid(segsum)) {
269 			brelse(bp);
270 			nandfs_error("nandfs: invalid summary of segment %jx\n", segno);
271 			return (error);
272 		}
273 
274 		DPRINTF(CLEAN, ("%s: %jx magic %x bytes %x nblocks %x nbinfos "
275 		    "%x\n", __func__, segno, segsum->ss_magic, segsum->ss_bytes,
276 		    segsum->ss_nblocks, segsum->ss_nbinfos));
277 
278 		nandfs_cleaner_iterate_psegment(fsdev, segsum, binfo, curr,
279 		    vipp, bdpp);
280 		nblocks = segsum->ss_nblocks;
281 		brelse(bp);
282 	}
283 
284 	if (error == 0)
285 		*select = 1;
286 
287 	return (error);
288 }
289 
290 static int
nandfs_cleaner_choose_segment(struct nandfs_device * fsdev,uint64_t ** segpp,uint64_t nsegs,uint64_t * rseg)291 nandfs_cleaner_choose_segment(struct nandfs_device *fsdev, uint64_t **segpp,
292     uint64_t nsegs, uint64_t *rseg)
293 {
294 	struct nandfs_suinfo *suinfo;
295 	uint64_t i, ssegs;
296 	int error;
297 
298 	suinfo = malloc(sizeof(*suinfo) * nsegs, M_NANDFSTEMP,
299 	    M_ZERO | M_WAITOK);
300 
301 	if (*rseg >= fsdev->nd_fsdata.f_nsegments)
302 		*rseg = 0;
303 
304 retry:
305 	error = nandfs_get_segment_info_filter(fsdev, suinfo, nsegs, *rseg,
306 	    &ssegs, NANDFS_SEGMENT_USAGE_DIRTY,
307 	    NANDFS_SEGMENT_USAGE_ACTIVE | NANDFS_SEGMENT_USAGE_ERROR |
308 	    NANDFS_SEGMENT_USAGE_GC);
309 	if (error) {
310 		nandfs_error("%s:%d", __FILE__, __LINE__);
311 		goto out;
312 	}
313 	if (ssegs == 0 && *rseg != 0) {
314 		*rseg = 0;
315 		goto retry;
316 	}
317 	if (ssegs > 0) {
318 		print_suinfo(suinfo, ssegs);
319 
320 		for (i = 0; i < ssegs; i++) {
321 			(**segpp) = suinfo[i].nsi_num;
322 			(*segpp)++;
323 		}
324 		*rseg = suinfo[i - 1].nsi_num + 1;
325 	}
326 
327 out:
328 	free(suinfo, M_NANDFSTEMP);
329 	return (error);
330 }
331 
332 static int
nandfs_cleaner_body(struct nandfs_device * fsdev,uint64_t * rseg)333 nandfs_cleaner_body(struct nandfs_device *fsdev, uint64_t *rseg)
334 {
335 	struct nandfs_vinfo *vinfo, *vip, *vipi;
336 	struct nandfs_bdesc *bdesc, *bdp, *bdpi;
337 	struct nandfs_cpstat cpstat;
338 	struct nandfs_cpinfo *cpinfo = NULL;
339 	uint64_t *segnums, *segp;
340 	int select, selected;
341 	int error = 0;
342 	int nsegs;
343 	int i;
344 
345 	nsegs = nandfs_cleaner_segments;
346 
347 	vip = vinfo = malloc(sizeof(*vinfo) *
348 	    fsdev->nd_fsdata.f_blocks_per_segment * nsegs, M_NANDFSTEMP,
349 	    M_ZERO | M_WAITOK);
350 	bdp = bdesc = malloc(sizeof(*bdesc) *
351 	    fsdev->nd_fsdata.f_blocks_per_segment * nsegs, M_NANDFSTEMP,
352 	    M_ZERO | M_WAITOK);
353 	segp = segnums = malloc(sizeof(*segnums) * nsegs, M_NANDFSTEMP,
354 	    M_WAITOK);
355 
356 	error = nandfs_cleaner_choose_segment(fsdev, &segp, nsegs, rseg);
357 	if (error) {
358 		nandfs_error("%s:%d", __FILE__, __LINE__);
359 		goto out;
360 	}
361 
362 	if (segnums == segp)
363 		goto out;
364 
365 	selected = 0;
366 	for (i = 0; i < segp - segnums; i++) {
367 		error = nandfs_cleaner_iterate_segment(fsdev, segnums[i], &vip,
368 		    &bdp, &select);
369 		if (error) {
370 			/*
371 			 * XXX deselect (see below)?
372 			 */
373 			goto out;
374 		}
375 		if (!select)
376 			segnums[i] = NANDFS_NOSEGMENT;
377 		else {
378 			error = nandfs_markgc_segment(fsdev, segnums[i]);
379 			if (error) {
380 				nandfs_error("%s:%d\n", __FILE__, __LINE__);
381 				goto out;
382 			}
383 			selected++;
384 		}
385 	}
386 
387 	if (selected == 0) {
388 		MPASS(vinfo == vip);
389 		MPASS(bdesc == bdp);
390 		goto out;
391 	}
392 
393 	error = nandfs_get_cpstat(fsdev->nd_cp_node, &cpstat);
394 	if (error) {
395 		nandfs_error("%s:%d\n", __FILE__, __LINE__);
396 		goto out;
397 	}
398 
399 	if (cpstat.ncp_nss != 0) {
400 		cpinfo = malloc(sizeof(struct nandfs_cpinfo) * cpstat.ncp_nss,
401 		    M_NANDFSTEMP, M_WAITOK);
402 		error = nandfs_get_cpinfo(fsdev->nd_cp_node, 1, NANDFS_SNAPSHOT,
403 		    cpinfo, cpstat.ncp_nss, NULL);
404 		if (error) {
405 			nandfs_error("%s:%d\n", __FILE__, __LINE__);
406 			goto out_locked;
407 		}
408 	}
409 
410 	NANDFS_WRITELOCK(fsdev);
411 	DPRINTF(CLEAN, ("%s: got lock\n", __func__));
412 
413 	error = nandfs_get_dat_vinfo(fsdev, vinfo, vip - vinfo);
414 	if (error) {
415 		nandfs_error("%s:%d\n", __FILE__, __LINE__);
416 		goto out_locked;
417 	}
418 
419 	nandfs_cleaner_vinfo_mark_alive(fsdev, vinfo, vip - vinfo, cpinfo,
420 	    cpstat.ncp_nss);
421 
422 	error = nandfs_get_dat_bdescs(fsdev, bdesc, bdp - bdesc);
423 	if (error) {
424 		nandfs_error("%s:%d\n", __FILE__, __LINE__);
425 		goto out_locked;
426 	}
427 
428 	nandfs_cleaner_bdesc_mark_alive(fsdev, bdesc, bdp - bdesc);
429 
430 	DPRINTF(CLEAN, ("got:\n"));
431 	for (vipi = vinfo; vipi < vip; vipi++) {
432 		DPRINTF(CLEAN, ("v ino %jx vblocknr %jx start %jx end %jx "
433 		    "alive %d\n", vipi->nvi_ino, vipi->nvi_vblocknr,
434 		    vipi->nvi_start, vipi->nvi_end, vipi->nvi_alive));
435 	}
436 	for (bdpi = bdesc; bdpi < bdp; bdpi++) {
437 		DPRINTF(CLEAN, ("b oblocknr %jx blocknr %jx offset %jx "
438 		    "alive %d\n", bdpi->bd_oblocknr, bdpi->bd_blocknr,
439 		    bdpi->bd_offset, bdpi->bd_alive));
440 	}
441 	DPRINTF(CLEAN, ("end list\n"));
442 
443 	error = nandfs_cleaner_clean_segments(fsdev, vinfo, vip - vinfo, NULL,
444 	    0, bdesc, bdp - bdesc, segnums, segp - segnums);
445 	if (error)
446 		nandfs_error("%s:%d\n", __FILE__, __LINE__);
447 
448 out_locked:
449 	NANDFS_WRITEUNLOCK(fsdev);
450 out:
451 	free(cpinfo, M_NANDFSTEMP);
452 	free(segnums, M_NANDFSTEMP);
453 	free(bdesc, M_NANDFSTEMP);
454 	free(vinfo, M_NANDFSTEMP);
455 
456 	return (error);
457 }
458 
459 static void
nandfs_cleaner(struct nandfs_device * fsdev)460 nandfs_cleaner(struct nandfs_device *fsdev)
461 {
462 	uint64_t checked_seg = 0;
463 	int error;
464 
465 	while (!nandfs_cleaner_finished(fsdev)) {
466 		if (!nandfs_cleaner_enable || rebooting)
467 			continue;
468 
469 		DPRINTF(CLEAN, ("%s: run started\n", __func__));
470 
471 		fsdev->nd_cleaning = 1;
472 
473 		error = nandfs_cleaner_body(fsdev, &checked_seg);
474 
475 		DPRINTF(CLEAN, ("%s: run finished error %d\n", __func__,
476 		    error));
477 	}
478 
479 	DPRINTF(CLEAN, ("%s: exiting\n", __func__));
480 	kthread_exit();
481 }
482 
483 static int
nandfs_cleaner_clean_segments(struct nandfs_device * nffsdev,struct nandfs_vinfo * vinfo,uint32_t nvinfo,struct nandfs_period * pd,uint32_t npd,struct nandfs_bdesc * bdesc,uint32_t nbdesc,uint64_t * segments,uint32_t nsegs)484 nandfs_cleaner_clean_segments(struct nandfs_device *nffsdev,
485     struct nandfs_vinfo *vinfo, uint32_t nvinfo,
486     struct nandfs_period *pd, uint32_t npd,
487     struct nandfs_bdesc *bdesc, uint32_t nbdesc,
488     uint64_t *segments, uint32_t nsegs)
489 {
490 	struct nandfs_node *gc;
491 	struct buf *bp;
492 	uint32_t i;
493 	int error = 0;
494 
495 	gc = nffsdev->nd_gc_node;
496 
497 	DPRINTF(CLEAN, ("%s: enter\n", __func__));
498 
499 	VOP_LOCK(NTOV(gc), LK_EXCLUSIVE);
500 	for (i = 0; i < nvinfo; i++) {
501 		if (!vinfo[i].nvi_alive)
502 			continue;
503 		DPRINTF(CLEAN, ("%s: read vblknr:%#jx blk:%#jx\n",
504 		    __func__, (uintmax_t)vinfo[i].nvi_vblocknr,
505 		    (uintmax_t)vinfo[i].nvi_blocknr));
506 		error = nandfs_bread(nffsdev->nd_gc_node, vinfo[i].nvi_blocknr,
507 		    NULL, 0, &bp);
508 		if (error) {
509 			nandfs_error("%s:%d", __FILE__, __LINE__);
510 			VOP_UNLOCK(NTOV(gc), 0);
511 			goto out;
512 		}
513 		nandfs_vblk_set(bp, vinfo[i].nvi_vblocknr);
514 		nandfs_buf_set(bp, NANDFS_VBLK_ASSIGNED);
515 		nandfs_dirty_buf(bp, 1);
516 	}
517 	VOP_UNLOCK(NTOV(gc), 0);
518 
519 	/* Delete checkpoints */
520 	for (i = 0; i < npd; i++) {
521 		DPRINTF(CLEAN, ("delete checkpoint: %jx\n",
522 		    (uintmax_t)pd[i].p_start));
523 		error = nandfs_delete_cp(nffsdev->nd_cp_node, pd[i].p_start,
524 		    pd[i].p_end);
525 		if (error) {
526 			nandfs_error("%s:%d", __FILE__, __LINE__);
527 			goto out;
528 		}
529 	}
530 
531 	/* Update vblocks */
532 	for (i = 0; i < nvinfo; i++) {
533 		if (vinfo[i].nvi_alive)
534 			continue;
535 		DPRINTF(CLEAN, ("freeing vblknr: %jx\n", vinfo[i].nvi_vblocknr));
536 		error = nandfs_vblock_free(nffsdev, vinfo[i].nvi_vblocknr);
537 		if (error) {
538 			nandfs_error("%s:%d", __FILE__, __LINE__);
539 			goto out;
540 		}
541 	}
542 
543 	error = nandfs_process_bdesc(nffsdev, bdesc, nbdesc);
544 	if (error) {
545 		nandfs_error("%s:%d", __FILE__, __LINE__);
546 		goto out;
547 	}
548 
549 	/* Add segments to clean */
550 	if (nffsdev->nd_free_count) {
551 		nffsdev->nd_free_base = realloc(nffsdev->nd_free_base,
552 		    (nffsdev->nd_free_count + nsegs) * sizeof(uint64_t),
553 		    M_NANDFSTEMP, M_WAITOK | M_ZERO);
554 		memcpy(&nffsdev->nd_free_base[nffsdev->nd_free_count], segments,
555 		    nsegs * sizeof(uint64_t));
556 		nffsdev->nd_free_count += nsegs;
557 	} else {
558 		nffsdev->nd_free_base = malloc(nsegs * sizeof(uint64_t),
559 		    M_NANDFSTEMP, M_WAITOK|M_ZERO);
560 		memcpy(nffsdev->nd_free_base, segments,
561 		    nsegs * sizeof(uint64_t));
562 		nffsdev->nd_free_count = nsegs;
563 	}
564 
565 out:
566 
567 	DPRINTF(CLEAN, ("%s: exit error %d\n", __func__, error));
568 
569 	return (error);
570 }
571 
572 static int
nandfs_process_bdesc(struct nandfs_device * nffsdev,struct nandfs_bdesc * bd,uint64_t nmembs)573 nandfs_process_bdesc(struct nandfs_device *nffsdev, struct nandfs_bdesc *bd,
574     uint64_t nmembs)
575 {
576 	struct nandfs_node *dat_node;
577 	struct buf *bp;
578 	uint64_t i;
579 	int error;
580 
581 	dat_node = nffsdev->nd_dat_node;
582 
583 	VOP_LOCK(NTOV(dat_node), LK_EXCLUSIVE);
584 
585 	for (i = 0; i < nmembs; i++) {
586 		if (!bd[i].bd_alive)
587 			continue;
588 		DPRINTF(CLEAN, ("%s: idx %jx offset %jx\n",
589 		    __func__, i, bd[i].bd_offset));
590 		if (bd[i].bd_level) {
591 			error = nandfs_bread_meta(dat_node, bd[i].bd_offset,
592 			    NULL, 0, &bp);
593 			if (error) {
594 				nandfs_error("%s: cannot read dat node "
595 				    "level:%d\n", __func__, bd[i].bd_level);
596 				brelse(bp);
597 				VOP_UNLOCK(NTOV(dat_node), 0);
598 				return (error);
599 			}
600 			nandfs_dirty_buf_meta(bp, 1);
601 			nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1);
602 		} else {
603 			error = nandfs_bread(dat_node, bd[i].bd_offset, NULL,
604 			    0, &bp);
605 			if (error) {
606 				nandfs_error("%s: cannot read dat node\n",
607 				    __func__);
608 				brelse(bp);
609 				VOP_UNLOCK(NTOV(dat_node), 0);
610 				return (error);
611 			}
612 			nandfs_dirty_buf(bp, 1);
613 		}
614 		DPRINTF(CLEAN, ("%s: bp: %p\n", __func__, bp));
615 	}
616 
617 	VOP_UNLOCK(NTOV(dat_node), 0);
618 
619 	return (0);
620 }
621