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: releng/10.4/sys/fs/nandfs/nandfs_segment.c 294853 2016-01-26 22:14:55Z rpokala $");
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 struct bufobj *bo;
483 int error, update;
484
485 td = curthread;
486
487 MNT_VNODE_FOREACH_ACTIVE(vp, mp, mvp) {
488 update = 0;
489
490 if (mp->mnt_syncer == vp || VOP_ISLOCKED(vp)) {
491 VI_UNLOCK(vp);
492 continue;
493 }
494 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK | LK_NOWAIT, td) != 0)
495 continue;
496
497 nandfs_node = VTON(vp);
498 if (nandfs_node->nn_flags & IN_MODIFIED) {
499 nandfs_node->nn_flags &= ~(IN_MODIFIED);
500 update = 1;
501 }
502
503 bo = &vp->v_bufobj;
504 BO_LOCK(bo);
505 if (vp->v_bufobj.bo_dirty.bv_cnt) {
506 error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
507 if (error) {
508 nandfs_error("%s: cannot iterate vnode:%p "
509 "err:%d\n", __func__, vp, error);
510 vput(vp);
511 BO_UNLOCK(bo);
512 return (error);
513 }
514 update = 1;
515 } else
516 vput(vp);
517 BO_UNLOCK(bo);
518
519 if (update)
520 nandfs_node_update(nandfs_node);
521 }
522
523 return (0);
524 }
525
526 static int
527 nandfs_update_phys_block(struct nandfs_device *fsdev, struct buf *bp,
528 uint64_t phys_blknr, union nandfs_binfo *binfo)
529 {
530 struct nandfs_node *node, *dat;
531 struct vnode *vp;
532 uint64_t new_blknr;
533 int error;
534
535 vp = bp->b_vp;
536 node = VTON(vp);
537 new_blknr = nandfs_vblk_get(bp);
538 dat = fsdev->nd_dat_node;
539
540 DPRINTF(BMAP, ("%s: ino %#jx lblk %#jx: vblk %#jx -> %#jx\n",
541 __func__, (uintmax_t)node->nn_ino, (uintmax_t)bp->b_lblkno,
542 (uintmax_t)new_blknr, (uintmax_t)phys_blknr));
543
544 if (node->nn_ino != NANDFS_DAT_INO) {
545 KASSERT((new_blknr != 0), ("vblk for bp %p is 0", bp));
546
547 nandfs_vblock_assign(fsdev, new_blknr, phys_blknr);
548 binfo->bi_v.bi_vblocknr = new_blknr;
549 binfo->bi_v.bi_blkoff = bp->b_lblkno;
550 binfo->bi_v.bi_ino = node->nn_ino;
551 } else {
552 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
553 error = nandfs_bmap_update_block(node, bp, phys_blknr);
554 if (error) {
555 nandfs_error("%s: error updating block:%jx for bp:%p\n",
556 __func__, (uintmax_t)phys_blknr, bp);
557 VOP_UNLOCK(NTOV(dat), 0);
558 return (error);
559 }
560 VOP_UNLOCK(NTOV(dat), 0);
561 binfo->bi_dat.bi_blkoff = bp->b_lblkno;
562 binfo->bi_dat.bi_ino = node->nn_ino;
563 if (NANDFS_IS_INDIRECT(bp))
564 binfo->bi_dat.bi_level = 1;
565 else
566 binfo->bi_dat.bi_level = 0;
567 }
568
569 return (0);
570 }
571
572 #define NBINFO(off) ((off) + sizeof(union nandfs_binfo))
573 static int
574 nandfs_segment_assign_pblk(struct nandfs_segment *nfsseg)
575 {
576 struct nandfs_device *fsdev;
577 union nandfs_binfo *binfo;
578 struct buf *bp, *seg_bp;
579 uint64_t blocknr;
580 uint32_t curr_off, blocksize;
581 int error;
582
583 fsdev = nfsseg->fsdev;
584 blocksize = fsdev->nd_blocksize;
585
586 blocknr = nfsseg->start_block + nfsseg->segsum_blocks;
587 seg_bp = TAILQ_FIRST(&nfsseg->segsum);
588 DPRINTF(SYNC, ("%s: seg:%p segsum bp:%p data:%p\n",
589 __func__, nfsseg, seg_bp, seg_bp->b_data));
590
591 binfo = (union nandfs_binfo *)(seg_bp->b_data +
592 sizeof(struct nandfs_segment_summary));
593 curr_off = sizeof(struct nandfs_segment_summary);
594
595 TAILQ_FOREACH(bp, &nfsseg->data, b_cluster.cluster_entry) {
596 KASSERT((bp->b_vp), ("bp %p has not vp", bp));
597
598 DPRINTF(BMAP, ("\n\n%s: assign buf %p for ino %#jx next %p\n",
599 __func__, bp, (uintmax_t)VTON(bp->b_vp)->nn_ino,
600 TAILQ_NEXT(bp, b_cluster.cluster_entry)));
601
602 if (NBINFO(curr_off) > blocksize) {
603 seg_bp = TAILQ_NEXT(seg_bp, b_cluster.cluster_entry);
604 binfo = (union nandfs_binfo *)seg_bp->b_data;
605 curr_off = 0;
606 DPRINTF(SYNC, ("%s: next segsum %p data %p\n",
607 __func__, seg_bp, seg_bp->b_data));
608 }
609
610 error = nandfs_update_phys_block(fsdev, bp, blocknr, binfo);
611 if (error) {
612 nandfs_error("%s: err:%d when updatinng phys block:%jx"
613 " for bp:%p and binfo:%p\n", __func__, error,
614 (uintmax_t)blocknr, bp, binfo);
615 return (error);
616 }
617 binfo++;
618 curr_off = NBINFO(curr_off);
619
620 blocknr++;
621 }
622
623 return (0);
624 }
625
626 static int
627 nandfs_seginfo_assign_pblk(struct nandfs_seginfo *seginfo)
628 {
629 struct nandfs_segment *nfsseg;
630 int error = 0;
631
632 LIST_FOREACH(nfsseg, &seginfo->seg_list, seg_link) {
633 error = nandfs_segment_assign_pblk(nfsseg);
634 if (error)
635 break;
636 }
637
638 return (error);
639 }
640
641 static struct nandfs_segment_summary *
642 nandfs_fill_segsum(struct nandfs_segment *seg, int has_sr)
643 {
644 struct nandfs_segment_summary *ss;
645 struct nandfs_device *fsdev;
646 struct buf *bp;
647 uint32_t rest, segsum_size, blocksize, crc_calc;
648 uint16_t flags;
649 uint8_t *crc_area, crc_skip;
650
651 DPRINTF(SYNC, ("%s: seg %#jx nblocks %#x sumbytes %#x\n",
652 __func__, (uintmax_t) seg->seg_num,
653 seg->nblocks + seg->segsum_blocks,
654 seg->segsum_bytes));
655
656 fsdev = seg->fsdev;
657
658 flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND;
659 if (has_sr)
660 flags |= NANDFS_SS_SR;
661
662 bp = TAILQ_FIRST(&seg->segsum);
663 ss = (struct nandfs_segment_summary *) bp->b_data;
664 ss->ss_magic = NANDFS_SEGSUM_MAGIC;
665 ss->ss_bytes = sizeof(struct nandfs_segment_summary);
666 ss->ss_flags = flags;
667 ss->ss_seq = ++(fsdev->nd_seg_sequence);
668 ss->ss_create = fsdev->nd_ts.tv_sec;
669 nandfs_get_segment_range(fsdev, seg->seg_next, &ss->ss_next, NULL);
670 ss->ss_nblocks = seg->nblocks + seg->segsum_blocks;
671 ss->ss_nbinfos = seg->nbinfos;
672 ss->ss_sumbytes = seg->segsum_bytes;
673
674 crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum);
675 blocksize = seg->fsdev->nd_blocksize;
676
677 segsum_size = seg->segsum_bytes - crc_skip;
678 rest = min(seg->segsum_bytes, blocksize) - crc_skip;
679 crc_area = (uint8_t *)ss + crc_skip;
680 crc_calc = ~0U;
681 while (segsum_size > 0) {
682 crc_calc = crc32_raw(crc_area, rest, crc_calc);
683 segsum_size -= rest;
684 if (!segsum_size)
685 break;
686 bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
687 crc_area = (uint8_t *)bp->b_data;
688 rest = segsum_size <= blocksize ? segsum_size : blocksize;
689 }
690 ss->ss_sumsum = crc_calc ^ ~0U;
691
692 return (ss);
693
694 }
695
696 static int
697 nandfs_save_buf(struct buf *bp, uint64_t blocknr, struct nandfs_device *fsdev)
698 {
699 struct bufobj *bo;
700 int error;
701
702 bo = &fsdev->nd_devvp->v_bufobj;
703
704 bp->b_blkno = nandfs_block_to_dblock(fsdev, blocknr);
705 bp->b_iooffset = dbtob(bp->b_blkno);
706
707 KASSERT(bp->b_bufobj != NULL, ("no bufobj for %p", bp));
708 if (bp->b_bufobj != bo) {
709 BO_LOCK(bp->b_bufobj);
710 BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK,
711 BO_LOCKPTR(bp->b_bufobj));
712 KASSERT(BUF_ISLOCKED(bp), ("Problem with locking buffer"));
713 }
714
715 DPRINTF(SYNC, ("%s: buf: %p offset %#jx blk %#jx size %#x\n",
716 __func__, bp, (uintmax_t)bp->b_offset, (uintmax_t)blocknr,
717 fsdev->nd_blocksize));
718
719 NANDFS_UNGATHER(bp);
720 nandfs_buf_clear(bp, 0xffffffff);
721 bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
722 error = bwrite(bp);
723 if (error) {
724 nandfs_error("%s: error:%d when writing buffer:%p\n",
725 __func__, error, bp);
726 return (error);
727 }
728 return (error);
729 }
730
731 static void
732 nandfs_clean_buf(struct nandfs_device *fsdev, struct buf *bp)
733 {
734
735 DPRINTF(SYNC, ("%s: buf: %p\n", __func__, bp));
736
737 NANDFS_UNGATHER(bp);
738 nandfs_buf_clear(bp, 0xffffffff);
739 bp->b_flags &= ~(B_ASYNC|B_INVAL|B_MANAGED);
740 nandfs_undirty_buf_fsdev(fsdev, bp);
741 }
742
743 static void
744 nandfs_clean_segblocks(struct nandfs_segment *seg, uint8_t unlock)
745 {
746 struct nandfs_device *fsdev = seg->fsdev;
747 struct nandfs_segment *next_seg;
748 struct buf *bp, *tbp, *next_bp;
749 struct vnode *vp, *next_vp;
750
751 VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
752 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
753 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
754 nandfs_clean_buf(fsdev, bp);
755 };
756
757 TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
758 TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
759
760 /*
761 * If bp is not super-root and vnode is not currently
762 * locked lock it.
763 */
764 vp = bp->b_vp;
765 next_vp = NULL;
766 next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
767 if (!next_bp) {
768 next_seg = LIST_NEXT(seg, seg_link);
769 if (next_seg)
770 next_bp = TAILQ_FIRST(&next_seg->data);
771 }
772
773 if (next_bp)
774 next_vp = next_bp->b_vp;
775
776 nandfs_clean_buf(fsdev, bp);
777
778 if (unlock && vp != NULL && next_vp != vp &&
779 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
780 vput(vp);
781
782 nandfs_dirty_bufs_decrement(fsdev);
783 }
784
785 VOP_UNLOCK(fsdev->nd_devvp, 0);
786 }
787
788 static int
789 nandfs_save_segblocks(struct nandfs_segment *seg, uint8_t unlock)
790 {
791 struct nandfs_device *fsdev = seg->fsdev;
792 struct nandfs_segment *next_seg;
793 struct buf *bp, *tbp, *next_bp;
794 struct vnode *vp, *next_vp;
795 uint64_t blocknr;
796 uint32_t i = 0;
797 int error = 0;
798
799 VOP_LOCK(fsdev->nd_devvp, LK_EXCLUSIVE);
800 TAILQ_FOREACH_SAFE(bp, &seg->segsum, b_cluster.cluster_entry, tbp) {
801 TAILQ_REMOVE(&seg->segsum, bp, b_cluster.cluster_entry);
802 blocknr = seg->start_block + i;
803 error = nandfs_save_buf(bp, blocknr, fsdev);
804 if (error) {
805 nandfs_error("%s: error saving buf: %p blocknr:%jx\n",
806 __func__, bp, (uintmax_t)blocknr);
807 goto out;
808 }
809 i++;
810 };
811
812 i = 0;
813 TAILQ_FOREACH_SAFE(bp, &seg->data, b_cluster.cluster_entry, tbp) {
814 TAILQ_REMOVE(&seg->data, bp, b_cluster.cluster_entry);
815
816 blocknr = seg->start_block + seg->segsum_blocks + i;
817 /*
818 * If bp is not super-root and vnode is not currently
819 * locked lock it.
820 */
821 vp = bp->b_vp;
822 next_vp = NULL;
823 next_bp = TAILQ_NEXT(bp, b_cluster.cluster_entry);
824 if (!next_bp) {
825 next_seg = LIST_NEXT(seg, seg_link);
826 if (next_seg)
827 next_bp = TAILQ_FIRST(&next_seg->data);
828 }
829
830 if (next_bp)
831 next_vp = next_bp->b_vp;
832
833 error = nandfs_save_buf(bp, blocknr, fsdev);
834 if (error) {
835 nandfs_error("%s: error saving buf: %p blknr: %jx\n",
836 __func__, bp, (uintmax_t)blocknr);
837 if (unlock && vp != NULL && next_vp != vp &&
838 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
839 vput(vp);
840 goto out;
841 }
842
843 if (unlock && vp != NULL && next_vp != vp &&
844 !NANDFS_SYS_NODE(VTON(vp)->nn_ino))
845 vput(vp);
846
847 i++;
848 nandfs_dirty_bufs_decrement(fsdev);
849 }
850 out:
851 if (error) {
852 nandfs_clean_segblocks(seg, unlock);
853 VOP_UNLOCK(fsdev->nd_devvp, 0);
854 return (error);
855 }
856
857 VOP_UNLOCK(fsdev->nd_devvp, 0);
858 return (error);
859 }
860
861
862 static void
863 clean_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
864 {
865 struct nandfs_segment *seg;
866
867 DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
868
869 LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
870 nandfs_clean_segblocks(seg, unlock);
871 }
872 }
873
874 static int
875 save_seginfo(struct nandfs_seginfo *seginfo, uint8_t unlock)
876 {
877 struct nandfs_segment *seg;
878 struct nandfs_device *fsdev;
879 struct nandfs_segment_summary *ss;
880 int error = 0;
881
882 fsdev = seginfo->fsdev;
883
884 DPRINTF(SYNC, ("%s: seginfo %p\n", __func__, seginfo));
885
886 LIST_FOREACH(seg, &seginfo->seg_list, seg_link) {
887 if (LIST_NEXT(seg, seg_link)) {
888 nandfs_fill_segsum(seg, 0);
889 error = nandfs_save_segblocks(seg, unlock);
890 if (error) {
891 nandfs_error("%s: error:%d saving seg:%p\n",
892 __func__, error, seg);
893 goto out;
894 }
895 } else {
896 ss = nandfs_fill_segsum(seg, 1);
897 fsdev->nd_last_segsum = *ss;
898 error = nandfs_save_segblocks(seg, unlock);
899 if (error) {
900 nandfs_error("%s: error:%d saving seg:%p\n",
901 __func__, error, seg);
902 goto out;
903 }
904 fsdev->nd_last_cno++;
905 fsdev->nd_last_pseg = seg->start_block;
906 }
907 }
908 out:
909 if (error)
910 clean_seginfo(seginfo, unlock);
911 return (error);
912 }
913
914 static void
915 nandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno)
916 {
917 uint64_t start, end;
918 struct buf *bp, *tbd;
919 struct bufobj *bo;
920
921 nandfs_get_segment_range(fsdev, segno, &start, &end);
922
923 bo = &NTOV(fsdev->nd_gc_node)->v_bufobj;
924
925 BO_LOCK(bo);
926 restart_locked_gc:
927 TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) {
928 if (!(bp->b_lblkno >= start && bp->b_lblkno <= end))
929 continue;
930
931 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL))
932 goto restart_locked_gc;
933
934 bremfree(bp);
935 bp->b_flags |= (B_INVAL | B_RELBUF);
936 bp->b_flags &= ~(B_ASYNC | B_MANAGED);
937 BO_UNLOCK(bo);
938 brelse(bp);
939 BO_LOCK(bo);
940 }
941 BO_UNLOCK(bo);
942 }
943
944 /* Process segments marks to free by cleaner */
945 static void
946 nandfs_process_segments(struct nandfs_device *fsdev)
947 {
948 uint64_t saved_segment;
949 int i;
950
951 if (fsdev->nd_free_base) {
952 saved_segment = nandfs_get_segnum_of_block(fsdev,
953 fsdev->nd_super.s_last_pseg);
954 for (i = 0; i < fsdev->nd_free_count; i++) {
955 if (fsdev->nd_free_base[i] == NANDFS_NOSEGMENT)
956 continue;
957 /* Update superblock if clearing segment point by it */
958 if (fsdev->nd_free_base[i] == saved_segment) {
959 nandfs_write_superblock(fsdev);
960 saved_segment = nandfs_get_segnum_of_block(
961 fsdev, fsdev->nd_super.s_last_pseg);
962 }
963 nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]);
964 nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]);
965 }
966
967 free(fsdev->nd_free_base, M_NANDFSTEMP);
968 fsdev->nd_free_base = NULL;
969 fsdev->nd_free_count = 0;
970 }
971 }
972
973 /* Collect and write dirty buffers */
974 int
975 nandfs_sync_file(struct vnode *vp)
976 {
977 struct nandfs_device *fsdev;
978 struct nandfs_node *nandfs_node;
979 struct nandfsmount *nmp;
980 struct nandfs_node *dat, *su, *ifile, *cp;
981 struct nandfs_seginfo *seginfo = NULL;
982 struct nandfs_segment *seg;
983 int update, error;
984 int cno_changed;
985
986 ASSERT_VOP_LOCKED(vp, __func__);
987 DPRINTF(SYNC, ("%s: START\n", __func__));
988
989 error = 0;
990 nmp = VFSTONANDFS(vp->v_mount);
991 fsdev = nmp->nm_nandfsdev;
992
993 dat = fsdev->nd_dat_node;
994 su = fsdev->nd_su_node;
995 cp = fsdev->nd_cp_node;
996 ifile = nmp->nm_ifile_node;
997
998 NANDFS_WRITEASSERT(fsdev);
999 if (lockmgr(&fsdev->nd_seg_const, LK_UPGRADE, NULL) != 0) {
1000 DPRINTF(SYNC, ("%s: lost shared lock\n", __func__));
1001 if (lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL) != 0)
1002 panic("couldn't lock exclusive");
1003 }
1004 DPRINTF(SYNC, ("%s: got lock\n", __func__));
1005
1006 VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1007 create_seginfo(fsdev, &seginfo);
1008
1009 update = 0;
1010
1011 nandfs_node = VTON(vp);
1012 if (nandfs_node->nn_flags & IN_MODIFIED) {
1013 nandfs_node->nn_flags &= ~(IN_MODIFIED);
1014 update = 1;
1015 }
1016
1017 if (vp->v_bufobj.bo_dirty.bv_cnt) {
1018 error = nandfs_iterate_dirty_buf(vp, seginfo, 0);
1019 if (error) {
1020 clean_seginfo(seginfo, 0);
1021 delete_seginfo(seginfo);
1022 VOP_UNLOCK(NTOV(su), 0);
1023 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1024 nandfs_error("%s: err:%d iterating dirty bufs vp:%p",
1025 __func__, error, vp);
1026 return (error);
1027 }
1028 update = 1;
1029 }
1030
1031 if (update) {
1032 VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1033 error = nandfs_node_update(nandfs_node);
1034 if (error) {
1035 clean_seginfo(seginfo, 0);
1036 delete_seginfo(seginfo);
1037 VOP_UNLOCK(NTOV(ifile), 0);
1038 VOP_UNLOCK(NTOV(su), 0);
1039 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1040 nandfs_error("%s: err:%d updating vp:%p",
1041 __func__, error, vp);
1042 return (error);
1043 }
1044 VOP_UNLOCK(NTOV(ifile), 0);
1045 }
1046
1047 cno_changed = 0;
1048 if (seginfo->blocks) {
1049 VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1050 cno_changed = 1;
1051 /* Create new checkpoint */
1052 error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1053 if (error) {
1054 clean_seginfo(seginfo, 0);
1055 delete_seginfo(seginfo);
1056 VOP_UNLOCK(NTOV(cp), 0);
1057 VOP_UNLOCK(NTOV(su), 0);
1058 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1059 nandfs_error("%s: err:%d getting cp:%jx",
1060 __func__, error, fsdev->nd_last_cno + 1);
1061 return (error);
1062 }
1063
1064 /* Reiterate all blocks and assign physical block number */
1065 nandfs_seginfo_assign_pblk(seginfo);
1066
1067 /* Fill checkpoint data */
1068 error = nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1069 &ifile->nn_inode, seginfo->blocks);
1070 if (error) {
1071 clean_seginfo(seginfo, 0);
1072 delete_seginfo(seginfo);
1073 VOP_UNLOCK(NTOV(cp), 0);
1074 VOP_UNLOCK(NTOV(su), 0);
1075 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1076 nandfs_error("%s: err:%d setting cp:%jx",
1077 __func__, error, fsdev->nd_last_cno + 1);
1078 return (error);
1079 }
1080
1081 VOP_UNLOCK(NTOV(cp), 0);
1082 LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1083 nandfs_update_segment(fsdev, seg->seg_num,
1084 seg->nblocks + seg->segsum_blocks);
1085
1086 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1087 error = save_seginfo(seginfo, 0);
1088 if (error) {
1089 clean_seginfo(seginfo, 0);
1090 delete_seginfo(seginfo);
1091 VOP_UNLOCK(NTOV(dat), 0);
1092 VOP_UNLOCK(NTOV(su), 0);
1093 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1094 nandfs_error("%s: err:%d updating seg",
1095 __func__, error);
1096 return (error);
1097 }
1098 VOP_UNLOCK(NTOV(dat), 0);
1099 }
1100
1101 VOP_UNLOCK(NTOV(su), 0);
1102
1103 delete_seginfo(seginfo);
1104 lockmgr(&fsdev->nd_seg_const, LK_DOWNGRADE, NULL);
1105
1106 if (cno_changed && !error) {
1107 if (nandfs_cps_between_sblocks != 0 &&
1108 fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0)
1109 nandfs_write_superblock(fsdev);
1110 }
1111
1112 ASSERT_VOP_LOCKED(vp, __func__);
1113 DPRINTF(SYNC, ("%s: END error %d\n", __func__, error));
1114 return (error);
1115 }
1116
1117 int
1118 nandfs_segment_constructor(struct nandfsmount *nmp, int flags)
1119 {
1120 struct nandfs_device *fsdev;
1121 struct nandfs_seginfo *seginfo = NULL;
1122 struct nandfs_segment *seg;
1123 struct nandfs_node *dat, *su, *ifile, *cp, *gc;
1124 int cno_changed, error;
1125
1126 DPRINTF(SYNC, ("%s: START\n", __func__));
1127 fsdev = nmp->nm_nandfsdev;
1128
1129 lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL);
1130 DPRINTF(SYNC, ("%s: git lock\n", __func__));
1131 again:
1132 create_seginfo(fsdev, &seginfo);
1133
1134 dat = fsdev->nd_dat_node;
1135 su = fsdev->nd_su_node;
1136 cp = fsdev->nd_cp_node;
1137 gc = fsdev->nd_gc_node;
1138 ifile = nmp->nm_ifile_node;
1139
1140 VOP_LOCK(NTOV(su), LK_EXCLUSIVE);
1141 VOP_LOCK(NTOV(ifile), LK_EXCLUSIVE);
1142 VOP_LOCK(NTOV(gc), LK_EXCLUSIVE);
1143 VOP_LOCK(NTOV(cp), LK_EXCLUSIVE);
1144
1145 nandfs_iterate_system_vnode(gc, seginfo);
1146 nandfs_iterate_dirty_vnodes(nmp->nm_vfs_mountp, seginfo);
1147 nandfs_iterate_system_vnode(ifile, seginfo);
1148 nandfs_iterate_system_vnode(su, seginfo);
1149
1150 cno_changed = 0;
1151 if (seginfo->blocks || flags) {
1152 cno_changed = 1;
1153 /* Create new checkpoint */
1154 error = nandfs_get_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1);
1155 if (error) {
1156 clean_seginfo(seginfo, 0);
1157 delete_seginfo(seginfo);
1158 goto error_locks;
1159 }
1160
1161 /* Collect blocks from system files */
1162 nandfs_iterate_system_vnode(cp, seginfo);
1163 nandfs_iterate_system_vnode(su, seginfo);
1164 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1165 nandfs_iterate_system_vnode(dat, seginfo);
1166 VOP_UNLOCK(NTOV(dat), 0);
1167 reiterate:
1168 seginfo->reiterate = 0;
1169 nandfs_iterate_system_vnode(su, seginfo);
1170 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1171 nandfs_iterate_system_vnode(dat, seginfo);
1172 VOP_UNLOCK(NTOV(dat), 0);
1173 if (seginfo->reiterate)
1174 goto reiterate;
1175 if (!(seginfo->curseg) || !seginfo->curseg->num_blocks) {
1176 error = create_segment(seginfo);
1177 if (error) {
1178 clean_seginfo(seginfo, 0);
1179 delete_seginfo(seginfo);
1180 goto error_locks;
1181 }
1182 goto reiterate;
1183 }
1184
1185 /* Reiterate all blocks and assign physical block number */
1186 nandfs_seginfo_assign_pblk(seginfo);
1187
1188 /* Fill superroot */
1189 error = nandfs_add_superroot(seginfo);
1190 if (error) {
1191 clean_seginfo(seginfo, 0);
1192 delete_seginfo(seginfo);
1193 goto error_locks;
1194 }
1195 KASSERT(!(seginfo->reiterate), ("reiteration after superroot"));
1196
1197 /* Fill checkpoint data */
1198 nandfs_set_checkpoint(fsdev, cp, fsdev->nd_last_cno + 1,
1199 &ifile->nn_inode, seginfo->blocks);
1200
1201 LIST_FOREACH(seg, &seginfo->seg_list, seg_link)
1202 nandfs_update_segment(fsdev, seg->seg_num,
1203 seg->nblocks + seg->segsum_blocks);
1204
1205 VOP_LOCK(NTOV(dat), LK_EXCLUSIVE);
1206 error = save_seginfo(seginfo, 1);
1207 if (error) {
1208 clean_seginfo(seginfo, 1);
1209 delete_seginfo(seginfo);
1210 goto error_dat;
1211 }
1212 VOP_UNLOCK(NTOV(dat), 0);
1213 }
1214
1215 VOP_UNLOCK(NTOV(cp), 0);
1216 VOP_UNLOCK(NTOV(gc), 0);
1217 VOP_UNLOCK(NTOV(ifile), 0);
1218
1219 nandfs_process_segments(fsdev);
1220
1221 VOP_UNLOCK(NTOV(su), 0);
1222
1223 delete_seginfo(seginfo);
1224
1225 /*
1226 * XXX: a hack, will go away soon
1227 */
1228 if ((NTOV(dat)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1229 NTOV(cp)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1230 NTOV(gc)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1231 NTOV(ifile)->v_bufobj.bo_dirty.bv_cnt != 0 ||
1232 NTOV(su)->v_bufobj.bo_dirty.bv_cnt != 0) &&
1233 (flags & NANDFS_UMOUNT)) {
1234 DPRINTF(SYNC, ("%s: RERUN\n", __func__));
1235 goto again;
1236 }
1237
1238 MPASS(fsdev->nd_free_base == NULL);
1239
1240 lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1241
1242 if (cno_changed) {
1243 if ((nandfs_cps_between_sblocks != 0 &&
1244 fsdev->nd_last_cno % nandfs_cps_between_sblocks == 0) ||
1245 flags & NANDFS_UMOUNT)
1246 nandfs_write_superblock(fsdev);
1247 }
1248
1249 DPRINTF(SYNC, ("%s: END\n", __func__));
1250 return (0);
1251 error_dat:
1252 VOP_UNLOCK(NTOV(dat), 0);
1253 error_locks:
1254 VOP_UNLOCK(NTOV(cp), 0);
1255 VOP_UNLOCK(NTOV(gc), 0);
1256 VOP_UNLOCK(NTOV(ifile), 0);
1257 VOP_UNLOCK(NTOV(su), 0);
1258 lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL);
1259
1260 return (error);
1261 }
1262
1263 #ifdef DDB
1264 /*
1265 * Show details about the given NANDFS mount point.
1266 */
1267 DB_SHOW_COMMAND(nandfs, db_show_nandfs)
1268 {
1269 struct mount *mp;
1270 struct nandfs_device *nffsdev;
1271 struct nandfs_segment *seg;
1272 struct nandfsmount *nmp;
1273 struct buf *bp;
1274 struct vnode *vp;
1275
1276 if (!have_addr) {
1277 db_printf("\nUsage: show nandfs <mount_addr>\n");
1278 return;
1279 }
1280
1281 mp = (struct mount *)addr;
1282 db_printf("%p %s on %s (%s)\n", mp, mp->mnt_stat.f_mntfromname,
1283 mp->mnt_stat.f_mntonname, mp->mnt_stat.f_fstypename);
1284
1285
1286 nmp = (struct nandfsmount *)(mp->mnt_data);
1287 nffsdev = nmp->nm_nandfsdev;
1288 db_printf("dev vnode:%p\n", nffsdev->nd_devvp);
1289 db_printf("blocksize:%jx last cno:%jx last pseg:%jx seg num:%jx\n",
1290 (uintmax_t)nffsdev->nd_blocksize, (uintmax_t)nffsdev->nd_last_cno,
1291 (uintmax_t)nffsdev->nd_last_pseg, (uintmax_t)nffsdev->nd_seg_num);
1292 db_printf("system nodes: dat:%p cp:%p su:%p ifile:%p gc:%p\n",
1293 nffsdev->nd_dat_node, nffsdev->nd_cp_node, nffsdev->nd_su_node,
1294 nmp->nm_ifile_node, nffsdev->nd_gc_node);
1295
1296 if (nffsdev->nd_seginfo != NULL) {
1297 LIST_FOREACH(seg, &nffsdev->nd_seginfo->seg_list, seg_link) {
1298 db_printf("seg: %p\n", seg);
1299 TAILQ_FOREACH(bp, &seg->segsum,
1300 b_cluster.cluster_entry)
1301 db_printf("segbp %p\n", bp);
1302 TAILQ_FOREACH(bp, &seg->data,
1303 b_cluster.cluster_entry) {
1304 vp = bp->b_vp;
1305 db_printf("bp:%p bp->b_vp:%p ino:%jx\n", bp, vp,
1306 (uintmax_t)(vp ? VTON(vp)->nn_ino : 0));
1307 }
1308 }
1309 }
1310 }
1311 #endif
Cache object: 51b353bc5c40fb64618ab5e04a4b93a9
|