1235537Sgber/*- 2235537Sgber * Copyright (c) 2012 Semihalf 3235537Sgber * All rights reserved. 4235537Sgber * 5235537Sgber * Redistribution and use in source and binary forms, with or without 6235537Sgber * modification, are permitted provided that the following conditions 7235537Sgber * are met: 8235537Sgber * 1. Redistributions of source code must retain the above copyright 9235537Sgber * notice, this list of conditions and the following disclaimer. 10235537Sgber * 2. Redistributions in binary form must reproduce the above copyright 11235537Sgber * notice, this list of conditions and the following disclaimer in the 12235537Sgber * documentation and/or other materials provided with the distribution. 13235537Sgber * 14235537Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15235537Sgber * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16235537Sgber * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17235537Sgber * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18235537Sgber * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19235537Sgber * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20235537Sgber * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21235537Sgber * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22235537Sgber * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23235537Sgber * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24235537Sgber */ 25235537Sgber 26235537Sgber#include <sys/cdefs.h> 27235537Sgber__FBSDID("$FreeBSD$"); 28235537Sgber 29235537Sgber#include <sys/param.h> 30235537Sgber#include <sys/systm.h> 31235537Sgber#include <sys/namei.h> 32235537Sgber#include <sys/kernel.h> 33235537Sgber#include <sys/stat.h> 34235537Sgber#include <sys/buf.h> 35235537Sgber#include <sys/bio.h> 36235537Sgber#include <sys/proc.h> 37235537Sgber#include <sys/mount.h> 38235537Sgber#include <sys/vnode.h> 39235537Sgber#include <sys/signalvar.h> 40235537Sgber#include <sys/malloc.h> 41235537Sgber#include <sys/dirent.h> 42235537Sgber#include <sys/lockf.h> 43235537Sgber#include <sys/ktr.h> 44235537Sgber#include <sys/kdb.h> 45235537Sgber 46235537Sgber#include <vm/vm.h> 47235537Sgber#include <vm/vm_extern.h> 48235537Sgber#include <vm/vm_object.h> 49235537Sgber#include <vm/vnode_pager.h> 50235537Sgber 51235537Sgber#include <machine/_inttypes.h> 52235537Sgber 53235537Sgber#include <vm/vm.h> 54235537Sgber#include <vm/vm_extern.h> 55235537Sgber#include <vm/vm_object.h> 56235537Sgber#include <vm/vnode_pager.h> 57235537Sgber 58235537Sgber#include "nandfs_mount.h" 59235537Sgber#include "nandfs.h" 60235537Sgber#include "nandfs_subr.h" 61235537Sgber#include "bmap.h" 62235537Sgber 63235537Sgberstatic int bmap_getlbns(struct nandfs_node *, nandfs_lbn_t, 64235537Sgber struct nandfs_indir *, int *); 65235537Sgber 66235537Sgberint 67235537Sgberbmap_lookup(struct nandfs_node *node, nandfs_lbn_t lblk, nandfs_daddr_t *vblk) 68235537Sgber{ 69235537Sgber struct nandfs_inode *ip; 70235537Sgber struct nandfs_indir a[NIADDR + 1], *ap; 71235537Sgber nandfs_daddr_t daddr; 72235537Sgber struct buf *bp; 73235537Sgber int error; 74235537Sgber int num, *nump; 75235537Sgber 76235537Sgber DPRINTF(BMAP, ("%s: node %p lblk %jx enter\n", __func__, node, lblk)); 77235537Sgber ip = &node->nn_inode; 78235537Sgber 79235537Sgber ap = a; 80235537Sgber nump = # 81235537Sgber 82235537Sgber error = bmap_getlbns(node, lblk, ap, nump); 83235537Sgber if (error) 84235537Sgber return (error); 85235537Sgber 86235537Sgber if (num == 0) { 87235537Sgber *vblk = ip->i_db[lblk]; 88235537Sgber return (0); 89235537Sgber } 90235537Sgber 91235537Sgber DPRINTF(BMAP, ("%s: node %p lblk=%jx trying ip->i_ib[%x]\n", __func__, 92235537Sgber node, lblk, ap->in_off)); 93235537Sgber daddr = ip->i_ib[ap->in_off]; 94235537Sgber for (bp = NULL, ++ap; --num; ap++) { 95235537Sgber if (daddr == 0) { 96235537Sgber DPRINTF(BMAP, ("%s: node %p lblk=%jx returning with " 97235537Sgber "vblk 0\n", __func__, node, lblk)); 98235537Sgber *vblk = 0; 99235537Sgber return (0); 100235537Sgber } 101235537Sgber if (ap->in_lbn == lblk) { 102235537Sgber DPRINTF(BMAP, ("%s: node %p lblk=%jx ap->in_lbn=%jx " 103235537Sgber "returning address of indirect block (%jx)\n", 104235537Sgber __func__, node, lblk, ap->in_lbn, daddr)); 105235537Sgber *vblk = daddr; 106235537Sgber return (0); 107235537Sgber } 108235537Sgber 109235537Sgber DPRINTF(BMAP, ("%s: node %p lblk=%jx reading block " 110235537Sgber "ap->in_lbn=%jx\n", __func__, node, lblk, ap->in_lbn)); 111235537Sgber 112235537Sgber error = nandfs_bread_meta(node, ap->in_lbn, NOCRED, 0, &bp); 113235537Sgber if (error) { 114235537Sgber brelse(bp); 115235537Sgber return (error); 116235537Sgber } 117235537Sgber 118235537Sgber daddr = ((nandfs_daddr_t *)bp->b_data)[ap->in_off]; 119235537Sgber brelse(bp); 120235537Sgber } 121235537Sgber 122235537Sgber DPRINTF(BMAP, ("%s: node %p lblk=%jx returning with %jx\n", __func__, 123235537Sgber node, lblk, daddr)); 124235537Sgber *vblk = daddr; 125235537Sgber 126235537Sgber return (0); 127235537Sgber} 128235537Sgber 129235537Sgberint 130235537Sgberbmap_dirty_meta(struct nandfs_node *node, nandfs_lbn_t lblk, int force) 131235537Sgber{ 132235537Sgber struct nandfs_indir a[NIADDR+1], *ap; 133235537Sgber#ifdef DEBUG 134235537Sgber nandfs_daddr_t daddr; 135235537Sgber#endif 136235537Sgber struct buf *bp; 137235537Sgber int error; 138235537Sgber int num, *nump; 139235537Sgber 140235537Sgber DPRINTF(BMAP, ("%s: node %p lblk=%jx\n", __func__, node, lblk)); 141235537Sgber 142235537Sgber ap = a; 143235537Sgber nump = # 144235537Sgber 145235537Sgber error = bmap_getlbns(node, lblk, ap, nump); 146235537Sgber if (error) 147235537Sgber return (error); 148235537Sgber 149235537Sgber /* 150235537Sgber * Direct block, nothing to do 151235537Sgber */ 152235537Sgber if (num == 0) 153235537Sgber return (0); 154235537Sgber 155235537Sgber DPRINTF(BMAP, ("%s: node %p reading blocks\n", __func__, node)); 156235537Sgber 157235537Sgber for (bp = NULL, ++ap; --num; ap++) { 158235537Sgber error = nandfs_bread_meta(node, ap->in_lbn, NOCRED, 0, &bp); 159235537Sgber if (error) { 160235537Sgber brelse(bp); 161235537Sgber return (error); 162235537Sgber } 163235537Sgber 164235537Sgber#ifdef DEBUG 165235537Sgber daddr = ((nandfs_daddr_t *)bp->b_data)[ap->in_off]; 166235537Sgber MPASS(daddr != 0 || node->nn_ino == 3); 167235537Sgber#endif 168235537Sgber 169235537Sgber error = nandfs_dirty_buf_meta(bp, force); 170235537Sgber if (error) 171235537Sgber return (error); 172235537Sgber } 173235537Sgber 174235537Sgber return (0); 175235537Sgber} 176235537Sgber 177235537Sgberint 178235537Sgberbmap_insert_block(struct nandfs_node *node, nandfs_lbn_t lblk, 179235537Sgber nandfs_daddr_t vblk) 180235537Sgber{ 181235537Sgber struct nandfs_inode *ip; 182235537Sgber struct nandfs_indir a[NIADDR+1], *ap; 183235537Sgber struct buf *bp; 184235537Sgber nandfs_daddr_t daddr; 185235537Sgber int error; 186235537Sgber int num, *nump, i; 187235537Sgber 188235537Sgber DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx\n", __func__, node, lblk, 189235537Sgber vblk)); 190235537Sgber 191235537Sgber ip = &node->nn_inode; 192235537Sgber 193235537Sgber ap = a; 194235537Sgber nump = # 195235537Sgber 196235537Sgber error = bmap_getlbns(node, lblk, ap, nump); 197235537Sgber if (error) 198235537Sgber return (error); 199235537Sgber 200235537Sgber DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx got num=%d\n", __func__, 201235537Sgber node, lblk, vblk, num)); 202235537Sgber 203235537Sgber if (num == 0) { 204235537Sgber DPRINTF(BMAP, ("%s: node %p lblk=%jx direct block\n", __func__, 205235537Sgber node, lblk)); 206235537Sgber ip->i_db[lblk] = vblk; 207235537Sgber return (0); 208235537Sgber } 209235537Sgber 210235537Sgber DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block level %d\n", 211235537Sgber __func__, node, lblk, ap->in_off)); 212235537Sgber 213235537Sgber if (num == 1) { 214235537Sgber DPRINTF(BMAP, ("%s: node %p lblk=%jx indirect block: inserting " 215235537Sgber "%jx as vblk for indirect block %d\n", __func__, node, 216235537Sgber lblk, vblk, ap->in_off)); 217235537Sgber ip->i_ib[ap->in_off] = vblk; 218235537Sgber return (0); 219235537Sgber } 220235537Sgber 221235537Sgber bp = NULL; 222235537Sgber daddr = ip->i_ib[a[0].in_off]; 223235537Sgber for (i = 1; i < num; i++) { 224235537Sgber if (bp) 225235537Sgber brelse(bp); 226235537Sgber if (daddr == 0) { 227235537Sgber DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx create " 228235537Sgber "block %jx %d\n", __func__, node, lblk, vblk, 229235537Sgber a[i].in_lbn, a[i].in_off)); 230235537Sgber error = nandfs_bcreate_meta(node, a[i].in_lbn, NOCRED, 231235537Sgber 0, &bp); 232235537Sgber if (error) 233235537Sgber return (error); 234235537Sgber } else { 235235537Sgber DPRINTF(BMAP, ("%s: node %p lblk=%jx vblk=%jx read " 236235537Sgber "block %jx %d\n", __func__, node, daddr, vblk, 237235537Sgber a[i].in_lbn, a[i].in_off)); 238235537Sgber error = nandfs_bread_meta(node, a[i].in_lbn, NOCRED, 0, &bp); 239235537Sgber if (error) { 240235537Sgber brelse(bp); 241235537Sgber return (error); 242235537Sgber } 243235537Sgber } 244235537Sgber daddr = ((nandfs_daddr_t *)bp->b_data)[a[i].in_off]; 245235537Sgber } 246235537Sgber i--; 247235537Sgber 248235537Sgber DPRINTF(BMAP, 249235537Sgber ("%s: bmap node %p lblk=%jx vblk=%jx inserting vblk level %d at " 250235537Sgber "offset %d at %jx\n", __func__, node, lblk, vblk, i, a[i].in_off, 251235537Sgber daddr)); 252235537Sgber 253235537Sgber if (!bp) { 254235537Sgber nandfs_error("%s: cannot find indirect block\n", __func__); 255235537Sgber return (-1); 256235537Sgber } 257235537Sgber ((nandfs_daddr_t *)bp->b_data)[a[i].in_off] = vblk; 258235537Sgber 259235537Sgber error = nandfs_dirty_buf_meta(bp, 0); 260235537Sgber if (error) { 261235537Sgber nandfs_warning("%s: dirty failed buf: %p\n", __func__, bp); 262235537Sgber return (error); 263235537Sgber } 264235537Sgber DPRINTF(BMAP, ("%s: exiting node %p lblk=%jx vblk=%jx\n", __func__, 265235537Sgber node, lblk, vblk)); 266235537Sgber 267235537Sgber return (error); 268235537Sgber} 269235537Sgber 270235537SgberCTASSERT(NIADDR <= 3); 271235537Sgber#define SINGLE 0 /* index of single indirect block */ 272235537Sgber#define DOUBLE 1 /* index of double indirect block */ 273235537Sgber#define TRIPLE 2 /* index of triple indirect block */ 274235537Sgber 275235537Sgberstatic __inline nandfs_lbn_t 276235537Sgberlbn_offset(struct nandfs_device *fsdev, int level) 277235537Sgber{ 278235537Sgber nandfs_lbn_t res; 279235537Sgber 280235537Sgber for (res = 1; level > 0; level--) 281235537Sgber res *= MNINDIR(fsdev); 282235537Sgber return (res); 283235537Sgber} 284235537Sgber 285235537Sgberstatic nandfs_lbn_t 286235537Sgberblocks_inside(struct nandfs_device *fsdev, int level, struct nandfs_indir *nip) 287235537Sgber{ 288235537Sgber nandfs_lbn_t blocks; 289235537Sgber 290235537Sgber for (blocks = 1; level >= SINGLE; level--, nip++) { 291235537Sgber MPASS(nip->in_off >= 0 && nip->in_off < MNINDIR(fsdev)); 292235537Sgber blocks += nip->in_off * lbn_offset(fsdev, level); 293235537Sgber } 294235537Sgber 295235537Sgber return (blocks); 296235537Sgber} 297235537Sgber 298235537Sgberstatic int 299235537Sgberbmap_truncate_indirect(struct nandfs_node *node, int level, nandfs_lbn_t *left, 300235537Sgber int *cleaned, struct nandfs_indir *ap, struct nandfs_indir *fp, 301235537Sgber nandfs_daddr_t *copy) 302235537Sgber{ 303235537Sgber struct buf *bp; 304235537Sgber nandfs_lbn_t i, lbn, nlbn, factor, tosub; 305235537Sgber struct nandfs_device *fsdev; 306235537Sgber int error, lcleaned, modified; 307235537Sgber 308235537Sgber DPRINTF(BMAP, ("%s: node %p level %d left %jx\n", __func__, 309235537Sgber node, level, *left)); 310235537Sgber 311235537Sgber fsdev = node->nn_nandfsdev; 312235537Sgber 313235537Sgber MPASS(ap->in_off >= 0 && ap->in_off < MNINDIR(fsdev)); 314235537Sgber 315235537Sgber factor = lbn_offset(fsdev, level); 316235537Sgber lbn = ap->in_lbn; 317235537Sgber 318235537Sgber error = nandfs_bread_meta(node, lbn, NOCRED, 0, &bp); 319235537Sgber if (error) { 320235537Sgber brelse(bp); 321235537Sgber return (error); 322235537Sgber } 323235537Sgber 324235537Sgber bcopy(bp->b_data, copy, fsdev->nd_blocksize); 325235537Sgber bqrelse(bp); 326235537Sgber 327235537Sgber modified = 0; 328235537Sgber 329235537Sgber i = ap->in_off; 330235537Sgber 331235537Sgber if (ap != fp) 332235537Sgber ap++; 333235537Sgber for (nlbn = lbn + 1 - i * factor; i >= 0 && *left > 0; i--, 334235537Sgber nlbn += factor) { 335235537Sgber lcleaned = 0; 336235537Sgber 337235537Sgber DPRINTF(BMAP, 338235537Sgber ("%s: node %p i=%jx nlbn=%jx left=%jx ap=%p vblk %jx\n", 339235537Sgber __func__, node, i, nlbn, *left, ap, copy[i])); 340235537Sgber 341235537Sgber if (copy[i] == 0) { 342235537Sgber tosub = blocks_inside(fsdev, level - 1, ap); 343235537Sgber if (tosub > *left) 344235537Sgber tosub = 0; 345235537Sgber 346235537Sgber *left -= tosub; 347235537Sgber } else { 348235537Sgber if (level > SINGLE) { 349235537Sgber if (ap == fp) 350235537Sgber ap->in_lbn = nlbn; 351235537Sgber 352235537Sgber error = bmap_truncate_indirect(node, level - 1, 353235537Sgber left, &lcleaned, ap, fp, 354235537Sgber copy + MNINDIR(fsdev)); 355235537Sgber if (error) 356235537Sgber return (error); 357235537Sgber } else { 358235537Sgber error = nandfs_bdestroy(node, copy[i]); 359235537Sgber if (error) 360235537Sgber return (error); 361235537Sgber lcleaned = 1; 362235537Sgber *left -= 1; 363235537Sgber } 364235537Sgber } 365235537Sgber 366235537Sgber if (lcleaned) { 367235537Sgber if (level > SINGLE) { 368235537Sgber error = nandfs_vblock_end(fsdev, copy[i]); 369235537Sgber if (error) 370235537Sgber return (error); 371235537Sgber } 372235537Sgber copy[i] = 0; 373235537Sgber modified++; 374235537Sgber } 375235537Sgber 376235537Sgber ap = fp; 377235537Sgber } 378235537Sgber 379235537Sgber if (i == -1) 380235537Sgber *cleaned = 1; 381235537Sgber 382235537Sgber error = nandfs_bread_meta(node, lbn, NOCRED, 0, &bp); 383235537Sgber if (error) { 384235537Sgber brelse(bp); 385235537Sgber return (error); 386235537Sgber } 387235537Sgber if (modified) 388235537Sgber bcopy(copy, bp->b_data, fsdev->nd_blocksize); 389235537Sgber 390235537Sgber error = nandfs_dirty_buf_meta(bp, 0); 391235537Sgber if (error) 392235537Sgber return (error); 393235537Sgber 394235537Sgber return (error); 395235537Sgber} 396235537Sgber 397235537Sgberint 398235537Sgberbmap_truncate_mapping(struct nandfs_node *node, nandfs_lbn_t lastblk, 399235537Sgber nandfs_lbn_t todo) 400235537Sgber{ 401235537Sgber struct nandfs_inode *ip; 402235537Sgber struct nandfs_indir a[NIADDR + 1], f[NIADDR], *ap; 403235537Sgber nandfs_daddr_t indir_lbn[NIADDR]; 404235537Sgber nandfs_daddr_t *copy; 405235537Sgber int error, level; 406235537Sgber nandfs_lbn_t left, tosub; 407235537Sgber struct nandfs_device *fsdev; 408235537Sgber int cleaned, i; 409235537Sgber int num, *nump; 410235537Sgber 411235537Sgber DPRINTF(BMAP, ("%s: node %p lastblk %jx truncating by %jx\n", __func__, 412235537Sgber node, lastblk, todo)); 413235537Sgber 414235537Sgber ip = &node->nn_inode; 415235537Sgber fsdev = node->nn_nandfsdev; 416235537Sgber 417235537Sgber ap = a; 418235537Sgber nump = # 419235537Sgber 420235537Sgber error = bmap_getlbns(node, lastblk, ap, nump); 421235537Sgber if (error) 422235537Sgber return (error); 423235537Sgber 424235537Sgber indir_lbn[SINGLE] = -NDADDR; 425235537Sgber indir_lbn[DOUBLE] = indir_lbn[SINGLE] - MNINDIR(fsdev) - 1; 426235537Sgber indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - MNINDIR(fsdev) 427235537Sgber * MNINDIR(fsdev) - 1; 428235537Sgber 429235537Sgber for (i = 0; i < NIADDR; i++) { 430235537Sgber f[i].in_off = MNINDIR(fsdev) - 1; 431235537Sgber f[i].in_lbn = 0xdeadbeef; 432235537Sgber } 433235537Sgber 434235537Sgber left = todo; 435235537Sgber 436235537Sgber#ifdef DEBUG 437235537Sgber a[num].in_off = -1; 438235537Sgber#endif 439235537Sgber 440235537Sgber ap++; 441235537Sgber num -= 2; 442235537Sgber 443235537Sgber if (num < 0) 444235537Sgber goto direct; 445235537Sgber 446235537Sgber copy = malloc(MNINDIR(fsdev) * sizeof(nandfs_daddr_t) * (num + 1), 447235537Sgber M_NANDFSTEMP, M_WAITOK); 448235537Sgber 449235537Sgber for (level = num; level >= SINGLE && left > 0; level--) { 450235537Sgber cleaned = 0; 451235537Sgber 452235537Sgber if (ip->i_ib[level] == 0) { 453235537Sgber tosub = blocks_inside(fsdev, level, ap); 454235537Sgber if (tosub > left) 455235537Sgber left = 0; 456235537Sgber else 457235537Sgber left -= tosub; 458235537Sgber } else { 459235537Sgber if (ap == f) 460235537Sgber ap->in_lbn = indir_lbn[level]; 461235537Sgber error = bmap_truncate_indirect(node, level, &left, 462235537Sgber &cleaned, ap, f, copy); 463235537Sgber if (error) { 464235537Sgber nandfs_error("%s: error %d when truncate " 465235537Sgber "at level %d\n", __func__, error, level); 466235537Sgber return (error); 467235537Sgber } 468235537Sgber } 469235537Sgber 470235537Sgber if (cleaned) { 471235537Sgber nandfs_vblock_end(fsdev, ip->i_ib[level]); 472235537Sgber ip->i_ib[level] = 0; 473235537Sgber } 474235537Sgber 475235537Sgber ap = f; 476235537Sgber } 477235537Sgber 478235537Sgber free(copy, M_NANDFSTEMP); 479235537Sgber 480235537Sgberdirect: 481235537Sgber if (num < 0) 482235537Sgber i = lastblk; 483235537Sgber else 484235537Sgber i = NDADDR - 1; 485235537Sgber 486235537Sgber for (; i >= 0 && left > 0; i--) { 487235537Sgber if (ip->i_db[i] != 0) { 488235537Sgber error = nandfs_bdestroy(node, ip->i_db[i]); 489235537Sgber if (error) { 490235537Sgber nandfs_error("%s: cannot destroy " 491235537Sgber "block %jx, error %d\n", __func__, 492235537Sgber (uintmax_t)ip->i_db[i], error); 493235537Sgber return (error); 494235537Sgber } 495235537Sgber ip->i_db[i] = 0; 496235537Sgber } 497235537Sgber 498235537Sgber left--; 499235537Sgber } 500235537Sgber 501235537Sgber KASSERT(left == 0, 502235537Sgber ("truncated wrong number of blocks (%jd should be 0)", left)); 503235537Sgber 504235537Sgber return (error); 505235537Sgber} 506235537Sgber 507235537Sgbernandfs_lbn_t 508235537Sgberget_maxfilesize(struct nandfs_device *fsdev) 509235537Sgber{ 510235537Sgber struct nandfs_indir f[NIADDR]; 511235537Sgber nandfs_lbn_t max; 512235537Sgber int i; 513235537Sgber 514235537Sgber max = NDADDR; 515235537Sgber 516235537Sgber for (i = 0; i < NIADDR; i++) { 517235537Sgber f[i].in_off = MNINDIR(fsdev) - 1; 518235537Sgber max += blocks_inside(fsdev, i, f); 519235537Sgber } 520235537Sgber 521235537Sgber max *= fsdev->nd_blocksize; 522235537Sgber 523235537Sgber return (max); 524235537Sgber} 525235537Sgber 526235537Sgber/* 527235537Sgber * This is ufs_getlbns with minor modifications. 528235537Sgber */ 529235537Sgber/* 530235537Sgber * Create an array of logical block number/offset pairs which represent the 531235537Sgber * path of indirect blocks required to access a data block. The first "pair" 532235537Sgber * contains the logical block number of the appropriate single, double or 533235537Sgber * triple indirect block and the offset into the inode indirect block array. 534235537Sgber * Note, the logical block number of the inode single/double/triple indirect 535235537Sgber * block appears twice in the array, once with the offset into the i_ib and 536235537Sgber * once with the offset into the page itself. 537235537Sgber */ 538235537Sgberstatic int 539235537Sgberbmap_getlbns(struct nandfs_node *node, nandfs_lbn_t bn, struct nandfs_indir *ap, int *nump) 540235537Sgber{ 541235537Sgber nandfs_daddr_t blockcnt; 542235537Sgber nandfs_lbn_t metalbn, realbn; 543235537Sgber struct nandfs_device *fsdev; 544235537Sgber int i, numlevels, off; 545235537Sgber 546235537Sgber fsdev = node->nn_nandfsdev; 547235537Sgber 548235537Sgber DPRINTF(BMAP, ("%s: node %p bn=%jx mnindir=%zd enter\n", __func__, 549235537Sgber node, bn, MNINDIR(fsdev))); 550235537Sgber 551240358Skevlo if (nump) 552240358Skevlo *nump = 0; 553235537Sgber numlevels = 0; 554235537Sgber realbn = bn; 555235537Sgber 556235537Sgber if (bn < 0) 557235537Sgber bn = -bn; 558235537Sgber 559235537Sgber /* The first NDADDR blocks are direct blocks. */ 560235537Sgber if (bn < NDADDR) 561235537Sgber return (0); 562235537Sgber 563235537Sgber /* 564235537Sgber * Determine the number of levels of indirection. After this loop 565235537Sgber * is done, blockcnt indicates the number of data blocks possible 566235537Sgber * at the previous level of indirection, and NIADDR - i is the number 567235537Sgber * of levels of indirection needed to locate the requested block. 568235537Sgber */ 569235537Sgber for (blockcnt = 1, i = NIADDR, bn -= NDADDR;; i--, bn -= blockcnt) { 570235537Sgber DPRINTF(BMAP, ("%s: blockcnt=%jd i=%d bn=%jd\n", __func__, 571235537Sgber blockcnt, i, bn)); 572235537Sgber if (i == 0) 573235537Sgber return (EFBIG); 574235537Sgber blockcnt *= MNINDIR(fsdev); 575235537Sgber if (bn < blockcnt) 576235537Sgber break; 577235537Sgber } 578235537Sgber 579235537Sgber /* Calculate the address of the first meta-block. */ 580235537Sgber if (realbn >= 0) 581235537Sgber metalbn = -(realbn - bn + NIADDR - i); 582235537Sgber else 583235537Sgber metalbn = -(-realbn - bn + NIADDR - i); 584235537Sgber 585235537Sgber /* 586235537Sgber * At each iteration, off is the offset into the bap array which is 587235537Sgber * an array of disk addresses at the current level of indirection. 588235537Sgber * The logical block number and the offset in that block are stored 589235537Sgber * into the argument array. 590235537Sgber */ 591235537Sgber ap->in_lbn = metalbn; 592235537Sgber ap->in_off = off = NIADDR - i; 593235537Sgber 594235537Sgber DPRINTF(BMAP, ("%s: initial: ap->in_lbn=%jx ap->in_off=%d\n", __func__, 595235537Sgber metalbn, off)); 596235537Sgber 597235537Sgber ap++; 598235537Sgber for (++numlevels; i <= NIADDR; i++) { 599235537Sgber /* If searching for a meta-data block, quit when found. */ 600235537Sgber if (metalbn == realbn) 601235537Sgber break; 602235537Sgber 603235537Sgber blockcnt /= MNINDIR(fsdev); 604235537Sgber off = (bn / blockcnt) % MNINDIR(fsdev); 605235537Sgber 606235537Sgber ++numlevels; 607235537Sgber ap->in_lbn = metalbn; 608235537Sgber ap->in_off = off; 609235537Sgber 610235537Sgber DPRINTF(BMAP, ("%s: in_lbn=%jx in_off=%d\n", __func__, 611235537Sgber ap->in_lbn, ap->in_off)); 612235537Sgber ++ap; 613235537Sgber 614235537Sgber metalbn -= -1 + off * blockcnt; 615235537Sgber } 616235537Sgber if (nump) 617235537Sgber *nump = numlevels; 618235537Sgber 619235537Sgber DPRINTF(BMAP, ("%s: numlevels=%d\n", __func__, numlevels)); 620235537Sgber 621235537Sgber return (0); 622235537Sgber} 623