2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2012 Semihalf
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/namei.h>
34 #include <sys/kernel.h>
39 #include <sys/mount.h>
40 #include <sys/vnode.h>
41 #include <sys/signalvar.h>
42 #include <sys/malloc.h>
43 #include <sys/dirent.h>
44 #include <sys/lockf.h>
49 #include <vm/vm_extern.h>
50 #include <vm/vm_object.h>
51 #include <vm/vnode_pager.h>
53 #include <machine/_inttypes.h>
56 #include <vm/vm_extern.h>
57 #include <vm/vm_object.h>
58 #include <vm/vnode_pager.h>
60 #include "nandfs_mount.h"
62 #include "nandfs_subr.h"
65 static int bmap_getlbns(struct nandfs_node *, nandfs_lbn_t,
66 struct nandfs_indir *, int *);
69 bmap_lookup(struct nandfs_node *node, nandfs_lbn_t lblk, nandfs_daddr_t *vblk)
71 struct nandfs_inode *ip;
72 struct nandfs_indir a[NANDFS_NIADDR + 1], *ap;
78 DPRINTF(BMAP, ("%s: node %p lblk %jx enter\n", __func__, node, lblk));
84 error = bmap_getlbns(node, lblk, ap, nump);
89 *vblk = ip->i_db[lblk];
93 DPRINTF(BMAP, ("%s: node %p lblk=%jx trying ip->i_ib[%x]\n", __func__,
94 node, lblk, ap->in_off));
95 daddr = ip->i_ib[ap->in_off];
96 for (bp = NULL, ++ap; --num; ap++) {
98 DPRINTF(BMAP, ("%s: node %p lblk=%jx returning with "
99 "vblk 0\n", __func__, node, lblk));
103 if (ap->in_lbn == lblk) {
104 DPRINTF(BMAP, ("%s: node %p lblk=%jx ap->in_lbn=%jx "
105 "returning address of indirect block (%jx)\n",
106 __func__, node, lblk, ap->in_lbn, daddr));
111 DPRINTF(BMAP, ("%s: node %p lblk=%jx reading block "
112 "ap->in_lbn=%jx\n", __func__, node, lblk, ap->in_lbn));
114 error = nandfs_bread_meta(node, ap->in_lbn, NOCRED, 0, &bp);
120 daddr = ((nandfs_daddr_t *)bp->b_data)[ap->in_off];
124 DPRINTF(BMAP, ("%s: node %p lblk=%jx returning with %jx\n", __func__,
132 bmap_dirty_meta(struct nandfs_node *node, nandfs_lbn_t lblk, int force)
134 struct nandfs_indir a[NANDFS_NIADDR+1], *ap;
136 nandfs_daddr_t daddr;
142 DPRINTF(BMAP, ("%s: node %p lblk=%jx\n", __func__, node, lblk));
147 error = bmap_getlbns(node, lblk, ap, nump);
152 * Direct block, nothing to do
157 DPRINTF(BMAP, ("%s: node %p reading blocks\n", __func__, node));
159 for (bp = NULL, ++ap; --num; ap++) {
160 error = nandfs_bread_meta(node, ap->in_lbn, NOCRED, 0, &bp);
167 daddr = ((nandfs_daddr_t *)bp->b_data)[ap->in_off];
168 MPASS(daddr != 0 || node->nn_ino == 3);
171 error = nandfs_dirty_buf_meta(bp, force);
180 bmap_insert_block(struct nandfs_node *node, nandfs_lbn_t lblk,
183 struct nandfs_inode *ip;
184 struct nandfs_indir a[NANDFS_NIADDR+1], *ap;
186 nandfs_daddr_t daddr;
190 DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx\n", __func__, node, lblk,
193 ip = &node->nn_inode;
198 error = bmap_getlbns(node, lblk, ap, nump);
202 DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx got num=%d\n", __func__,
203 node, lblk, vblk, num));
206 DPRINTF(BMAP, ("%s: node %p lblk=%jx direct block\n", __func__,
208 ip->i_db[lblk] = vblk;
212 DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block level %d\n",
213 __func__, node, lblk, ap->in_off));
216 DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block: inserting "
217 "%jx as vblk for indirect block %d\n", __func__, node,
218 lblk, vblk, ap->in_off));
219 ip->i_ib[ap->in_off] = vblk;
224 daddr = ip->i_ib[a[0].in_off];
225 for (i = 1; i < num; i++) {
229 DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx create "
230 "block %jx %d\n", __func__, node, lblk, vblk,
231 a[i].in_lbn, a[i].in_off));
232 error = nandfs_bcreate_meta(node, a[i].in_lbn, NOCRED,
237 DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx read "
238 "block %jx %d\n", __func__, node, daddr, vblk,
239 a[i].in_lbn, a[i].in_off));
240 error = nandfs_bread_meta(node, a[i].in_lbn, NOCRED, 0, &bp);
246 daddr = ((nandfs_daddr_t *)bp->b_data)[a[i].in_off];
251 ("%s: bmap node %p lblk=%jx vblk=%jx inserting vblk level %d at "
252 "offset %d at %jx\n", __func__, node, lblk, vblk, i, a[i].in_off,
256 nandfs_error("%s: cannot find indirect block\n", __func__);
259 ((nandfs_daddr_t *)bp->b_data)[a[i].in_off] = vblk;
261 error = nandfs_dirty_buf_meta(bp, 0);
263 nandfs_warning("%s: dirty failed buf: %p\n", __func__, bp);
266 DPRINTF(BMAP, ("%s: exiting node %p lblk=%jx vblk=%jx\n", __func__,
272 CTASSERT(NANDFS_NIADDR <= 3);
273 #define SINGLE 0 /* index of single indirect block */
274 #define DOUBLE 1 /* index of double indirect block */
275 #define TRIPLE 2 /* index of triple indirect block */
277 static __inline nandfs_lbn_t
278 lbn_offset(struct nandfs_device *fsdev, int level)
282 for (res = 1; level > 0; level--)
283 res *= MNINDIR(fsdev);
288 blocks_inside(struct nandfs_device *fsdev, int level, struct nandfs_indir *nip)
292 for (blocks = 1; level >= SINGLE; level--, nip++) {
293 MPASS(nip->in_off >= 0 && nip->in_off < MNINDIR(fsdev));
294 blocks += nip->in_off * lbn_offset(fsdev, level);
301 bmap_truncate_indirect(struct nandfs_node *node, int level, nandfs_lbn_t *left,
302 int *cleaned, struct nandfs_indir *ap, struct nandfs_indir *fp,
303 nandfs_daddr_t *copy)
306 nandfs_lbn_t i, lbn, nlbn, factor, tosub;
307 struct nandfs_device *fsdev;
308 int error, lcleaned, modified;
310 DPRINTF(BMAP, ("%s: node %p level %d left %jx\n", __func__,
311 node, level, *left));
313 fsdev = node->nn_nandfsdev;
315 MPASS(ap->in_off >= 0 && ap->in_off < MNINDIR(fsdev));
317 factor = lbn_offset(fsdev, level);
320 error = nandfs_bread_meta(node, lbn, NOCRED, 0, &bp);
327 bcopy(bp->b_data, copy, fsdev->nd_blocksize);
336 for (nlbn = lbn + 1 - i * factor; i >= 0 && *left > 0; i--,
341 ("%s: node %p i=%jx nlbn=%jx left=%jx ap=%p vblk %jx\n",
342 __func__, node, i, nlbn, *left, ap, copy[i]));
345 tosub = blocks_inside(fsdev, level - 1, ap);
351 if (level > SINGLE) {
355 error = bmap_truncate_indirect(node, level - 1,
356 left, &lcleaned, ap, fp,
357 copy + MNINDIR(fsdev));
361 error = nandfs_bdestroy(node, copy[i]);
370 if (level > SINGLE) {
371 error = nandfs_vblock_end(fsdev, copy[i]);
385 error = nandfs_bread_meta(node, lbn, NOCRED, 0, &bp);
391 bcopy(copy, bp->b_data, fsdev->nd_blocksize);
393 /* Force success even if we can't dirty the buffer metadata when freeing space */
394 nandfs_dirty_buf_meta(bp, 1);
400 bmap_truncate_mapping(struct nandfs_node *node, nandfs_lbn_t lastblk,
403 struct nandfs_inode *ip;
404 struct nandfs_indir a[NANDFS_NIADDR + 1], f[NANDFS_NIADDR], *ap;
405 nandfs_daddr_t indir_lbn[NANDFS_NIADDR];
406 nandfs_daddr_t *copy;
408 nandfs_lbn_t left, tosub;
409 struct nandfs_device *fsdev;
413 DPRINTF(BMAP, ("%s: node %p lastblk %jx truncating by %jx\n", __func__,
414 node, lastblk, todo));
416 ip = &node->nn_inode;
417 fsdev = node->nn_nandfsdev;
422 error = bmap_getlbns(node, lastblk, ap, nump);
426 indir_lbn[SINGLE] = -NANDFS_NDADDR;
427 indir_lbn[DOUBLE] = indir_lbn[SINGLE] - MNINDIR(fsdev) - 1;
428 indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - MNINDIR(fsdev)
429 * MNINDIR(fsdev) - 1;
431 for (i = 0; i < NANDFS_NIADDR; i++) {
432 f[i].in_off = MNINDIR(fsdev) - 1;
433 f[i].in_lbn = 0xdeadbeef;
448 copy = malloc(MNINDIR(fsdev) * sizeof(nandfs_daddr_t) * (num + 1),
449 M_NANDFSTEMP, M_WAITOK);
451 for (level = num; level >= SINGLE && left > 0; level--) {
454 if (ip->i_ib[level] == 0) {
455 tosub = blocks_inside(fsdev, level, ap);
462 ap->in_lbn = indir_lbn[level];
463 error = bmap_truncate_indirect(node, level, &left,
464 &cleaned, ap, f, copy);
466 free(copy, M_NANDFSTEMP);
467 nandfs_error("%s: error %d when truncate "
468 "at level %d\n", __func__, error, level);
474 nandfs_vblock_end(fsdev, ip->i_ib[level]);
481 free(copy, M_NANDFSTEMP);
487 i = NANDFS_NDADDR - 1;
489 for (; i >= 0 && left > 0; i--) {
490 if (ip->i_db[i] != 0) {
491 error = nandfs_bdestroy(node, ip->i_db[i]);
493 nandfs_error("%s: cannot destroy "
494 "block %jx, error %d\n", __func__,
495 (uintmax_t)ip->i_db[i], error);
505 ("truncated wrong number of blocks (%jd should be 0)", left));
511 get_maxfilesize(struct nandfs_device *fsdev)
513 struct nandfs_indir f[NANDFS_NIADDR];
519 for (i = 0; i < NANDFS_NIADDR; i++) {
520 f[i].in_off = MNINDIR(fsdev) - 1;
521 max += blocks_inside(fsdev, i, f);
524 max *= fsdev->nd_blocksize;
530 * This is ufs_getlbns with minor modifications.
533 * Create an array of logical block number/offset pairs which represent the
534 * path of indirect blocks required to access a data block. The first "pair"
535 * contains the logical block number of the appropriate single, double or
536 * triple indirect block and the offset into the inode indirect block array.
537 * Note, the logical block number of the inode single/double/triple indirect
538 * block appears twice in the array, once with the offset into the i_ib and
539 * once with the offset into the page itself.
542 bmap_getlbns(struct nandfs_node *node, nandfs_lbn_t bn, struct nandfs_indir *ap, int *nump)
544 nandfs_daddr_t blockcnt;
545 nandfs_lbn_t metalbn, realbn;
546 struct nandfs_device *fsdev;
547 int i, numlevels, off;
549 fsdev = node->nn_nandfsdev;
551 DPRINTF(BMAP, ("%s: node %p bn=%jx mnindir=%zd enter\n", __func__,
552 node, bn, MNINDIR(fsdev)));
562 /* The first NANDFS_NDADDR blocks are direct blocks. */
563 if (bn < NANDFS_NDADDR)
567 * Determine the number of levels of indirection. After this loop
568 * is done, blockcnt indicates the number of data blocks possible
569 * at the previous level of indirection, and NANDFS_NIADDR - i is the
570 * number of levels of indirection needed to locate the requested block.
572 for (blockcnt = 1, i = NANDFS_NIADDR, bn -= NANDFS_NDADDR;; i--, bn -= blockcnt) {
573 DPRINTF(BMAP, ("%s: blockcnt=%jd i=%d bn=%jd\n", __func__,
577 blockcnt *= MNINDIR(fsdev);
582 /* Calculate the address of the first meta-block. */
584 metalbn = -(realbn - bn + NANDFS_NIADDR - i);
586 metalbn = -(-realbn - bn + NANDFS_NIADDR - i);
589 * At each iteration, off is the offset into the bap array which is
590 * an array of disk addresses at the current level of indirection.
591 * The logical block number and the offset in that block are stored
592 * into the argument array.
594 ap->in_lbn = metalbn;
595 ap->in_off = off = NANDFS_NIADDR - i;
597 DPRINTF(BMAP, ("%s: initial: ap->in_lbn=%jx ap->in_off=%d\n", __func__,
601 for (++numlevels; i <= NANDFS_NIADDR; i++) {
602 /* If searching for a meta-data block, quit when found. */
603 if (metalbn == realbn)
606 blockcnt /= MNINDIR(fsdev);
607 off = (bn / blockcnt) % MNINDIR(fsdev);
610 ap->in_lbn = metalbn;
613 DPRINTF(BMAP, ("%s: in_lbn=%jx in_off=%d\n", __func__,
614 ap->in_lbn, ap->in_off));
617 metalbn -= -1 + off * blockcnt;
622 DPRINTF(BMAP, ("%s: numlevels=%d\n", __func__, numlevels));