]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/nandfs/nandfs_subr.c
Fix regression in rpc.rquotad with certain NFS servers.
[FreeBSD/FreeBSD.git] / sys / fs / nandfs / nandfs_subr.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2010-2012 Semihalf
5  * Copyright (c) 2008, 2009 Reinoud Zandijk
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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.
16  *
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.
27  *
28  * From: NetBSD: nilfs_subr.c,v 1.4 2009/07/29 17:06:57 reinoud
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
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>
39 #include <sys/file.h>
40 #include <sys/stat.h>
41 #include <sys/buf.h>
42 #include <sys/bio.h>
43 #include <sys/proc.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>
51
52 #include <geom/geom.h>
53 #include <geom/geom_vfs.h>
54
55 #include <vm/vm.h>
56 #include <vm/vm_extern.h>
57
58 #include <machine/_inttypes.h>
59 #include "nandfs_mount.h"
60 #include "nandfs.h"
61 #include "nandfs_subr.h"
62
63 MALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount");
64 MALLOC_DEFINE(M_NANDFSTEMP, "nandfs_tmt", "NANDFS tmp");
65
66 uma_zone_t nandfs_node_zone;
67
68 void nandfs_bdflush(struct bufobj *bo, struct buf *bp);
69 int nandfs_bufsync(struct bufobj *bo, int waitfor);
70
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,
77 };
78
79 int
80 nandfs_bufsync(struct bufobj *bo, int waitfor)
81 {
82         struct vnode *vp;
83         int error = 0;
84
85         vp = bo2vnode(bo);
86
87         ASSERT_VOP_LOCKED(vp, __func__);
88         error = nandfs_sync_file(vp);
89         if (error)
90                 nandfs_warning("%s: cannot flush buffers err:%d\n",
91                     __func__, error);
92
93         return (error);
94 }
95
96 void
97 nandfs_bdflush(bo, bp)
98         struct bufobj *bo;
99         struct buf *bp;
100 {
101         struct vnode *vp;
102         int error;
103
104         if (bo->bo_dirty.bv_cnt <= ((dirtybufthresh * 8) / 10))
105                 return;
106
107         vp = bp->b_vp;
108         if (NANDFS_SYS_NODE(VTON(vp)->nn_ino))
109                 return;
110
111         if (NANDFS_IS_INDIRECT(bp))
112                 return;
113
114         error = nandfs_sync_file(vp);
115         if (error)
116                 nandfs_warning("%s: cannot flush buffers err:%d\n",
117                     __func__, error);
118 }
119
120 int
121 nandfs_init(struct vfsconf *vfsp)
122 {
123
124         nandfs_node_zone = uma_zcreate("nandfs node zone",
125             sizeof(struct nandfs_node), NULL, NULL, NULL, NULL, 0, 0);
126
127         return (0);
128 }
129
130 int
131 nandfs_uninit(struct vfsconf *vfsp)
132 {
133
134         uma_zdestroy(nandfs_node_zone);
135         return (0);
136 }
137
138 /* Basic calculators */
139 uint64_t
140 nandfs_get_segnum_of_block(struct nandfs_device *nandfsdev,
141     nandfs_daddr_t blocknr)
142 {
143         uint64_t segnum, blks_per_seg;
144
145         MPASS(blocknr >= nandfsdev->nd_fsdata.f_first_data_block);
146
147         blks_per_seg = nandfsdev->nd_fsdata.f_blocks_per_segment;
148
149         segnum = blocknr / blks_per_seg;
150         segnum -= nandfsdev->nd_fsdata.f_first_data_block / blks_per_seg;
151
152         DPRINTF(SYNC, ("%s: returning blocknr %jx -> segnum %jx\n", __func__,
153             blocknr, segnum));
154
155         return (segnum);
156 }
157
158 void
159 nandfs_get_segment_range(struct nandfs_device *nandfsdev, uint64_t segnum,
160     uint64_t *seg_start, uint64_t *seg_end)
161 {
162         uint64_t blks_per_seg;
163
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;
167         if (seg_end != NULL)
168                 *seg_end = *seg_start + blks_per_seg -1;
169 }
170
171 void nandfs_calc_mdt_consts(struct nandfs_device *nandfsdev,
172     struct nandfs_mdt *mdt, int entry_size)
173 {
174         uint32_t blocksize = nandfsdev->nd_blocksize;
175
176         mdt->entries_per_group = blocksize * 8;
177         mdt->entries_per_block = blocksize / entry_size;
178
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;
185 }
186
187 int
188 nandfs_dev_bread(struct nandfs_device *nandfsdev, nandfs_lbn_t blocknr,
189     struct ucred *cred, int flags, struct buf **bpp)
190 {
191         int blk2dev = nandfsdev->nd_blocksize / DEV_BSIZE;
192         int error;
193
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);
198         if (error)
199                 nandfs_error("%s: cannot read from device - blk:%jx\n",
200                     __func__, blocknr);
201         return (error);
202 }
203
204 /* Read on a node */
205 int
206 nandfs_bread(struct nandfs_node *node, nandfs_lbn_t blocknr,
207     struct ucred *cred, int flags, struct buf **bpp)
208 {
209         nandfs_daddr_t vblk;
210         int error;
211
212         DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
213             blocknr));
214
215         error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
216             cred, bpp);
217
218         KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__,
219             NTOV(node), blocknr, error));
220
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);
225         }
226         return (error);
227 }
228
229 int
230 nandfs_bread_meta(struct nandfs_node *node, nandfs_lbn_t blocknr,
231     struct ucred *cred, int flags, struct buf **bpp)
232 {
233         nandfs_daddr_t vblk;
234         int error;
235
236         DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
237             blocknr));
238
239         error = bread(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
240             cred, bpp);
241
242         KASSERT(error == 0, ("%s: vp:%p lbn:%#jx err:%d\n", __func__,
243             NTOV(node), blocknr, error));
244
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);
249         }
250
251         return (error);
252 }
253
254 int
255 nandfs_bdestroy(struct nandfs_node *node, nandfs_daddr_t vblk)
256 {
257         int error;
258
259         if (!NANDFS_SYS_NODE(node->nn_ino))
260                 NANDFS_WRITEASSERT(node->nn_nandfsdev);
261
262         error = nandfs_vblock_end(node->nn_nandfsdev, vblk);
263         if (error) {
264                 nandfs_error("%s: ending vblk: %jx failed\n",
265                     __func__, (uintmax_t)vblk);
266                 return (error);
267         }
268         node->nn_inode.i_blocks--;
269
270         return (0);
271 }
272
273 int
274 nandfs_bcreate(struct nandfs_node *node, nandfs_lbn_t blocknr,
275     struct ucred *cred, int flags, struct buf **bpp)
276 {
277         int error;
278
279         ASSERT_VOP_LOCKED(NTOV(node), __func__);
280         if (!NANDFS_SYS_NODE(node->nn_ino))
281                 NANDFS_WRITEASSERT(node->nn_nandfsdev);
282
283         DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
284             blocknr));
285
286         *bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
287             0, 0, 0);
288
289         KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__,
290             NTOV(node), blocknr));
291
292         if (*bpp) {
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);
296                 if (error) {
297                         nandfs_warning("%s: failed bmap insert node:%p"
298                             " blk:%jx\n", __func__, node, blocknr);
299                         brelse(*bpp);
300                         return (error);
301                 }
302                 node->nn_inode.i_blocks++;
303
304                 return (0);
305         }
306
307         return (-1);
308 }
309
310 int
311 nandfs_bcreate_meta(struct nandfs_node *node, nandfs_lbn_t blocknr,
312     struct ucred *cred, int flags, struct buf **bpp)
313 {
314         struct nandfs_device *fsdev;
315         nandfs_daddr_t vblk;
316         int error;
317
318         ASSERT_VOP_LOCKED(NTOV(node), __func__);
319         NANDFS_WRITEASSERT(node->nn_nandfsdev);
320
321         DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node),
322             blocknr));
323
324         fsdev = node->nn_nandfsdev;
325
326         *bpp = getblk(NTOV(node), blocknr, node->nn_nandfsdev->nd_blocksize,
327             0, 0, 0);
328
329         KASSERT((*bpp), ("%s: vp:%p lbn:%#jx\n", __func__,
330             NTOV(node), blocknr));
331
332         memset((*bpp)->b_data, 0, fsdev->nd_blocksize);
333
334         vfs_bio_clrbuf(*bpp);
335         (*bpp)->b_blkno = ~(0); /* To avoid VOP_BMAP in bdwrite */
336
337         nandfs_buf_set(*bpp, NANDFS_VBLK_ASSIGNED);
338
339         if (node->nn_ino != NANDFS_DAT_INO) {
340                 error = nandfs_vblock_alloc(fsdev, &vblk);
341                 if (error) {
342                         nandfs_buf_clear(*bpp, NANDFS_VBLK_ASSIGNED);
343                         brelse(*bpp);
344                         return (error);
345                 }
346         } else
347                 vblk = fsdev->nd_fakevblk++;
348
349         nandfs_vblk_set(*bpp, vblk);
350
351         nandfs_bmap_insert_block(node, blocknr, *bpp);
352         return (0);
353 }
354
355 /* Translate index to a file block number and an entry */
356 void
357 nandfs_mdt_trans(struct nandfs_mdt *mdt, uint64_t index,
358     nandfs_lbn_t *blocknr, uint32_t *entry_in_block)
359 {
360         uint64_t blknr;
361         uint64_t group, group_offset, blocknr_in_group;
362         uint64_t desc_block, desc_offset;
363
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;
370
371         /* To descgroup offset */
372         blknr = 1 + desc_block * mdt->blocks_per_desc_block;
373
374         /* To group offset */
375         blknr += desc_offset * mdt->blocks_per_group;
376
377         /* To actual file block */
378         blknr += 1 + blocknr_in_group;
379
380         *blocknr = blknr;
381         *entry_in_block = group_offset % mdt->entries_per_block;
382 }
383
384 void
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)
388 {
389         uint64_t blknr;
390         uint64_t group, group_offset, blocknr_in_group;
391         uint64_t desc_block, desc_offset;
392
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;
399
400         /* To descgroup offset */
401         *desc = desc_block * mdt->blocks_per_desc_block;
402         blknr = 1 + desc_block * mdt->blocks_per_desc_block;
403
404         /* To group offset */
405         blknr += desc_offset * mdt->blocks_per_group;
406         *bitmap = blknr;
407
408         /* To actual file block */
409         blknr += 1 + blocknr_in_group;
410
411         *blocknr = blknr;
412         *entry_in_block = group_offset % mdt->entries_per_block;
413
414         DPRINTF(ALLOC,
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));
418 }
419
420 int
421 nandfs_vtop(struct nandfs_node *node, nandfs_daddr_t vblocknr,
422     nandfs_daddr_t *pblocknr)
423 {
424         struct nandfs_node *dat_node;
425         struct nandfs_dat_entry *entry;
426         struct buf *bp;
427         nandfs_lbn_t ldatblknr;
428         uint32_t entry_in_block;
429         int locked, error;
430
431         if (node->nn_ino == NANDFS_DAT_INO || node->nn_ino == NANDFS_GC_INO) {
432                 *pblocknr = vblocknr;
433                 return (0);
434         }
435
436         /* only translate valid vblocknrs */
437         if (vblocknr == 0)
438                 return (0);
439
440         dat_node = node->nn_nandfsdev->nd_dat_node;
441         nandfs_mdt_trans(&node->nn_nandfsdev->nd_dat_mdt, vblocknr, &ldatblknr,
442             &entry_in_block);
443
444         locked = NANDFS_VOP_ISLOCKED(NTOV(dat_node));
445         if (!locked)
446                 VOP_LOCK(NTOV(dat_node), LK_SHARED);
447         error = nandfs_bread(dat_node, ldatblknr, NOCRED, 0, &bp);
448         if (error) {
449                 DPRINTF(TRANSLATE, ("vtop: can't read in DAT block %#jx!\n",
450                     (uintmax_t)ldatblknr));
451                 brelse(bp);
452                 VOP_UNLOCK(NTOV(dat_node), 0);
453                 return (error);
454         }
455
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));
463
464         *pblocknr = entry->de_blocknr;
465         brelse(bp);
466         if (!locked)
467                 VOP_UNLOCK(NTOV(dat_node), 0);
468
469         MPASS(*pblocknr >= node->nn_nandfsdev->nd_fsdata.f_first_data_block ||
470             *pblocknr == 0);
471
472         return (0);
473 }
474
475 int
476 nandfs_segsum_valid(struct nandfs_segment_summary *segsum)
477 {
478
479         return (segsum->ss_magic == NANDFS_SEGSUM_MAGIC);
480 }
481
482 int
483 nandfs_load_segsum(struct nandfs_device *fsdev, nandfs_daddr_t blocknr,
484     struct nandfs_segment_summary *segsum)
485 {
486         struct buf *bp;
487         int error;
488
489         DPRINTF(VOLUMES, ("nandfs: try segsum at block %jx\n",
490             (uintmax_t)blocknr));
491
492         error = nandfs_dev_bread(fsdev, blocknr, NOCRED, 0, &bp);
493         if (error)
494                 return (error);
495
496         memcpy(segsum, bp->b_data, sizeof(struct nandfs_segment_summary));
497         brelse(bp);
498
499         if (!nandfs_segsum_valid(segsum)) {
500                 DPRINTF(VOLUMES, ("%s: bad magic pseg:%jx\n", __func__,
501                     blocknr));
502                 return (EINVAL);
503         }
504
505         return (error);
506 }
507
508 static int
509 nandfs_load_super_root(struct nandfs_device *nandfsdev,
510     struct nandfs_segment_summary *segsum, uint64_t pseg)
511 {
512         struct nandfs_super_root super_root;
513         struct buf *bp;
514         uint64_t blocknr;
515         uint32_t super_root_crc, comp_crc;
516         int off, error;
517
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__,
521                     pseg));
522                 return (ENOENT);
523         }
524
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));
528
529         error = nandfs_dev_bread(nandfsdev, blocknr, NOCRED, 0, &bp);
530         if (error)
531                 return (error);
532
533         memcpy(&super_root, bp->b_data, sizeof(struct nandfs_super_root));
534         brelse(bp);
535
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);
541
542         if (super_root_crc != comp_crc) {
543                 DPRINTF(VOLUMES, ("%s: invalid crc:%#x [expect:%#x]\n",
544                     __func__, super_root_crc, comp_crc));
545                 return (EINVAL);
546         }
547
548         nandfsdev->nd_super_root = super_root;
549         DPRINTF(VOLUMES, ("%s: got valid superroot\n", __func__));
550
551         return (0);
552 }
553
554 /*
555  * Search for the last super root recorded.
556  */
557 int
558 nandfs_search_super_root(struct nandfs_device *nandfsdev)
559 {
560         struct nandfs_super_block *super;
561         struct nandfs_segment_summary segsum;
562         uint64_t seg_start, seg_end, cno, seq, create, pseg;
563         uint64_t segnum;
564         int error, found;
565
566         error = found = 0;
567
568         /* Search for last super root */
569         pseg = nandfsdev->nd_super.s_last_pseg;
570         segnum = nandfs_get_segnum_of_block(nandfsdev, pseg);
571
572         cno = nandfsdev->nd_super.s_last_cno;
573         create = seq = 0;
574         DPRINTF(VOLUMES, ("%s: start in pseg %#jx\n", __func__,
575             (uintmax_t)pseg));
576
577         for (;;) {
578                 error = nandfs_load_segsum(nandfsdev, pseg, &segsum);
579                 if (error)
580                         break;
581
582                 if (segsum.ss_seq < seq || segsum.ss_create < create)
583                         break;
584
585                 /* Try to load super root */
586                 if (segsum.ss_flags & NANDFS_SS_SR) {
587                         error = nandfs_load_super_root(nandfsdev, &segsum, pseg);
588                         if (error)
589                                 break;  /* confused */
590                         found = 1;
591
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;
598                         seq = segsum.ss_seq;
599                         create = segsum.ss_create;
600                 } else {
601                         seq = segsum.ss_seq;
602                         create = segsum.ss_create;
603                 }
604
605                 /* Calculate next partial segment location */
606                 pseg += segsum.ss_nblocks;
607                 DPRINTF(VOLUMES, ("%s: next partial seg is %jx\n", __func__,
608                     (uintmax_t)pseg));
609
610                 /* Did we reach the end of the segment? if so, go to the next */
611                 nandfs_get_segment_range(nandfsdev, segnum, &seg_start,
612                     &seg_end);
613                 if (pseg >= seg_end) {
614                         pseg = segsum.ss_next;
615                         DPRINTF(VOLUMES,
616                             (" partial seg oor next is %jx[%jx - %jx]\n",
617                             (uintmax_t)pseg, (uintmax_t)seg_start,
618                             (uintmax_t)seg_end));
619                 }
620                 segnum = nandfs_get_segnum_of_block(nandfsdev, pseg);
621         }
622
623         if (error && !found)
624                 return (error);
625
626         return (0);
627 }
628
629 int
630 nandfs_get_node_raw(struct nandfs_device *nandfsdev, struct nandfsmount *nmp,
631     uint64_t ino, struct nandfs_inode *inode, struct nandfs_node **nodep)
632 {
633         struct nandfs_node *node;
634         struct vnode *nvp;
635         struct mount *mp;
636         int error;
637
638         *nodep = NULL;
639
640         /* Associate with mountpoint if present */
641         if (nmp) {
642                 mp = nmp->nm_vfs_mountp;
643                 error = getnewvnode("nandfs", mp, &nandfs_vnodeops, &nvp);
644                 if (error)
645                         return (error);
646         } else {
647                 mp = NULL;
648                 error = getnewvnode("snandfs", mp, &nandfs_system_vnodeops,
649                     &nvp);
650                 if (error)
651                         return (error);
652         }
653
654         if (mp)
655                 NANDFS_WRITELOCK(nandfsdev);
656
657         DPRINTF(IFILE, ("%s: ino: %#jx -> vp: %p\n",
658             __func__, (uintmax_t)ino, nvp));
659         /* Lock node */
660         lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL);
661
662         if (mp) {
663                 error = insmntque(nvp, mp);
664                 if (error != 0) {
665                         *nodep = NULL;
666                         return (error);
667                 }
668         }
669
670         node = uma_zalloc(nandfs_node_zone, M_WAITOK | M_ZERO);
671
672         /* Crosslink */
673         node->nn_vnode = nvp;
674         nvp->v_bufobj.bo_ops = &buf_ops_nandfs;
675         node->nn_nmp = nmp;
676         node->nn_nandfsdev = nandfsdev;
677         nvp->v_data = node;
678
679         /* Initiase NANDFS node */
680         node->nn_ino = ino;
681         if (inode != NULL)
682                 node->nn_inode = *inode;
683
684         nandfs_vinit(nvp, ino);
685
686         /* Return node */
687         *nodep = node;
688         DPRINTF(IFILE, ("%s: ino:%#jx vp:%p node:%p\n",
689             __func__, (uintmax_t)ino, nvp, *nodep));
690
691         return (0);
692 }
693
694 int
695 nandfs_get_node(struct nandfsmount *nmp, uint64_t ino,
696     struct nandfs_node **nodep)
697 {
698         struct nandfs_device *nandfsdev;
699         struct nandfs_inode inode, *entry;
700         struct vnode *nvp, *vpp;
701         struct thread *td;
702         struct buf *bp;
703         uint64_t ivblocknr;
704         uint32_t entry_in_block;
705         int error;
706
707         /* Look up node in hash table */
708         td = curthread;
709         *nodep = NULL;
710
711         if ((ino < NANDFS_ATIME_INO) && (ino != NANDFS_ROOT_INO)) {
712                 printf("nandfs_get_node: system ino %"PRIu64" not in mount "
713                     "point!\n", ino);
714                 return (ENOENT);
715         }
716
717         error = vfs_hash_get(nmp->nm_vfs_mountp, ino, LK_EXCLUSIVE, td, &nvp,
718             NULL, NULL);
719         if (error)
720                 return (error);
721
722         if (nvp != NULL) {
723                 *nodep = (struct nandfs_node *)nvp->v_data;
724                 return (0);
725         }
726
727         /* Look up inode structure in mountpoints ifile */
728         nandfsdev = nmp->nm_nandfsdev;
729         nandfs_mdt_trans(&nandfsdev->nd_ifile_mdt, ino, &ivblocknr,
730             &entry_in_block);
731
732         VOP_LOCK(NTOV(nmp->nm_ifile_node), LK_SHARED);
733         error = nandfs_bread(nmp->nm_ifile_node, ivblocknr, NOCRED, 0, &bp);
734         if (error) {
735                 brelse(bp);
736                 VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0);
737                 return (ENOENT);
738         }
739
740         /* Get inode entry */
741         entry = (struct nandfs_inode *) bp->b_data + entry_in_block;
742         memcpy(&inode, entry, sizeof(struct nandfs_inode));
743         brelse(bp);
744         VOP_UNLOCK(NTOV(nmp->nm_ifile_node), 0);
745
746         /* Get node */
747         error = nandfs_get_node_raw(nmp->nm_nandfsdev, nmp, ino, &inode, nodep);
748         if (error) {
749                 *nodep = NULL;
750                 return (error);
751         }
752
753         nvp = (*nodep)->nn_vnode;
754         error = vfs_hash_insert(nvp, ino, 0, td, &vpp, NULL, NULL);
755         if (error) {
756                 *nodep = NULL;
757                 return (error);
758         }
759
760         return (error);
761 }
762
763 void
764 nandfs_dispose_node(struct nandfs_node **nodep)
765 {
766         struct nandfs_node *node;
767         struct vnode *vp;
768
769         /* Protect against rogue values */
770         node = *nodep;
771         if (!node) {
772                 return;
773         }
774         DPRINTF(NODE, ("nandfs_dispose_node: %p\n", *nodep));
775
776         vp = NTOV(node);
777         vp->v_data = NULL;
778
779         /* Free our associated memory */
780         uma_zfree(nandfs_node_zone, node);
781
782         *nodep = NULL;
783 }
784
785 int
786 nandfs_lookup_name_in_dir(struct vnode *dvp, const char *name, int namelen,
787     uint64_t *ino, int *found, uint64_t *off)
788 {
789         struct nandfs_node *dir_node = VTON(dvp);
790         struct nandfs_dir_entry *ndirent;
791         struct buf *bp;
792         uint64_t file_size, diroffset, blkoff;
793         uint64_t blocknr;
794         uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize;
795         uint8_t *pos, name_len;
796         int error;
797
798         *found = 0;
799
800         DPRINTF(VNCALL, ("%s: %s file\n", __func__, name));
801         if (dvp->v_type != VDIR) {
802                 return (ENOTDIR);
803         }
804
805         /* Get directory filesize */
806         file_size = dir_node->nn_inode.i_size;
807
808         /* Walk the directory */
809         diroffset = 0;
810         blocknr = 0;
811         blkoff = 0;
812         error = nandfs_bread(dir_node, blocknr, NOCRED, 0, &bp);
813         if (error) {
814                 brelse(bp);
815                 return (EIO);
816         }
817
818         while (diroffset < file_size) {
819                 if (blkoff >= blocksize) {
820                         blkoff = 0; blocknr++;
821                         brelse(bp);
822                         error = nandfs_bread(dir_node, blocknr, NOCRED, 0,
823                             &bp);
824                         if (error) {
825                                 brelse(bp);
826                                 return (EIO);
827                         }
828                 }
829
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;
834
835                 if ((name_len == namelen) &&
836                     (strncmp(name, ndirent->name, name_len) == 0) &&
837                     (ndirent->inode != 0)) {
838                         *ino = ndirent->inode;
839                         *off = diroffset;
840                         DPRINTF(LOOKUP, ("found `%.*s` with ino %"PRIx64"\n",
841                             name_len, ndirent->name, *ino));
842                         *found = 1;
843                         break;
844                 }
845
846                 /* Advance */
847                 diroffset += ndirent->rec_len;
848                 blkoff += ndirent->rec_len;
849         }
850         brelse(bp);
851
852         return (error);
853 }
854
855 int
856 nandfs_get_fsinfo(struct nandfsmount *nmp, struct nandfs_fsinfo *fsinfo)
857 {
858         struct nandfs_device *fsdev;
859
860         fsdev = nmp->nm_nandfsdev;
861
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);
866
867         return (0);
868 }
869
870 void
871 nandfs_inode_init(struct nandfs_inode *inode, uint16_t mode)
872 {
873         struct timespec ts;
874
875         vfs_timestamp(&ts);
876
877         inode->i_blocks = 0;
878         inode->i_size = 0;
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;
885         if (S_ISDIR(mode))
886                 inode->i_links_count = 2;
887         inode->i_flags = 0;
888
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));
892 }
893
894 void
895 nandfs_inode_destroy(struct nandfs_inode *inode)
896 {
897
898         MPASS(inode->i_blocks == 0);
899         bzero(inode, sizeof(*inode));
900 }
901
902 int
903 nandfs_fs_full(struct nandfs_device *nffsdev)
904 {
905         uint64_t space, bps;
906
907         bps = nffsdev->nd_fsdata.f_blocks_per_segment;
908         space = (nffsdev->nd_clean_segs - 1) * bps;
909
910         DPRINTF(BUF, ("%s: bufs:%jx space:%jx\n", __func__,
911             (uintmax_t)nffsdev->nd_dirty_bufs, (uintmax_t)space));
912
913         if (nffsdev->nd_dirty_bufs + (nffsdev->nd_segs_reserved * bps) >= space)
914                 return (1);
915
916         return (0);
917 }
918
919 static int
920 _nandfs_dirty_buf(struct buf *bp, int dirty_meta, int force)
921 {
922         struct nandfs_device *nffsdev;
923         struct nandfs_node *node;
924         uint64_t ino, bps;
925
926         if (NANDFS_ISGATHERED(bp)) {
927                 bqrelse(bp);
928                 return (0);
929         }
930         if ((bp->b_flags & (B_MANAGED | B_DELWRI)) == (B_MANAGED | B_DELWRI)) {
931                 bqrelse(bp);
932                 return (0);
933         }
934
935         node = VTON(bp->b_vp);
936         nffsdev = node->nn_nandfsdev;
937         DPRINTF(BUF, ("%s: buf:%p\n", __func__, bp));
938         ino = node->nn_ino;
939
940         if (nandfs_fs_full(nffsdev) && !NANDFS_SYS_NODE(ino) && !force) {
941                 brelse(bp);
942                 return (ENOSPC);
943         }
944
945         bp->b_flags |= B_MANAGED;
946         bdwrite(bp);
947
948         nandfs_dirty_bufs_increment(nffsdev);
949
950         KASSERT((bp->b_vp), ("vp missing for bp"));
951         KASSERT((nandfs_vblk_get(bp) || ino == NANDFS_DAT_INO),
952             ("bp vblk is 0"));
953
954         /*
955          * To maintain consistency of FS we need to force making
956          * meta buffers dirty, even if free space is low.
957          */
958         if (dirty_meta && ino != NANDFS_GC_INO)
959                 nandfs_bmap_dirty_blocks(VTON(bp->b_vp), bp, 1);
960
961         bps = nffsdev->nd_fsdata.f_blocks_per_segment;
962
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);
969                 }
970                 mtx_unlock(&nffsdev->nd_sync_mtx);
971         }
972
973         return (0);
974 }
975
976 int
977 nandfs_dirty_buf(struct buf *bp, int force)
978 {
979
980         return (_nandfs_dirty_buf(bp, 1, force));
981 }
982
983 int
984 nandfs_dirty_buf_meta(struct buf *bp, int force)
985 {
986
987         return (_nandfs_dirty_buf(bp, 0, force));
988 }
989
990 void
991 nandfs_undirty_buf_fsdev(struct nandfs_device *nffsdev, struct buf *bp)
992 {
993
994         BUF_ASSERT_HELD(bp);
995
996         if (bp->b_flags & B_DELWRI) {
997                 bp->b_flags &= ~(B_DELWRI|B_MANAGED);
998                 nandfs_dirty_bufs_decrement(nffsdev);
999         }
1000         /*
1001          * Since it is now being written, we can clear its deferred write flag.
1002          */
1003         bp->b_flags &= ~B_DEFERRED;
1004
1005         brelse(bp);
1006 }
1007
1008 void
1009 nandfs_undirty_buf(struct buf *bp)
1010 {
1011         struct nandfs_node *node;
1012
1013         node = VTON(bp->b_vp);
1014
1015         nandfs_undirty_buf_fsdev(node->nn_nandfsdev, bp);
1016 }
1017
1018 void
1019 nandfs_vblk_set(struct buf *bp, nandfs_daddr_t blocknr)
1020 {
1021
1022         nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1);
1023         *vblk = blocknr;
1024 }
1025
1026 nandfs_daddr_t
1027 nandfs_vblk_get(struct buf *bp)
1028 {
1029
1030         nandfs_daddr_t *vblk = (nandfs_daddr_t *)(&bp->b_fsprivate1);
1031         return (*vblk);
1032 }
1033
1034 void
1035 nandfs_buf_set(struct buf *bp, uint32_t bits)
1036 {
1037         uintptr_t flags;
1038
1039         flags = (uintptr_t)bp->b_fsprivate3;
1040         flags |= (uintptr_t)bits;
1041         bp->b_fsprivate3 = (void *)flags;
1042 }
1043
1044 void
1045 nandfs_buf_clear(struct buf *bp, uint32_t bits)
1046 {
1047         uintptr_t flags;
1048
1049         flags = (uintptr_t)bp->b_fsprivate3;
1050         flags &= ~(uintptr_t)bits;
1051         bp->b_fsprivate3 = (void *)flags;
1052 }
1053
1054 int
1055 nandfs_buf_check(struct buf *bp, uint32_t bits)
1056 {
1057         uintptr_t flags;
1058
1059         flags = (uintptr_t)bp->b_fsprivate3;
1060         if (flags & bits)
1061                 return (1);
1062         return (0);
1063 }
1064
1065 int
1066 nandfs_erase(struct nandfs_device *fsdev, off_t offset, size_t size)
1067 {
1068         DPRINTF(BLOCK, ("%s: performing erase at offset %jx size %zx\n",
1069             __func__, offset, size));
1070
1071         MPASS(size % fsdev->nd_erasesize == 0);
1072
1073         return (g_delete_data(fsdev->nd_gconsumer, offset, size));
1074 }
1075
1076 int
1077 nandfs_vop_islocked(struct vnode *vp)
1078 {
1079         int islocked;
1080
1081         islocked = VOP_ISLOCKED(vp);
1082         return (islocked == LK_EXCLUSIVE || islocked == LK_SHARED);
1083 }
1084
1085 nandfs_daddr_t
1086 nandfs_block_to_dblock(struct nandfs_device *fsdev, nandfs_lbn_t block)
1087 {
1088
1089         return (btodb(block * fsdev->nd_blocksize));
1090 }