2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2010-2012 Semihalf
5 * Copyright (c) 2008, 2009 Reinoud Zandijk
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/namei.h>
37 #include <sys/resourcevar.h>
38 #include <sys/kernel.h>
44 #include <sys/mount.h>
45 #include <sys/vnode.h>
46 #include <sys/signalvar.h>
47 #include <sys/malloc.h>
48 #include <sys/dirent.h>
49 #include <sys/lockf.h>
50 #include <sys/libkern.h>
52 #include <geom/geom.h>
53 #include <geom/geom_vfs.h>
56 #include <vm/vm_extern.h>
58 #include <machine/_inttypes.h>
59 #include "nandfs_mount.h"
61 #include "nandfs_subr.h"
63 MALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount");
64 MALLOC_DEFINE(M_NANDFSTEMP, "nandfs_tmt", "NANDFS tmp");
66 uma_zone_t nandfs_node_zone;
68 void nandfs_bdflush(struct bufobj *bo, struct buf *bp);
69 int nandfs_bufsync(struct bufobj *bo, int waitfor);
71 struct buf_ops buf_ops_nandfs = {
72 .bop_name = "buf_ops_nandfs",
73 .bop_write = bufwrite,
74 .bop_strategy = bufstrategy,
75 .bop_sync = nandfs_bufsync,
76 .bop_bdflush = nandfs_bdflush,
80 nandfs_bufsync(struct bufobj *bo, int waitfor)
87 ASSERT_VOP_LOCKED(vp, __func__);
88 error = nandfs_sync_file(vp);
90 nandfs_warning("%s: cannot flush buffers err:%d\n",
97 nandfs_bdflush(bo, bp)
104 if (bo->bo_dirty.bv_cnt <= ((dirtybufthresh * 8) / 10))
108 if (NANDFS_SYS_NODE(VTON(vp)->nn_ino))
111 if (NANDFS_IS_INDIRECT(bp))
114 error = nandfs_sync_file(vp);
116 nandfs_warning("%s: cannot flush buffers err:%d\n",
121 nandfs_init(struct vfsconf *vfsp)
124 nandfs_node_zone = uma_zcreate("nandfs node zone",
125 sizeof(struct nandfs_node), NULL, NULL, NULL, NULL, 0, 0);
131 nandfs_uninit(struct vfsconf *vfsp)
134 uma_zdestroy(nandfs_node_zone);
138 /* Basic calculators */
140 nandfs_get_segnum_of_block(struct nandfs_device *nandfsdev,
141 nandfs_daddr_t blocknr)
143 uint64_t segnum, blks_per_seg;
145 MPASS(blocknr >= nandfsdev->nd_fsdata.f_first_data_block);
147 blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment;
149 segnum = blocknr / blks_per_seg;
150 segnum -= nandfsdev->nd_fsdata.f_first_data_block / blks_per_seg;
152 DPRINTF(SYNC, ("%s: returning blocknr %jx -> segnum %jx\n", __func__,
159 nandfs_get_segment_range(struct nandfs_device *nandfsdev, uint64_t segnum,
160 uint64_t *seg_start, uint64_t *seg_end)
162 uint64_t blks_per_seg;
164 blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment;
165 *seg_start = nandfsdev->nd_fsdata.f_first_data_block +
166 blks_per_seg * segnum;
168 *seg_end = *seg_start + blks_per_seg -1;
171 void nandfs_calc_mdt_consts(struct nandfs_device *nandfsdev,
172 struct nandfs_mdt *mdt, int entry_size)
174 uint32_t blocksize = nandfsdev->nd_blocksize;
176 mdt->entries_per_group = blocksize * 8;
177 mdt->entries_per_block = blocksize / entry_size;
179 mdt->blocks_per_group =
180 (mdt->entries_per_group -1) / mdt->entries_per_block + 1 + 1;
181 mdt->groups_per_desc_block =
182 blocksize / sizeof(struct nandfs_block_group_desc);
183 mdt->blocks_per_desc_block =
184 mdt->groups_per_desc_block * mdt->blocks_per_group + 1;
188 nandfs_dev_bread(struct nandfs_device *nandfsdev, nandfs_lbn_t blocknr,
189 struct ucred *cred, int flags, struct buf **bpp)
191 int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE;
194 DPRINTF(BLOCK, ("%s: read from block %jx vp %p\n", __func__,
195 blocknr * blk2dev, nandfsdev->nd_devvp));
196 error = bread(nandfsdev->nd_devvp, blocknr * blk2dev,
197 nandfsdev->nd_blocksize, NOCRED, bpp);
199 nandfs_error("%s: cannot read from device - blk:%jx\n",
206 nandfs_bread(struct nandfs_node *node, nandfs_lbn_t blocknr,
207 struct ucred *cred, int flags, struct buf **bpp)
212 DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
215 error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
218 KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__,
219 NTOV(node), blocknr, error));
221 if (!nandfs_vblk_get(*bpp) &&
222 ((*bpp)->b_flags & B_CACHE) && node->nn_ino != NANDFS_DAT_INO) {
223 nandfs_bmap_lookup(node, blocknr, &vblk);
224 nandfs_vblk_set(*bpp, vblk);
230 nandfs_bread_meta(struct nandfs_node *node, nandfs_lbn_t blocknr,
231 struct ucred *cred, int flags, struct buf **bpp)
236 DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
239 error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
242 KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__,
243 NTOV(node), blocknr, error));
245 if (!nandfs_vblk_get(*bpp) &&
246 ((*bpp)->b_flags & B_CACHE) && node->nn_ino != NANDFS_DAT_INO) {
247 nandfs_bmap_lookup(node, blocknr, &vblk);
248 nandfs_vblk_set(*bpp, vblk);
255 nandfs_bdestroy(struct nandfs_node *node, nandfs_daddr_t vblk)
259 if (!NANDFS_SYS_NODE(node->nn_ino))
260 NANDFS_WRITEASSERT(node->nn_nandfsdev);
262 error = nandfs_vblock_end(node->nn_nandfsdev, vblk);
264 nandfs_error("%s: ending vblk: %jx failed\n",
265 __func__, (uintmax_t)vblk);
268 node->nn_inode.i_blocks--;
274 nandfs_bcreate(struct nandfs_node *node, nandfs_lbn_t blocknr,
275 struct ucred *cred, int flags, struct buf **bpp)
279 ASSERT_VOP_LOCKED(NTOV(node), __func__);
280 if (!NANDFS_SYS_NODE(node->nn_ino))
281 NANDFS_WRITEASSERT(node->nn_nandfsdev);
283 DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
286 *bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
289 KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__,
290 NTOV(node), blocknr));
293 vfs_bio_clrbuf(*bpp);
294 (*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */
295 error = nandfs_bmap_insert_block(node, blocknr, *bpp);
297 nandfs_warning("%s: failed bmap insert node:%p"
298 " blk:%jx\n", __func__, node, blocknr);
302 node->nn_inode.i_blocks++;
311 nandfs_bcreate_meta(struct nandfs_node *node, nandfs_lbn_t blocknr,
312 struct ucred *cred, int flags, struct buf **bpp)
314 struct nandfs_device *fsdev;
318 ASSERT_VOP_LOCKED(NTOV(node), __func__);
319 NANDFS_WRITEASSERT(node->nn_nandfsdev);
321 DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
324 fsdev = node->nn_nandfsdev;
326 *bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
329 KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__,
330 NTOV(node), blocknr));
332 memset((*bpp)->b_data, 0, fsdev->nd_blocksize);
334 vfs_bio_clrbuf(*bpp);
335 (*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */
337 nandfs_buf_set(*bpp, NANDFS_VBLK_ASSIGNED);
339 if (node->nn_ino != NANDFS_DAT_INO) {
340 error = nandfs_vblock_alloc(fsdev, &vblk);
342 nandfs_buf_clear(*bpp, NANDFS_VBLK_ASSIGNED);
347 vblk = fsdev->nd_fakevblk++;
349 nandfs_vblk_set(*bpp, vblk);
351 nandfs_bmap_insert_block(node, blocknr, *bpp);
355 /* Translate index to a file block number and an entry */
357 nandfs_mdt_trans(struct nandfs_mdt *mdt, uint64_t index,
358 nandfs_lbn_t *blocknr, uint32_t *entry_in_block)
361 uint64_t group, group_offset, blocknr_in_group;
362 uint64_t desc_block, desc_offset;
364 /* Calculate our offset in the file */
365 group = index / mdt->entries_per_group;
366 group_offset = index % mdt->entries_per_group;
367 desc_block = group / mdt->groups_per_desc_block;
368 desc_offset = group % mdt->groups_per_desc_block;
369 blocknr_in_group = group_offset / mdt->entries_per_block;
371 /* To descgroup offset */
372 blknr = 1 + desc_block * mdt->blocks_per_desc_block;
374 /* To group offset */
375 blknr += desc_offset * mdt->blocks_per_group;
377 /* To actual file block */
378 blknr += 1 + blocknr_in_group;
381 *entry_in_block = group_offset % mdt->entries_per_block;
385 nandfs_mdt_trans_blk(struct nandfs_mdt *mdt, uint64_t index,
386 uint64_t *desc, uint64_t *bitmap, nandfs_lbn_t *blocknr,
387 uint32_t *entry_in_block)
390 uint64_t group, group_offset, blocknr_in_group;
391 uint64_t desc_block, desc_offset;
393 /* Calculate our offset in the file */
394 group = index / mdt->entries_per_group;
395 group_offset = index % mdt->entries_per_group;
396 desc_block = group / mdt->groups_per_desc_block;
397 desc_offset = group % mdt->groups_per_desc_block;
398 blocknr_in_group = group_offset / mdt->entries_per_block;
400 /* To descgroup offset */
401 *desc = desc_block * mdt->blocks_per_desc_block;
402 blknr = 1 + desc_block * mdt->blocks_per_desc_block;
404 /* To group offset */
405 blknr += desc_offset * mdt->blocks_per_group;
408 /* To actual file block */
409 blknr += 1 + blocknr_in_group;
412 *entry_in_block = group_offset % mdt->entries_per_block;
415 ("%s: desc_buf: %jx bitmap_buf: %jx entry_buf: %jx entry: %x\n",
416 __func__, (uintmax_t)*desc, (uintmax_t)*bitmap,
417 (uintmax_t)*blocknr, *entry_in_block));
421 nandfs_vtop(struct nandfs_node *node, nandfs_daddr_t vblocknr,
422 nandfs_daddr_t *pblocknr)
424 struct nandfs_node *dat_node;
425 struct nandfs_dat_entry *entry;
427 nandfs_lbn_t ldatblknr;
428 uint32_t entry_in_block;
431 if (node->nn_ino == NANDFS_DAT_INO || node->nn_ino == NANDFS_GC_INO) {
432 *pblocknr = vblocknr;
436 /* only translate valid vblocknrs */
440 dat_node = node->nn_nandfsdev->nd_dat_node;
441 nandfs_mdt_trans(&node->nn_nandfsdev->nd_dat_mdt, vblocknr, &ldatblknr,
444 locked = NANDFS_VOP_ISLOCKED(NTOV(dat_node));
446 VOP_LOCK(NTOV(dat_node), LK_SHARED);
447 error = nandfs_bread(dat_node, ldatblknr, NOCRED, 0, &bp);
449 DPRINTF(TRANSLATE, ("vtop: can't read in DAT block %#jx!\n",
450 (uintmax_t)ldatblknr));
452 VOP_UNLOCK(NTOV(dat_node), 0);
456 /* Get our translation */
457 entry = ((struct nandfs_dat_entry *) bp->b_data) + entry_in_block;
458 DPRINTF(TRANSLATE, ("\tentry %p data %p entry_in_block %x\n",
459 entry, bp->b_data, entry_in_block))
460 DPRINTF(TRANSLATE, ("\tvblk %#jx -> %#jx for cp [%#jx-%#jx]\n",
461 (uintmax_t)vblocknr, (uintmax_t)entry->de_blocknr,
462 (uintmax_t)entry->de_start, (uintmax_t)entry->de_end));
464 *pblocknr = entry->de_blocknr;
467 VOP_UNLOCK(NTOV(dat_node), 0);
469 MPASS(*pblocknr >= node->nn_nandfsdev->nd_fsdata.f_first_data_block ||
476 nandfs_segsum_valid(struct nandfs_segment_summary *segsum)
479 return (segsum->ss_magic == NANDFS_SEGSUM_MAGIC);
483 nandfs_load_segsum(struct nandfs_device *fsdev, nandfs_daddr_t blocknr,
484 struct nandfs_segment_summary *segsum)
489 DPRINTF(VOLUMES, ("nandfs: try segsum at block %jx\n",
490 (uintmax_t)blocknr));
492 error = nandfs_dev_bread(fsdev, blocknr, NOCRED, 0, &bp);
496 memcpy(segsum, bp->b_data, sizeof(struct nandfs_segment_summary));
499 if (!nandfs_segsum_valid(segsum)) {
500 DPRINTF(VOLUMES, ("%s: bad magic pseg:%jx\n", __func__,
509 nandfs_load_super_root(struct nandfs_device *nandfsdev,
510 struct nandfs_segment_summary *segsum, uint64_t pseg)
512 struct nandfs_super_root super_root;
515 uint32_t super_root_crc, comp_crc;
518 /* Check if there is a superroot */
519 if ((segsum->ss_flags & NANDFS_SS_SR) == 0) {
520 DPRINTF(VOLUMES, ("%s: no super root in pseg:%jx\n", __func__,
525 /* Get our super root, located at the end of the pseg */
526 blocknr = pseg + segsum->ss_nblocks - 1;
527 DPRINTF(VOLUMES, ("%s: try at %#jx\n", __func__, (uintmax_t)blocknr));
529 error = nandfs_dev_bread(nandfsdev, blocknr, NOCRED, 0, &bp);
533 memcpy(&super_root, bp->b_data, sizeof(struct nandfs_super_root));
536 /* Check super root CRC */
537 super_root_crc = super_root.sr_sum;
538 off = sizeof(super_root.sr_sum);
539 comp_crc = crc32((uint8_t *)&super_root + off,
540 NANDFS_SR_BYTES - off);
542 if (super_root_crc != comp_crc) {
543 DPRINTF(VOLUMES, ("%s: invalid crc:%#x [expect:%#x]\n",
544 __func__, super_root_crc, comp_crc));
548 nandfsdev->nd_super_root = super_root;
549 DPRINTF(VOLUMES, ("%s: got valid superroot\n", __func__));
555 * Search for the last super root recorded.
558 nandfs_search_super_root(struct nandfs_device *nandfsdev)
560 struct nandfs_super_block *super;
561 struct nandfs_segment_summary segsum;
562 uint64_t seg_start, seg_end, cno, seq, create, pseg;
568 /* Search for last super root */
569 pseg = nandfsdev->nd_super.s_last_pseg;
570 segnum = nandfs_get_segnum_of_block(nandfsdev, pseg);
572 cno = nandfsdev->nd_super.s_last_cno;
574 DPRINTF(VOLUMES, ("%s: start in pseg %#jx\n", __func__,
578 error = nandfs_load_segsum(nandfsdev, pseg, &segsum);
582 if (segsum.ss_seq < seq || segsum.ss_create < create)
585 /* Try to load super root */
586 if (segsum.ss_flags & NANDFS_SS_SR) {
587 error = nandfs_load_super_root(nandfsdev, &segsum, pseg);
589 break; /* confused */
592 super = &nandfsdev->nd_super;
593 nandfsdev->nd_last_segsum = segsum;
594 super->s_last_pseg = pseg;
595 super->s_last_cno = cno++;
596 super->s_last_seq = segsum.ss_seq;
597 super->s_state = NANDFS_VALID_FS;
599 create = segsum.ss_create;
602 create = segsum.ss_create;
605 /* Calculate next partial segment location */
606 pseg += segsum.ss_nblocks;
607 DPRINTF(VOLUMES, ("%s: next partial seg is %jx\n", __func__,
610 /* Did we reach the end of the segment? if so, go to the next */
611 nandfs_get_segment_range(nandfsdev, segnum, &seg_start,
613 if (pseg >= seg_end) {
614 pseg = segsum.ss_next;
616 (" partial seg oor next is %jx[%jx - %jx]\n",
617 (uintmax_t)pseg, (uintmax_t)seg_start,
618 (uintmax_t)seg_end));
620 segnum = nandfs_get_segnum_of_block(nandfsdev, pseg);
630 nandfs_get_node_raw(struct nandfs_device *nandfsdev, struct nandfsmount *nmp,
631 uint64_t ino, struct nandfs_inode *inode, struct nandfs_node **nodep)
633 struct nandfs_node *node;
640 /* Associate with mountpoint if present */
642 mp = nmp->nm_vfs_mountp;
643 error = getnewvnode("nandfs", mp, &nandfs_vnodeops, &nvp);
648 error = getnewvnode("snandfs", mp, &nandfs_system_vnodeops,
655 NANDFS_WRITELOCK(nandfsdev);
657 DPRINTF(IFILE, ("%s: ino: %#jx -> vp: %p\n",
658 __func__, (uintmax_t)ino, nvp));
660 lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL);
663 error = insmntque(nvp, mp);
670 node = uma_zalloc(nandfs_node_zone, M_WAITOK | M_ZERO);
673 node->nn_vnode = nvp;
674 nvp->v_bufobj.bo_ops = &buf_ops_nandfs;
676 node->nn_nandfsdev = nandfsdev;
679 /* Initiase NANDFS node */
682 node->nn_inode = *inode;
684 nandfs_vinit(nvp, ino);
688 DPRINTF(IFILE, ("%s: ino:%#jx vp:%p node:%p\n",
689 __func__, (uintmax_t)ino, nvp, *nodep));
695 nandfs_get_node(struct nandfsmount *nmp, uint64_t ino,
696 struct nandfs_node **nodep)
698 struct nandfs_device *nandfsdev;
699 struct nandfs_inode inode, *entry;
700 struct vnode *nvp, *vpp;
704 uint32_t entry_in_block;
707 /* Look up node in hash table */
711 if ((ino < NANDFS_ATIME_INO) && (ino != NANDFS_ROOT_INO)) {
712 printf("nandfs_get_node: system ino %"PRIu64" not in mount "
717 error = vfs_hash_get(nmp->nm_vfs_mountp, ino, LK_EXCLUSIVE, td, &nvp,
723 *nodep = (struct nandfs_node *)nvp->v_data;
727 /* Look up inode structure in mountpoints ifile */
728 nandfsdev = nmp->nm_nandfsdev;
729 nandfs_mdt_trans(&nandfsdev->nd_ifile_mdt, ino, &ivblocknr,
732 VOP_LOCK(NTOV(nmp->nm_ifile_node), LK_SHARED);
733 error = nandfs_bread(nmp->nm_ifile_node, ivblocknr, NOCRED, 0, &bp);
736 VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0);
740 /* Get inode entry */
741 entry = (struct nandfs_inode *) bp->b_data + entry_in_block;
742 memcpy(&inode, entry, sizeof(struct nandfs_inode));
744 VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0);
747 error = nandfs_get_node_raw(nmp->nm_nandfsdev, nmp, ino, &inode, nodep);
753 nvp = (*nodep)->nn_vnode;
754 error = vfs_hash_insert(nvp, ino, 0, td, &vpp, NULL, NULL);
764 nandfs_dispose_node(struct nandfs_node **nodep)
766 struct nandfs_node *node;
769 /* Protect against rogue values */
774 DPRINTF(NODE, ("nandfs_dispose_node: %p\n", *nodep));
779 /* Free our associated memory */
780 uma_zfree(nandfs_node_zone, node);
786 nandfs_lookup_name_in_dir(struct vnode *dvp, const char *name, int namelen,
787 uint64_t *ino, int *found, uint64_t *off)
789 struct nandfs_node *dir_node = VTON(dvp);
790 struct nandfs_dir_entry *ndirent;
792 uint64_t file_size, diroffset, blkoff;
794 uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize;
795 uint8_t *pos, name_len;
800 DPRINTF(VNCALL, ("%s: %s file\n", __func__, name));
801 if (dvp->v_type != VDIR) {
805 /* Get directory filesize */
806 file_size = dir_node->nn_inode.i_size;
808 /* Walk the directory */
812 error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp);
818 while (diroffset < file_size) {
819 if (blkoff >= blocksize) {
820 blkoff = 0; blocknr++;
822 error = nandfs_bread(dir_node, blocknr, NOCRED, 0,
830 /* Read in one dirent */
831 pos = (uint8_t *) bp->b_data + blkoff;
832 ndirent = (struct nandfs_dir_entry *) pos;
833 name_len = ndirent->name_len;
835 if ((name_len == namelen) &&
836 (strncmp(name, ndirent->name, name_len) == 0) &&
837 (ndirent->inode != 0)) {
838 *ino = ndirent->inode;
840 DPRINTF(LOOKUP, ("found `%.*s` with ino %"PRIx64"\n",
841 name_len, ndirent->name, *ino));
847 diroffset += ndirent->rec_len;
848 blkoff += ndirent->rec_len;
856 nandfs_get_fsinfo(struct nandfsmount *nmp, struct nandfs_fsinfo *fsinfo)
858 struct nandfs_device *fsdev;
860 fsdev = nmp->nm_nandfsdev;
862 memcpy(&fsinfo->fs_fsdata, &fsdev->nd_fsdata, sizeof(fsdev->nd_fsdata));
863 memcpy(&fsinfo->fs_super, &fsdev->nd_super, sizeof(fsdev->nd_super));
864 snprintf(fsinfo->fs_dev, sizeof(fsinfo->fs_dev),
865 "%s", nmp->nm_vfs_mountp->mnt_stat.f_mntfromname);
871 nandfs_inode_init(struct nandfs_inode *inode, uint16_t mode)
879 inode->i_ctime = ts.tv_sec;
880 inode->i_ctime_nsec = ts.tv_nsec;
881 inode->i_mtime = ts.tv_sec;
882 inode->i_mtime_nsec = ts.tv_nsec;
883 inode->i_mode = mode;
884 inode->i_links_count = 1;
886 inode->i_links_count = 2;
889 inode->i_special = 0;
890 memset(inode->i_db, 0, sizeof(inode->i_db));
891 memset(inode->i_ib, 0, sizeof(inode->i_ib));
895 nandfs_inode_destroy(struct nandfs_inode *inode)
898 MPASS(inode->i_blocks == 0);
899 bzero(inode, sizeof(*inode));
903 nandfs_fs_full(struct nandfs_device *nffsdev)
907 bps = nffsdev->nd_fsdata.f_blocks_per_segment;
908 space = (nffsdev->nd_clean_segs - 1) * bps;
910 DPRINTF(BUF, ("%s: bufs:%jx space:%jx\n", __func__,
911 (uintmax_t)nffsdev->nd_dirty_bufs, (uintmax_t)space));
913 if (nffsdev->nd_dirty_bufs + (nffsdev->nd_segs_reserved * bps) >= space)
920 _nandfs_dirty_buf(struct buf *bp, int dirty_meta, int force)
922 struct nandfs_device *nffsdev;
923 struct nandfs_node *node;
926 if (NANDFS_ISGATHERED(bp)) {
930 if ((bp->b_flags & (B_MANAGED | B_DELWRI)) == (B_MANAGED | B_DELWRI)) {
935 node = VTON(bp->b_vp);
936 nffsdev = node->nn_nandfsdev;
937 DPRINTF(BUF, ("%s: buf:%p\n", __func__, bp));
940 if (nandfs_fs_full(nffsdev) && !NANDFS_SYS_NODE(ino) && !force) {
945 bp->b_flags |= B_MANAGED;
948 nandfs_dirty_bufs_increment(nffsdev);
950 KASSERT((bp->b_vp), ("vp missing for bp"));
951 KASSERT((nandfs_vblk_get(bp) || ino == NANDFS_DAT_INO),
955 * To maintain consistency of FS we need to force making
956 * meta buffers dirty, even if free space is low.
958 if (dirty_meta && ino != NANDFS_GC_INO)
959 nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1);
961 bps = nffsdev->nd_fsdata.f_blocks_per_segment;
963 if (nffsdev->nd_dirty_bufs >= (bps * nandfs_max_dirty_segs)) {
964 mtx_lock(&nffsdev->nd_sync_mtx);
965 if (nffsdev->nd_syncing == 0) {
966 DPRINTF(SYNC, ("%s: wakeup gc\n", __func__));
967 nffsdev->nd_syncing = 1;
968 wakeup(&nffsdev->nd_syncing);
970 mtx_unlock(&nffsdev->nd_sync_mtx);
977 nandfs_dirty_buf(struct buf *bp, int force)
980 return (_nandfs_dirty_buf(bp, 1, force));
984 nandfs_dirty_buf_meta(struct buf *bp, int force)
987 return (_nandfs_dirty_buf(bp, 0, force));
991 nandfs_undirty_buf_fsdev(struct nandfs_device *nffsdev, struct buf *bp)
996 if (bp->b_flags & B_DELWRI) {
997 bp->b_flags &= ~(B_DELWRI|B_MANAGED);
998 nandfs_dirty_bufs_decrement(nffsdev);
1001 * Since it is now being written, we can clear its deferred write flag.
1003 bp->b_flags &= ~B_DEFERRED;
1009 nandfs_undirty_buf(struct buf *bp)
1011 struct nandfs_node *node;
1013 node = VTON(bp->b_vp);
1015 nandfs_undirty_buf_fsdev(node->nn_nandfsdev, bp);
1019 nandfs_vblk_set(struct buf *bp, nandfs_daddr_t blocknr)
1022 nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1);
1027 nandfs_vblk_get(struct buf *bp)
1030 nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1);
1035 nandfs_buf_set(struct buf *bp, uint32_t bits)
1039 flags = (uintptr_t)bp->b_fsprivate3;
1040 flags |= (uintptr_t)bits;
1041 bp->b_fsprivate3 = (void *)flags;
1045 nandfs_buf_clear(struct buf *bp, uint32_t bits)
1049 flags = (uintptr_t)bp->b_fsprivate3;
1050 flags &= ~(uintptr_t)bits;
1051 bp->b_fsprivate3 = (void *)flags;
1055 nandfs_buf_check(struct buf *bp, uint32_t bits)
1059 flags = (uintptr_t)bp->b_fsprivate3;
1066 nandfs_erase(struct nandfs_device *fsdev, off_t offset, size_t size)
1068 DPRINTF(BLOCK, ("%s: performing erase at offset %jx size %zx\n",
1069 __func__, offset, size));
1071 MPASS(size % fsdev->nd_erasesize == 0);
1073 return (g_delete_data(fsdev->nd_gconsumer, offset, size));
1077 nandfs_vop_islocked(struct vnode *vp)
1081 islocked = VOP_ISLOCKED(vp);
1082 return (islocked == LK_EXCLUSIVE || islocked == LK_SHARED);
1086 nandfs_block_to_dblock(struct nandfs_device *fsdev, nandfs_lbn_t block)
1089 return (btodb(block * fsdev->nd_blocksize));