1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2010-2012 Semihalf.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include "opt_ddb.h"
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/conf.h>
37 #include <sys/gsb_crc32.h>
38 #include <sys/kernel.h>
39 #include <sys/lock.h>
40 #include <sys/malloc.h>
41 #include <sys/mount.h>
42 #include <sys/mutex.h>
43 #include <sys/namei.h>
44 #include <sys/rwlock.h>
45 #include <sys/sysctl.h>
46 #include <sys/vnode.h>
47 #include <sys/buf.h>
48 #include <sys/bio.h>
49 #include <sys/libkern.h>
50
51 #include <ddb/ddb.h>
52
53 #include <vm/vm.h>
54 #include <vm/vm_param.h>
55 #include <vm/vm_kern.h>
56 #include <vm/vm_page.h>
57
58 #include <geom/geom.h>
59 #include <geom/geom_vfs.h>
60
61 #include <fs/nandfs/nandfs_mount.h>
62 #include <fs/nandfs/nandfs.h>
63 #include <fs/nandfs/nandfs_subr.h>
64
65 static int
66 nandfs_new_segment(struct nandfs_device *fsdev)
67 {
68 int error = 0;
69 uint64_t new;
70
71 error = nandfs_alloc_segment(fsdev, &new);
72 if (!error) {
73 fsdev->nd_seg_num = fsdev->nd_next_seg_num;
74 fsdev->nd_next_seg_num = new;
75 }
76 DPRINTF(SYNC, ("%s: new segment %jx next %jx error %d\n",
77 __func__, (uintmax_t)fsdev->nd_seg_num, (uintmax_t)new, error));
78 if (error)
79 nandfs_error("%s: cannot create segment error %d\n",
80 __func__, error);
81
82 return (error);
83 }
84
85 static int
86 create_segment(struct nandfs_seginfo *seginfo)
87 {
88 struct nandfs_segment *seg;
89 struct nandfs_device *fsdev;
90 struct nandfs_segment *prev;
91 struct buf *bp;
92 uint64_t start_block, curr;
93 uint32_t blks_per_seg, nblocks;
94 int error;
95
96 fsdev = seginfo->fsdev;
97 prev = seginfo->curseg;
98 blks_per_seg = fsdev->nd_fsdata.f_blocks_per_segment;
99 nblocks = fsdev->nd_last_segsum.ss_nblocks;
100
101 if (!prev) {
102 vfs_timestamp(&fsdev->nd_ts);
103 /* Touch current segment */
104 error = nandfs_touch_segment(fsdev, fsdev->nd_seg_num);
105 if (error) {
106 nandfs_error("%s: cannot preallocate segment %jx\n",
107 __func__, fsdev->nd_seg_num);
108 return (error);
109 }
110 error = nandfs_touch_segment(fsdev, 0);
111 if (error) {
112 nandfs_error("%s: cannot dirty block with segment 0\n",
113 __func__);
114 return (error);
115 }
116 start_block = fsdev->nd_last_pseg + (uint64_t)nblocks;
117 /*
118 * XXX Hack
119 */
120 if (blks_per_seg - (start_block % blks_per_seg) - 1 == 0)
121 start_block++;
122 curr = nandfs_get_segnum_of_block(fsdev, start_block);
123 /* Allocate new segment if last one is full */
124 if (fsdev->nd_seg_num != curr) {
125 error = nandfs_new_segment(fsdev);
126 if (error) {
127 nandfs_error("%s: cannot create new segment\n",
128 __func__);
129 return (error);
130 }
131 /*
132 * XXX Hack
133 */
134 nandfs_get_segment_range(fsdev, fsdev->nd_seg_num, &start_block, NULL);
135 }
136 } else {
137 nandfs_get_segment_range(fsdev, fsdev->nd_next_seg_num,
138 &start_block, NULL);
139
140 /* Touch current segment and allocate and touch new one */
141 error = nandfs_new_segment(fsdev);
142 if (error) {
143 nandfs_error("%s: cannot create next segment\n",
144 __func__);
145 return (error);
146 }
147
148 /* Reiterate in case new buf is dirty */
149 seginfo->reiterate = 1;
150 }
151
152 /* Allocate and initialize nandfs_segment structure */
153 seg = malloc(sizeof(*seg), M_DEVBUF, M_WAITOK|M_ZERO);
154 TAILQ_INIT(&seg->segsum);
155 TAILQ_INIT(&seg->data);
156 seg->fsdev = fsdev;
157 seg->start_block = start_block;
158 seg->num_blocks = blks_per_seg - (start_block % blks_per_seg) - 1;
159 seg->seg_num = fsdev->nd_seg_num;
160 seg->seg_next = fsdev->nd_next_seg_num;
161 seg->segsum_blocks = 1;
162 seg->bytes_left = fsdev->nd_blocksize -
163 sizeof(struct nandfs_segment_summary);
164 seg->segsum_bytes = sizeof(struct nandfs_segment_summary);
165
166 /* Allocate buffer for segment summary */
167 bp = getblk(fsdev->nd_devvp, nandfs_block_to_dblock(fsdev,
168 seg->start_block), fsdev->nd_blocksize, 0, 0, 0);
169 bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
170 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
171 bp->b_flags |= B_MANAGED;
172
173 /* Add buffer to segment */
174 TAILQ_INSERT_TAIL(&seg->segsum, bp, b_cluster.cluster_entry);
175 seg->current_off = bp->b_data + sizeof(struct nandfs_segment_summary);
176
177 DPRINTF(SYNC, ("%s: seg %p : initial settings: start %#jx size :%#x\n",
178 __func__, seg, (uintmax_t)seg->start_block, seg->num_blocks));
179 DPRINTF(SYNC, ("%s: seg->seg_num %#jx cno %#jx next %#jx\n", __func__,
180 (uintmax_t)seg->seg_num, (uintmax_t)(fsdev->nd_last_cno + 1),
181 (uintmax_t)seg->seg_next));
182
183 if (!prev)
184 LIST_INSERT_HEAD(&seginfo->seg_list, seg, seg_link);
185 else
186 LIST_INSERT_AFTER(prev, seg, seg_link);
187
188 seginfo->curseg = seg;
189
190 return (0);
191 }
192
193 static int
194 delete_segment(struct nandfs_seginfo *seginfo)
195 {
196 struct nandfs_segment *seg, *tseg;
197 struct buf *bp, *tbp;
198
199 LIST_FOREACH_SAFE(seg, &seginfo->seg_list, seg_link, tseg) {
200 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry,
201 tbp) {
202 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
203 bp->b_flags &= ~B_MANAGED;
204 brelse(bp);
205 }
206
207 LIST_REMOVE(seg, seg_link);
208 free(seg, M_DEVBUF);
209 }
210
211 return (0);
212 }
213
214 static int
215 create_seginfo(struct nandfs_device *fsdev, struct nandfs_seginfo **seginfo)
216 {
217 struct nandfs_seginfo *info;
218
219 info = malloc(sizeof(*info), M_DEVBUF, M_WAITOK);
220
221 LIST_INIT(&info->seg_list);
222 info->fsdev = fsdev;
223 info->curseg = NULL;
224 info->blocks = 0;
225 *seginfo = info;
226 fsdev->nd_seginfo = info;
227 return (0);
228 }
229
230 static int
231 delete_seginfo(struct nandfs_seginfo *seginfo)
232 {
233 struct nandfs_device *nffsdev;
234
235 nffsdev = seginfo->fsdev;
236 delete_segment(seginfo);
237 nffsdev->nd_seginfo = NULL;
238 free(seginfo, M_DEVBUF);
239
240 return (0);
241 }
242
243 static int
244 nandfs_create_superroot_block(struct nandfs_seginfo *seginfo,
245 struct buf **newbp)
246 {
247 struct buf *bp;
248 int error;
249
250 bp = nandfs_geteblk(seginfo->fsdev->nd_blocksize, GB_NOWAIT_BD);
251
252 bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
253 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
254 bp->b_flags |= B_MANAGED;
255
256 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
257 error = create_segment(seginfo);
258 if (error) {
259 brelse(bp);
260 nandfs_error("%s: no segment for superroot\n",
261 __func__);
262 return (error);
263 }
264 }
265
266 TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry);
267
268 seginfo->curseg->nblocks++;
269 seginfo->curseg->num_blocks--;
270 seginfo->blocks++;
271
272 *newbp = bp;
273 return (0);
274 }
275
276 static int
277 nandfs_add_superroot(struct nandfs_seginfo *seginfo)
278 {
279 struct nandfs_device *fsdev;
280 struct nandfs_super_root *sr;
281 struct buf *bp = NULL;
282 uint64_t crc_skip;
283 uint32_t crc_calc;
284 int error;
285
286 fsdev = seginfo->fsdev;
287
288 error = nandfs_create_superroot_block(seginfo, &bp);
289 if (error) {
290 nandfs_error("%s: cannot add superroot\n", __func__);
291 return (error);
292 }
293
294 sr = (struct nandfs_super_root *)bp->b_data;
295 /* Save superroot CRC */
296 sr->sr_bytes = NANDFS_SR_BYTES;
297 sr->sr_flags = 0;
298 sr->sr_nongc_ctime = 0;
299
300 memcpy(&sr->sr_dat, &fsdev->nd_dat_node->nn_inode,
301 sizeof(struct nandfs_inode));
302 memcpy(&sr->sr_cpfile, &fsdev->nd_cp_node->nn_inode,
303 sizeof(struct nandfs_inode));
304 memcpy(&sr->sr_sufile, &fsdev->nd_su_node->nn_inode,
305 sizeof(struct nandfs_inode));
306
307 crc_skip = sizeof(sr->sr_sum);
308 crc_calc = crc32((uint8_t *)sr + crc_skip, NANDFS_SR_BYTES - crc_skip);
309
310 sr->sr_sum = crc_calc;
311
312 bp->b_flags |= B_MANAGED;
313 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
314
315 bp->b_flags &= ~B_INVAL;
316 nandfs_dirty_bufs_increment(fsdev);
317 DPRINTF(SYNC, ("%s: bp:%p\n", __func__, bp));
318
319 return (0);
320 }
321
322 static int
323 nandfs_add_segsum_block(struct nandfs_seginfo *seginfo, struct buf **newbp)
324 {
325 struct nandfs_device *fsdev;
326 nandfs_daddr_t blk;
327 struct buf *bp;
328 int error;
329
330 if (!(seginfo->curseg) || seginfo->curseg->num_blocks <= 1) {
331 error = create_segment(seginfo);
332 if (error) {
333 nandfs_error("%s: error:%d when creating segment\n",
334 __func__, error);
335 return (error);
336 }
337 *newbp = TAILQ_FIRST(&seginfo->curseg->segsum);
338 return (0);
339 }
340
341 fsdev = seginfo->fsdev;
342 blk = nandfs_block_to_dblock(fsdev, seginfo->curseg->start_block +
343 seginfo->curseg->segsum_blocks);
344
345 bp = getblk(fsdev->nd_devvp, blk, fsdev->nd_blocksize, 0, 0, 0);
346
347 bzero(bp->b_data, seginfo->fsdev->nd_blocksize);
348 bp->b_bufobj = &seginfo->fsdev->nd_devvp->v_bufobj;
349 bp->b_flags |= B_MANAGED;
350
351 TAILQ_INSERT_TAIL(&seginfo->curseg->segsum, bp,
352 b_cluster.cluster_entry);
353 seginfo->curseg->num_blocks--;
354
355 seginfo->curseg->segsum_blocks++;
356 seginfo->curseg->bytes_left = seginfo->fsdev->nd_blocksize;
357 seginfo->curseg->current_off = bp->b_data;
358 seginfo->blocks++;
359
360 *newbp = bp;
361
362 DPRINTF(SYNC, ("%s: bp %p\n", __func__, bp));
363
364 return (0);
365 }
366
367 static int
368 nandfs_add_blocks(struct nandfs_seginfo *seginfo, struct nandfs_node *node,
369 struct buf *bp)
370 {
371 union nandfs_binfo *binfo;
372 struct buf *seg_bp;
373 int error;
374
375 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
376 error = create_segment(seginfo);
377 if (error) {
378 nandfs_error("%s: error:%d when creating segment\n",
379 __func__, error);
380 return (error);
381 }
382 }
383
384 if (seginfo->curseg->bytes_left < sizeof(union nandfs_binfo)) {
385 error = nandfs_add_segsum_block(seginfo, &seg_bp);
386 if (error) {
387 nandfs_error("%s: error:%d when adding segsum\n",
388 __func__, error);
389 return (error);
390 }
391 }
392 binfo = (union nandfs_binfo *)seginfo->curseg->current_off;
393
394 if (node->nn_ino != NANDFS_DAT_INO) {
395 binfo->bi_v.bi_blkoff = bp->b_lblkno;
396 binfo->bi_v.bi_ino = node->nn_ino;
397 } else {
398 binfo->bi_dat.bi_blkoff = bp->b_lblkno;
399 binfo->bi_dat.bi_ino = node->nn_ino;
400 if (NANDFS_IS_INDIRECT(bp))
401 binfo->bi_dat.bi_level = 1;
402 else
403 binfo->bi_dat.bi_level = 0;
404 }
405 binfo++;
406
407 seginfo->curseg->bytes_left -= sizeof(union nandfs_binfo);
408 seginfo->curseg->segsum_bytes += sizeof(union nandfs_binfo);
409 seginfo->curseg->current_off = (char *)binfo;
410
411 TAILQ_INSERT_TAIL(&seginfo->curseg->data, bp, b_cluster.cluster_entry);
412
413 seginfo->curseg->nbinfos++;
414 seginfo->curseg->nblocks++;
415 seginfo->curseg->num_blocks--;
416 seginfo->blocks++;
417
418 DPRINTF(SYNC, ("%s: bp (%p) number %x (left %x)\n",
419 __func__, bp, seginfo->curseg->nblocks,
420 seginfo->curseg->num_blocks));
421 return (0);
422 }
423
424 static int
425 nandfs_iterate_dirty_buf(struct vnode *vp, struct nandfs_seginfo *seginfo,
426 uint8_t hold)
427 {
428 struct buf *bp, *tbd;
429 struct bufobj *bo;
430 struct nandfs_node *node;
431 int error;
432
433 node = VTON(vp);
434 bo = &vp->v_bufobj;
435
436 ASSERT_VOP_ELOCKED(vp, __func__);
437
438 /* Iterate dirty data bufs */
439 TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, tbd) {
440 DPRINTF(SYNC, ("%s: vp (%p): bp (%p) with lblkno %jx ino %jx "
441 "add buf\n", __func__, vp, bp, bp->b_lblkno, node->nn_ino));
442
443 if (!(NANDFS_ISGATHERED(bp))) {
444 error = nandfs_bmap_update_dat(node,
445 nandfs_vblk_get(bp), bp);
446 if (error)
447 return (error);
448 NANDFS_GATHER(bp);
449 nandfs_add_blocks(seginfo, node, bp);
450 }
451 }
452
453 return (0);
454 }
455
456 static int
457 nandfs_iterate_system_vnode(struct nandfs_node *node,
458 struct nandfs_seginfo *seginfo)
459 {
460 struct vnode *vp;
461 int nblocks;
462 uint8_t hold = 0;
463
464 if (node->nn_ino != NANDFS_IFILE_INO)
465 hold = 1;
466
467 vp = NTOV(node);
468
469 nblocks = vp->v_bufobj.bo_dirty.bv_cnt;
470 DPRINTF(SYNC, ("%s: vp (%p): nblocks %x ino %jx\n",
471 __func__, vp, nblocks, node->nn_ino));
472
473 if (nblocks)
474 nandfs_iterate_dirty_buf(vp, seginfo, hold);
475
476 return (0);
477 }
478
479 static int
480 nandfs_iterate_dirty_vnodes(struct mount *mp, struct nandfs_seginfo *seginfo)
481 {
482 struct nandfs_node *nandfs_node;
483 struct vnode *vp, *mvp;
484 struct thread *td;
485 struct bufobj *bo;
486 int error, update;
487
488 td = curthread;
489
490 MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) {
491 update = 0;
492
493 if (mp->mnt_syncer == vp || VOP_ISLOCKED(vp)) {
494 VI_UNLOCK(vp);
495 continue;
496 }
497 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, td) != 0)
498 continue;
499
500 nandfs_node = VTON(vp);
501 if (nandfs_node->nn_flags & IN_MODIFIED) {
502 nandfs_node->nn_flags &= ~(IN_MODIFIED);
503 update = 1;
504 }
505
506 bo = &vp->v_bufobj;
507 BO_LOCK(bo);
508 if (vp->v_bufobj.bo_dirty.bv_cnt) {
509 error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
510 if (error) {
511 nandfs_error("%s: cannot iterate vnode:%p "
512 "err:%d\n", __func__, vp, error);
513 vput(vp);
514 BO_UNLOCK(bo);
515 return (error);
516 }
517 update = 1;
518 } else
519 vput(vp);
520 BO_UNLOCK(bo);
521
522 if (update)
523 nandfs_node_update(nandfs_node);
524 }
525
526 return (0);
527 }
528
529 static int
530 nandfs_update_phys_block(struct nandfs_device *fsdev, struct buf *bp,
531 uint64_t phys_blknr, union nandfs_binfo *binfo)
532 {
533 struct nandfs_node *node, *dat;
534 struct vnode *vp;
535 uint64_t new_blknr;
536 int error;
537
538 vp = bp->b_vp;
539 node = VTON(vp);
540 new_blknr = nandfs_vblk_get(bp);
541 dat = fsdev->nd_dat_node;
542
543 DPRINTF(BMAP, ("%s: ino %#jx lblk %#jx: vblk %#jx -> %#jx\n",
544 __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno,
545 (uintmax_t)new_blknr, (uintmax_t)phys_blknr));
546
547 if (node->nn_ino != NANDFS_DAT_INO) {
548 KASSERT((new_blknr != 0), ("vblk for bp %p is 0", bp));
549
550 nandfs_vblock_assign(fsdev, new_blknr, phys_blknr);
551 binfo->bi_v.bi_vblocknr = new_blknr;
552 binfo->bi_v.bi_blkoff = bp->b_lblkno;
553 binfo->bi_v.bi_ino = node->nn_ino;
554 } else {
555 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
556 error = nandfs_bmap_update_block(node, bp, phys_blknr);
557 if (error) {
558 nandfs_error("%s: error updating block:%jx for bp:%p\n",
559 __func__, (uintmax_t)phys_blknr, bp);
560 VOP_UNLOCK(NTOV(dat), 0);
561 return (error);
562 }
563 VOP_UNLOCK(NTOV(dat), 0);
564 binfo->bi_dat.bi_blkoff = bp->b_lblkno;
565 binfo->bi_dat.bi_ino = node->nn_ino;
566 if (NANDFS_IS_INDIRECT(bp))
567 binfo->bi_dat.bi_level = 1;
568 else
569 binfo->bi_dat.bi_level = 0;
570 }
571
572 return (0);
573 }
574
575 #define NBINFO(off) ((off) + sizeof(union nandfs_binfo))
576 static int
577 nandfs_segment_assign_pblk(struct nandfs_segment *nfsseg)
578 {
579 struct nandfs_device *fsdev;
580 union nandfs_binfo *binfo;
581 struct buf *bp, *seg_bp;
582 uint64_t blocknr;
583 uint32_t curr_off, blocksize;
584 int error;
585
586 fsdev = nfsseg->fsdev;
587 blocksize = fsdev->nd_blocksize;
588
589 blocknr = nfsseg->start_block + nfsseg->segsum_blocks;
590 seg_bp = TAILQ_FIRST(&nfsseg->segsum);
591 DPRINTF(SYNC, ("%s: seg:%p segsum bp:%p data:%p\n",
592 __func__, nfsseg, seg_bp, seg_bp->b_data));
593
594 binfo = (union nandfs_binfo *)(seg_bp->b_data +
595 sizeof(struct nandfs_segment_summary));
596 curr_off = sizeof(struct nandfs_segment_summary);
597
598 TAILQ_FOREACH(bp, &nfsseg->data, b_cluster.cluster_entry) {
599 KASSERT((bp->b_vp), ("bp %p has not vp", bp));
600
601 DPRINTF(BMAP, ("\n\n%s: assign buf %p for ino %#jx next %p\n",
602 __func__, bp, (uintmax_t)VTON(bp->b_vp)->nn_ino,
603 TAILQ_NEXT(bp, b_cluster.cluster_entry)));
604
605 if (NBINFO(curr_off) > blocksize) {
606 seg_bp = TAILQ_NEXT(seg_bp, b_cluster.cluster_entry);
607 binfo = (union nandfs_binfo *)seg_bp->b_data;
608 curr_off = 0;
609 DPRINTF(SYNC, ("%s: next segsum %p data %p\n",
610 __func__, seg_bp, seg_bp->b_data));
611 }
612
613 error = nandfs_update_phys_block(fsdev, bp, blocknr, binfo);
614 if (error) {
615 nandfs_error("%s: err:%d when updatinng phys block:%jx"
616 " for bp:%p and binfo:%p\n", __func__, error,
617 (uintmax_t)blocknr, bp, binfo);
618 return (error);
619 }
620 binfo++;
621 curr_off = NBINFO(curr_off);
622
623 blocknr++;
624 }
625
626 return (0);
627 }
628
629 static int
630 nandfs_seginfo_assign_pblk(struct nandfs_seginfo *seginfo)
631 {
632 struct nandfs_segment *nfsseg;
633 int error = 0;
634
635 LIST_FOREACH(nfsseg, &seginfo->seg_list, seg_link) {
636 error = nandfs_segment_assign_pblk(nfsseg);
637 if (error)
638 break;
639 }
640
641 return (error);
642 }
643
644 static struct nandfs_segment_summary *
645 nandfs_fill_segsum(struct nandfs_segment *seg, int has_sr)
646 {
647 struct nandfs_segment_summary *ss;
648 struct nandfs_device *fsdev;
649 struct buf *bp;
650 uint32_t rest, segsum_size, blocksize, crc_calc;
651 uint16_t flags;
652 uint8_t *crc_area, crc_skip;
653
654 DPRINTF(SYNC, ("%s: seg %#jx nblocks %#x sumbytes %#x\n",
655 __func__, (uintmax_t) seg->seg_num,
656 seg->nblocks + seg->segsum_blocks,
657 seg->segsum_bytes));
658
659 fsdev = seg->fsdev;
660
661 flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND;
662 if (has_sr)
663 flags |= NANDFS_SS_SR;
664
665 bp = TAILQ_FIRST(&seg->segsum);
666 ss = (struct nandfs_segment_summary *) bp->b_data;
667 ss->ss_magic = NANDFS_SEGSUM_MAGIC;
668 ss->ss_bytes = sizeof(struct nandfs_segment_summary);
669 ss->ss_flags = flags;
670 ss->ss_seq = ++(fsdev->nd_seg_sequence);
671 ss->ss_create = fsdev->nd_ts.tv_sec;
672 nandfs_get_segment_range(fsdev, seg->seg_next, &ss->ss_next, NULL);
673 ss->ss_nblocks = seg->nblocks + seg->segsum_blocks;
674 ss->ss_nbinfos = seg->nbinfos;
675 ss->ss_sumbytes = seg->segsum_bytes;
676
677 crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum);
678 blocksize = seg->fsdev->nd_blocksize;
679
680 segsum_size = seg->segsum_bytes - crc_skip;
681 rest = min(seg->segsum_bytes, blocksize) - crc_skip;
682 crc_area = (uint8_t *)ss + crc_skip;
683 crc_calc = ~0U;
684 while (segsum_size > 0) {
685 crc_calc = crc32_raw(crc_area, rest, crc_calc);
686 segsum_size -= rest;
687 if (!segsum_size)
688 break;
689 bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
690 crc_area = (uint8_t *)bp->b_data;
691 rest = segsum_size <= blocksize ? segsum_size : blocksize;
692 }
693 ss->ss_sumsum = crc_calc ^ ~0U;
694
695 return (ss);
696
697 }
698
699 static int
700 nandfs_save_buf(struct buf *bp, uint64_t blocknr, struct nandfs_device *fsdev)
701 {
702 struct bufobj *bo;
703 int error;
704
705 bo = &fsdev->nd_devvp->v_bufobj;
706
707 bp->b_blkno = nandfs_block_to_dblock(fsdev, blocknr);
708 bp->b_iooffset = dbtob(bp->b_blkno);
709
710 KASSERT(bp->b_bufobj != NULL, ("no bufobj for %p", bp));
711 if (bp->b_bufobj != bo) {
712 BO_LOCK(bp->b_bufobj);
713 BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK,
714 BO_LOCKPTR(bp->b_bufobj));
715 KASSERT(BUF_ISLOCKED(bp), ("Problem with locking buffer"));
716 }
717
718 DPRINTF(SYNC, ("%s: buf: %p offset %#jx blk %#jx size %#x\n",
719 __func__, bp, (uintmax_t)bp->b_offset, (uintmax_t)blocknr,
720 fsdev->nd_blocksize));
721
722 NANDFS_UNGATHER(bp);
723 nandfs_buf_clear(bp, 0xffffffff);
724 bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
725 error = bwrite(bp);
726 if (error) {
727 nandfs_error("%s: error:%d when writing buffer:%p\n",
728 __func__, error, bp);
729 return (error);
730 }
731 return (error);
732 }
733
734 static void
735 nandfs_clean_buf(struct nandfs_device *fsdev, struct buf *bp)
736 {
737
738 DPRINTF(SYNC, ("%s: buf: %p\n", __func__, bp));
739
740 NANDFS_UNGATHER(bp);
741 nandfs_buf_clear(bp, 0xffffffff);
742 bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
743 nandfs_undirty_buf_fsdev(fsdev, bp);
744 }
745
746 static void
747 nandfs_clean_segblocks(struct nandfs_segment *seg, uint8_t unlock)
748 {
749 struct nandfs_device *fsdev = seg->fsdev;
750 struct nandfs_segment *next_seg;
751 struct buf *bp, *tbp, *next_bp;
752 struct vnode *vp, *next_vp;
753
754 VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
755 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
756 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
757 nandfs_clean_buf(fsdev, bp);
758 }
759
760 TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
761 TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
762
763 /*
764 * If bp is not super-root and vnode is not currently
765 * locked lock it.
766 */
767 vp = bp->b_vp;
768 next_vp = NULL;
769 next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
770 if (!next_bp) {
771 next_seg = LIST_NEXT(seg, seg_link);
772 if (next_seg)
773 next_bp = TAILQ_FIRST(&next_seg->data);
774 }
775
776 if (next_bp)
777 next_vp = next_bp->b_vp;
778
779 nandfs_clean_buf(fsdev, bp);
780
781 if (unlock && vp != NULL && next_vp != vp &&
782 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
783 vput(vp);
784
785 nandfs_dirty_bufs_decrement(fsdev);
786 }
787
788 VOP_UNLOCK(fsdev->nd_devvp, 0);
789 }
790
791 static int
792 nandfs_save_segblocks(struct nandfs_segment *seg, uint8_t unlock)
793 {
794 struct nandfs_device *fsdev = seg->fsdev;
795 struct nandfs_segment *next_seg;
796 struct buf *bp, *tbp, *next_bp;
797 struct vnode *vp, *next_vp;
798 uint64_t blocknr;
799 uint32_t i = 0;
800 int error = 0;
801
802 VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
803 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
804 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
805 blocknr = seg->start_block + i;
806 error = nandfs_save_buf(bp, blocknr, fsdev);
807 if (error) {
808 nandfs_error("%s: error saving buf: %p blocknr:%jx\n",
809 __func__, bp, (uintmax_t)blocknr);
810 goto out;
811 }
812 i++;
813 }
814
815 i = 0;
816 TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
817 TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
818
819 blocknr = seg->start_block + seg->segsum_blocks + i;
820 /*
821 * If bp is not super-root and vnode is not currently
822 * locked lock it.
823 */
824 vp = bp->b_vp;
825 next_vp = NULL;
826 next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
827 if (!next_bp) {
828 next_seg = LIST_NEXT(seg, seg_link);
829 if (next_seg)
830 next_bp = TAILQ_FIRST(&next_seg->data);
831 }
832
833 if (next_bp)
834 next_vp = next_bp->b_vp;
835
836 error = nandfs_save_buf(bp, blocknr, fsdev);
837 if (error) {
838 nandfs_error("%s: error saving buf: %p blknr: %jx\n",
839 __func__, bp, (uintmax_t)blocknr);
840 if (unlock && vp != NULL && next_vp != vp &&
841 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
842 vput(vp);
843 goto out;
844 }
845
846 if (unlock && vp != NULL && next_vp != vp &&
847 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
848 vput(vp);
849
850 i++;
851 nandfs_dirty_bufs_decrement(fsdev);
852 }
853 out:
854 if (error) {
855 nandfs_clean_segblocks(seg, unlock);
856 VOP_UNLOCK(fsdev->nd_devvp, 0);
857 return (error);
858 }
859
860 VOP_UNLOCK(fsdev->nd_devvp, 0);
861 return (error);
862 }
863
864
865 static void
866 clean_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
867 {
868 struct nandfs_segment *seg;
869
870 DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
871
872 LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
873 nandfs_clean_segblocks(seg, unlock);
874 }
875 }
876
877 static int
878 save_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
879 {
880 struct nandfs_segment *seg;
881 struct nandfs_device *fsdev;
882 struct nandfs_segment_summary *ss;
883 int error = 0;
884
885 fsdev = seginfo->fsdev;
886
887 DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
888
889 LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
890 if (LIST_NEXT(seg, seg_link)) {
891 nandfs_fill_segsum(seg, 0);
892 error = nandfs_save_segblocks(seg, unlock);
893 if (error) {
894 nandfs_error("%s: error:%d saving seg:%p\n",
895 __func__, error, seg);
896 goto out;
897 }
898 } else {
899 ss = nandfs_fill_segsum(seg, 1);
900 fsdev->nd_last_segsum = *ss;
901 error = nandfs_save_segblocks(seg, unlock);
902 if (error) {
903 nandfs_error("%s: error:%d saving seg:%p\n",
904 __func__, error, seg);
905 goto out;
906 }
907 fsdev->nd_last_cno++;
908 fsdev->nd_last_pseg = seg->start_block;
909 }
910 }
911 out:
912 if (error)
913 clean_seginfo(seginfo, unlock);
914 return (error);
915 }
916
917 static void
918 nandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno)
919 {
920 uint64_t start, end;
921 struct buf *bp, *tbd;
922 struct bufobj *bo;
923
924 nandfs_get_segment_range(fsdev, segno, &start, &end);
925
926 bo = &NTOV(fsdev->nd_gc_node)->v_bufobj;
927
928 BO_LOCK(bo);
929 restart_locked_gc:
930 TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) {
931 if (!(bp->b_lblkno >= start && bp->b_lblkno <= end))
932 continue;
933
934 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL))
935 goto restart_locked_gc;
936
937 bremfree(bp);
938 bp->b_flags |= (B_INVAL | B_RELBUF);
939 bp->b_flags &= ~(B_ASYNC | B_MANAGED);
940 BO_UNLOCK(bo);
941 brelse(bp);
942 BO_LOCK(bo);
943 }
944 BO_UNLOCK(bo);
945 }
946
947 /* Process segments marks to free by cleaner */
948 static void
949 nandfs_process_segments(struct nandfs_device *fsdev)
950 {
951 uint64_t saved_segment;
952 int i;
953
954 if (fsdev->nd_free_base) {
955 saved_segment = nandfs_get_segnum_of_block(fsdev,
956 fsdev->nd_super.s_last_pseg);
957 for (i = 0; i < fsdev->nd_free_count; i++) {
958 if (fsdev->nd_free_base[i] == NANDFS_NOSEGMENT)
959 continue;
960 /* Update superblock if clearing segment point by it */
961 if (fsdev->nd_free_base[i] == saved_segment) {
962 nandfs_write_superblock(fsdev);
963 saved_segment = nandfs_get_segnum_of_block(
964 fsdev, fsdev->nd_super.s_last_pseg);
965 }
966 nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]);
967 nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]);
968 }
969
970 free(fsdev->nd_free_base, M_NANDFSTEMP);
971 fsdev->nd_free_base = NULL;
972 fsdev->nd_free_count = 0;
973 }
974 }
975
976 /* Collect and write dirty buffers */
977 int
978 nandfs_sync_file(struct vnode *vp)
979 {
980 struct nandfs_device *fsdev;
981 struct nandfs_node *nandfs_node;
982 struct nandfsmount *nmp;
983 struct nandfs_node *dat, *su, *ifile, *cp;
984 struct nandfs_seginfo *seginfo = NULL;
985 struct nandfs_segment *seg;
986 int update, error;
987 int cno_changed;
988
989 ASSERT_VOP_LOCKED(vp, __func__);
990 DPRINTF(SYNC, ("%s: START\n", __func__));
991
992 error = 0;
993 nmp = VFSTONANDFS(vp->v_mount);
994 fsdev = nmp->nm_nandfsdev;
995
996 dat = fsdev->nd_dat_node;
997 su = fsdev->nd_su_node;
998 cp = fsdev->nd_cp_node;
999 ifile = nmp->nm_ifile_node;
1000
1001 NANDFS_WRITEASSERT(fsdev);
1002 if (lockmgr(&fsdev->nd_seg_const, LK_UPGRADE, NULL) != 0) {
1003 DPRINTF(SYNC, ("%s: lost shared lock\n", __func__));
1004 if (lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL) != 0)
1005 panic("couldn't lock exclusive");
1006 }
1007 DPRINTF(SYNC, ("%s: got lock\n", __func__));
1008
1009 VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1010 create_seginfo(fsdev, &seginfo);
1011
1012 update = 0;
1013
1014 nandfs_node = VTON(vp);
1015 if (nandfs_node->nn_flags & IN_MODIFIED) {
1016 nandfs_node->nn_flags &= ~(IN_MODIFIED);
1017 update = 1;
1018 }
1019
1020 if (vp->v_bufobj.bo_dirty.bv_cnt) {
1021 error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
1022 if (error) {
1023 clean_seginfo(seginfo, 0);
1024 delete_seginfo(seginfo);
1025 VOP_UNLOCK(NTOV(su), 0);
1026 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1027 nandfs_error("%s: err:%d iterating dirty bufs vp:%p",
1028 __func__, error, vp);
1029 return (error);
1030 }
1031 update = 1;
1032 }
1033
1034 if (update) {
1035 VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1036 error = nandfs_node_update(nandfs_node);
1037 if (error) {
1038 clean_seginfo(seginfo, 0);
1039 delete_seginfo(seginfo);
1040 VOP_UNLOCK(NTOV(ifile), 0);
1041 VOP_UNLOCK(NTOV(su), 0);
1042 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1043 nandfs_error("%s: err:%d updating vp:%p",
1044 __func__, error, vp);
1045 return (error);
1046 }
1047 VOP_UNLOCK(NTOV(ifile), 0);
1048 }
1049
1050 cno_changed = 0;
1051 if (seginfo->blocks) {
1052 VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1053 cno_changed = 1;
1054 /* Create new checkpoint */
1055 error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1056 if (error) {
1057 clean_seginfo(seginfo, 0);
1058 delete_seginfo(seginfo);
1059 VOP_UNLOCK(NTOV(cp), 0);
1060 VOP_UNLOCK(NTOV(su), 0);
1061 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1062 nandfs_error("%s: err:%d getting cp:%jx",
1063 __func__, error, fsdev->nd_last_cno + 1);
1064 return (error);
1065 }
1066
1067 /* Reiterate all blocks and assign physical block number */
1068 nandfs_seginfo_assign_pblk(seginfo);
1069
1070 /* Fill checkpoint data */
1071 error = nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1072 &ifile->nn_inode, seginfo->blocks);
1073 if (error) {
1074 clean_seginfo(seginfo, 0);
1075 delete_seginfo(seginfo);
1076 VOP_UNLOCK(NTOV(cp), 0);
1077 VOP_UNLOCK(NTOV(su), 0);
1078 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1079 nandfs_error("%s: err:%d setting cp:%jx",
1080 __func__, error, fsdev->nd_last_cno + 1);
1081 return (error);
1082 }
1083
1084 VOP_UNLOCK(NTOV(cp), 0);
1085 LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1086 nandfs_update_segment(fsdev, seg->seg_num,
1087 seg->nblocks + seg->segsum_blocks);
1088
1089 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1090 error = save_seginfo(seginfo, 0);
1091 if (error) {
1092 clean_seginfo(seginfo, 0);
1093 delete_seginfo(seginfo);
1094 VOP_UNLOCK(NTOV(dat), 0);
1095 VOP_UNLOCK(NTOV(su), 0);
1096 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1097 nandfs_error("%s: err:%d updating seg",
1098 __func__, error);
1099 return (error);
1100 }
1101 VOP_UNLOCK(NTOV(dat), 0);
1102 }
1103
1104 VOP_UNLOCK(NTOV(su), 0);
1105
1106 delete_seginfo(seginfo);
1107 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1108
1109 if (cno_changed && !error) {
1110 if (nandfs_cps_between_sblocks != 0 &&
1111 fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0)
1112 nandfs_write_superblock(fsdev);
1113 }
1114
1115 ASSERT_VOP_LOCKED(vp, __func__);
1116 DPRINTF(SYNC, ("%s: END error %d\n", __func__, error));
1117 return (error);
1118 }
1119
1120 int
1121 nandfs_segment_constructor(struct nandfsmount *nmp, int flags)
1122 {
1123 struct nandfs_device *fsdev;
1124 struct nandfs_seginfo *seginfo = NULL;
1125 struct nandfs_segment *seg;
1126 struct nandfs_node *dat, *su, *ifile, *cp, *gc;
1127 int cno_changed, error;
1128
1129 DPRINTF(SYNC, ("%s: START\n", __func__));
1130 fsdev = nmp->nm_nandfsdev;
1131
1132 lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL);
1133 DPRINTF(SYNC, ("%s: git lock\n", __func__));
1134 again:
1135 create_seginfo(fsdev, &seginfo);
1136
1137 dat = fsdev->nd_dat_node;
1138 su = fsdev->nd_su_node;
1139 cp = fsdev->nd_cp_node;
1140 gc = fsdev->nd_gc_node;
1141 ifile = nmp->nm_ifile_node;
1142
1143 VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1144 VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1145 VOP_LOCK(NTOV(gc), LK_EXCLUSIVE);
1146 VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1147
1148 nandfs_iterate_system_vnode(gc, seginfo);
1149 nandfs_iterate_dirty_vnodes(nmp->nm_vfs_mountp, seginfo);
1150 nandfs_iterate_system_vnode(ifile, seginfo);
1151 nandfs_iterate_system_vnode(su, seginfo);
1152
1153 cno_changed = 0;
1154 if (seginfo->blocks || flags) {
1155 cno_changed = 1;
1156 /* Create new checkpoint */
1157 error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1158 if (error) {
1159 clean_seginfo(seginfo, 0);
1160 delete_seginfo(seginfo);
1161 goto error_locks;
1162 }
1163
1164 /* Collect blocks from system files */
1165 nandfs_iterate_system_vnode(cp, seginfo);
1166 nandfs_iterate_system_vnode(su, seginfo);
1167 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1168 nandfs_iterate_system_vnode(dat, seginfo);
1169 VOP_UNLOCK(NTOV(dat), 0);
1170 reiterate:
1171 seginfo->reiterate = 0;
1172 nandfs_iterate_system_vnode(su, seginfo);
1173 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1174 nandfs_iterate_system_vnode(dat, seginfo);
1175 VOP_UNLOCK(NTOV(dat), 0);
1176 if (seginfo->reiterate)
1177 goto reiterate;
1178 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
1179 error = create_segment(seginfo);
1180 if (error) {
1181 clean_seginfo(seginfo, 0);
1182 delete_seginfo(seginfo);
1183 goto error_locks;
1184 }
1185 goto reiterate;
1186 }
1187
1188 /* Reiterate all blocks and assign physical block number */
1189 nandfs_seginfo_assign_pblk(seginfo);
1190
1191 /* Fill superroot */
1192 error = nandfs_add_superroot(seginfo);
1193 if (error) {
1194 clean_seginfo(seginfo, 0);
1195 delete_seginfo(seginfo);
1196 goto error_locks;
1197 }
1198 KASSERT(!(seginfo->reiterate), ("reiteration after superroot"));
1199
1200 /* Fill checkpoint data */
1201 nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1202 &ifile->nn_inode, seginfo->blocks);
1203
1204 LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1205 nandfs_update_segment(fsdev, seg->seg_num,
1206 seg->nblocks + seg->segsum_blocks);
1207
1208 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1209 error = save_seginfo(seginfo, 1);
1210 if (error) {
1211 clean_seginfo(seginfo, 1);
1212 delete_seginfo(seginfo);
1213 goto error_dat;
1214 }
1215 VOP_UNLOCK(NTOV(dat), 0);
1216 }
1217
1218 VOP_UNLOCK(NTOV(cp), 0);
1219 VOP_UNLOCK(NTOV(gc), 0);
1220 VOP_UNLOCK(NTOV(ifile), 0);
1221
1222 nandfs_process_segments(fsdev);
1223
1224 VOP_UNLOCK(NTOV(su), 0);
1225
1226 delete_seginfo(seginfo);
1227
1228 /*
1229 * XXX: a hack, will go away soon
1230 */
1231 if ((NTOV(dat)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1232 NTOV(cp)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1233 NTOV(gc)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1234 NTOV(ifile)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1235 NTOV(su)->v_bufobj.bo_dirty.bv_cnt != 0) &&
1236 (flags & NANDFS_UMOUNT)) {
1237 DPRINTF(SYNC, ("%s: RERUN\n", __func__));
1238 goto again;
1239 }
1240
1241 MPASS(fsdev->nd_free_base == NULL);
1242
1243 lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1244
1245 if (cno_changed) {
1246 if ((nandfs_cps_between_sblocks != 0 &&
1247 fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) ||
1248 flags & NANDFS_UMOUNT)
1249 nandfs_write_superblock(fsdev);
1250 }
1251
1252 DPRINTF(SYNC, ("%s: END\n", __func__));
1253 return (0);
1254 error_dat:
1255 VOP_UNLOCK(NTOV(dat), 0);
1256 error_locks:
1257 VOP_UNLOCK(NTOV(cp), 0);
1258 VOP_UNLOCK(NTOV(gc), 0);
1259 VOP_UNLOCK(NTOV(ifile), 0);
1260 VOP_UNLOCK(NTOV(su), 0);
1261 lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1262
1263 return (error);
1264 }
1265
1266 #ifdef DDB
1267 /*
1268 * Show details about the given NANDFS mount point.
1269 */
1270 DB_SHOW_COMMAND(nandfs, db_show_nandfs)
1271 {
1272 struct mount *mp;
1273 struct nandfs_device *nffsdev;
1274 struct nandfs_segment *seg;
1275 struct nandfsmount *nmp;
1276 struct buf *bp;
1277 struct vnode *vp;
1278
1279 if (!have_addr) {
1280 db_printf("\nUsage: show nandfs <mount_addr>\n");
1281 return;
1282 }
1283
1284 mp = (struct mount *)addr;
1285 db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname,
1286 mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename);
1287
1288
1289 nmp = (struct nandfsmount *)(mp->mnt_data);
1290 nffsdev = nmp->nm_nandfsdev;
1291 db_printf("dev vnode:%p\n", nffsdev->nd_devvp);
1292 db_printf("blocksize:%jx last cno:%jx last pseg:%jx seg num:%jx\n",
1293 (uintmax_t)nffsdev->nd_blocksize, (uintmax_t)nffsdev->nd_last_cno,
1294 (uintmax_t)nffsdev->nd_last_pseg, (uintmax_t)nffsdev->nd_seg_num);
1295 db_printf("system nodes: dat:%p cp:%p su:%p ifile:%p gc:%p\n",
1296 nffsdev->nd_dat_node, nffsdev->nd_cp_node, nffsdev->nd_su_node,
1297 nmp->nm_ifile_node, nffsdev->nd_gc_node);
1298
1299 if (nffsdev->nd_seginfo != NULL) {
1300 LIST_FOREACH(seg, &nffsdev->nd_seginfo->seg_list, seg_link) {
1301 db_printf("seg: %p\n", seg);
1302 TAILQ_FOREACH(bp, &seg->segsum,
1303 b_cluster.cluster_entry)
1304 db_printf("segbp %p\n", bp);
1305 TAILQ_FOREACH(bp, &seg->data,
1306 b_cluster.cluster_entry) {
1307 vp = bp->b_vp;
1308 db_printf("bp:%p bp->b_vp:%p ino:%jx\n", bp, vp,
1309 (uintmax_t)(vp ? VTON(vp)->nn_ino : 0));
1310 }
1311 }
1312 }
1313 }
1314 #endif
Cache object: 506901e218e3a7ca0bed884ac59fbada
|