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