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