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