1 /* $NetBSD: ufs_bmap.c,v 1.56 2026/01/22 03:24:19 riastradh Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)ufs_bmap.c 8.8 (Berkeley) 8/11/95 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: ufs_bmap.c,v 1.56 2026/01/22 03:24:19 riastradh Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/types.h> 44 45 #include <sys/buf.h> 46 #include <sys/mount.h> 47 #include <sys/proc.h> 48 #include <sys/resourcevar.h> 49 #include <sys/sdt.h> 50 #include <sys/systm.h> 51 #include <sys/trace.h> 52 #include <sys/vnode.h> 53 54 #include <miscfs/specfs/specdev.h> 55 56 #include <ufs/ufs/inode.h> 57 #include <ufs/ufs/ufs_bswap.h> 58 #include <ufs/ufs/ufs_extern.h> 59 #include <ufs/ufs/ufsmount.h> 60 61 static bool 62 ufs_issequential(const struct ufsmount *ump, daddr_t daddr0, daddr_t daddr1) 63 { 64 65 /* for ufs, blocks in a hole is not 'contiguous'. */ 66 if (daddr0 == 0) 67 return false; 68 69 return (daddr0 + ump->um_seqinc == daddr1); 70 } 71 72 /* 73 * Bmap converts the logical block number of a file to its physical block 74 * number on the disk. The conversion is done by using the logical block 75 * number to index into the array of block pointers described by the dinode. 76 */ 77 int 78 ufs_bmap(void *v) 79 { 80 struct vop_bmap_args /* { 81 struct vnode *a_vp; 82 daddr_t a_bn; 83 struct vnode **a_vpp; 84 daddr_t *a_bnp; 85 int *a_runp; 86 } */ *ap = v; 87 int error; 88 89 /* 90 * Check for underlying vnode requests and ensure that logical 91 * to physical mapping is requested. 92 */ 93 if (ap->a_vpp != NULL) 94 *ap->a_vpp = VTOI(ap->a_vp)->i_devvp; 95 if (ap->a_bnp == NULL) 96 return 0; 97 98 error = ufs_bmaparray(ap->a_vp, ap->a_bn, ap->a_bnp, NULL, NULL, 99 ap->a_runp, ufs_issequential); 100 return error; 101 } 102 103 /* 104 * Indirect blocks are now on the vnode for the file. They are given negative 105 * logical block numbers. Indirect blocks are addressed by the negative 106 * address of the first data block to which they point. Double indirect blocks 107 * are addressed by one less than the address of the first indirect block to 108 * which they point. Triple indirect blocks are addressed by one less than 109 * the address of the first double indirect block to which they point. 110 * 111 * ufs_bmaparray does the bmap conversion, and if requested returns the 112 * array of logical blocks which must be traversed to get to a block. 113 * Each entry contains the offset into that block that gets you to the 114 * next block and the disk address of the block (if it is assigned). 115 */ 116 117 int 118 ufs_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, struct indir *ap, 119 int *nump, int *runp, ufs_issequential_callback_t is_sequential) 120 { 121 struct inode *ip; 122 struct buf *bp, *cbp; 123 struct ufsmount *ump; 124 struct mount *mp; 125 struct indir a[UFS_NIADDR + 1], *xap; 126 daddr_t daddr; 127 daddr_t metalbn; 128 int error, maxrun = 0, num; 129 130 ip = VTOI(vp); 131 mp = vp->v_mount; 132 ump = ip->i_ump; 133 KASSERTMSG(((ap == NULL) == (nump == NULL)), 134 "ufs_bmaparray: invalid arguments: ap = %p, nump = %p", ap, nump); 135 136 if (runp) { 137 /* 138 * XXX 139 * If MAXBSIZE is the largest transfer the disks can handle, 140 * we probably want maxrun to be 1 block less so that we 141 * don't create a block larger than the device can handle. 142 */ 143 *runp = 0; 144 maxrun = MAXPHYS / mp->mnt_stat.f_iosize - 1; 145 } 146 147 if (bn >= 0 && bn < UFS_NDADDR) { 148 if (nump != NULL) 149 *nump = 0; 150 if (ump->um_fstype == UFS1) 151 daddr = ufs_rw32(ip->i_ffs1_db[bn], 152 UFS_MPNEEDSWAP(ump)); 153 else 154 daddr = ufs_rw64(ip->i_ffs2_db[bn], 155 UFS_MPNEEDSWAP(ump)); 156 *bnp = blkptrtodb(ump, daddr); 157 /* 158 * Since this is FFS independent code, we are out of 159 * scope for the definitions of BLK_NOCOPY and 160 * BLK_SNAP, but we do know that they will fall in 161 * the range 1..um_seqinc, so we use that test and 162 * return a request for a zeroed out buffer if attempts 163 * are made to read a BLK_NOCOPY or BLK_SNAP block. 164 */ 165 if ((ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) == SF_SNAPSHOT 166 && daddr > 0 && 167 daddr < ump->um_seqinc) { 168 *bnp = -1; 169 } else if (*bnp == 0) { 170 if ((ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) 171 == SF_SNAPSHOT) { 172 *bnp = blkptrtodb(ump, bn * ump->um_seqinc); 173 } else { 174 *bnp = -1; 175 } 176 } else if (runp) { 177 if (ump->um_fstype == UFS1) { 178 for (++bn; bn < UFS_NDADDR && *runp < maxrun && 179 is_sequential(ump, 180 ufs_rw32(ip->i_ffs1_db[bn - 1], 181 UFS_MPNEEDSWAP(ump)), 182 ufs_rw32(ip->i_ffs1_db[bn], 183 UFS_MPNEEDSWAP(ump))); 184 ++bn, ++*runp); 185 } else { 186 for (++bn; bn < UFS_NDADDR && *runp < maxrun && 187 is_sequential(ump, 188 ufs_rw64(ip->i_ffs2_db[bn - 1], 189 UFS_MPNEEDSWAP(ump)), 190 ufs_rw64(ip->i_ffs2_db[bn], 191 UFS_MPNEEDSWAP(ump))); 192 ++bn, ++*runp); 193 } 194 } 195 return 0; 196 } else if (bn < 0 && bn >= -UFS_NXADDR) { 197 KASSERT(ump->um_fstype == UFS2 && (ump->um_flags & UFS_EA) != 0); 198 daddr = ufs_rw64(ip->i_ffs2_extb[-1 - bn], UFS_MPNEEDSWAP(ump)); 199 *bnp = blkptrtodb(ump, daddr); 200 if (*bnp == 0) 201 *bnp = -1; 202 return 0; 203 } 204 205 xap = ap == NULL ? a : ap; 206 if (!nump) 207 nump = # 208 if ((error = ufs_getlbns(vp, bn, xap, nump)) != 0) 209 return error; 210 211 num = *nump; 212 213 /* Get disk address out of indirect block array */ 214 if (ump->um_fstype == UFS1) 215 daddr = ufs_rw32(ip->i_ffs1_ib[xap->in_off], 216 UFS_MPNEEDSWAP(ump)); 217 else 218 daddr = ufs_rw64(ip->i_ffs2_ib[xap->in_off], 219 UFS_MPNEEDSWAP(ump)); 220 221 for (bp = NULL, ++xap; --num; ++xap) { 222 /* 223 * Exit the loop if there is no disk address assigned yet and 224 * the indirect block isn't in the cache, or if we were 225 * looking for an indirect block and we've found it. 226 */ 227 228 metalbn = xap->in_lbn; 229 if (metalbn == bn) 230 break; 231 if (daddr == 0) { 232 mutex_enter(&bufcache_lock); 233 cbp = incore(vp, metalbn); 234 mutex_exit(&bufcache_lock); 235 if (cbp == NULL) 236 break; 237 } 238 239 /* 240 * If we get here, we've either got the block in the cache 241 * or we have a disk address for it, go fetch it. 242 */ 243 if (bp) 244 brelse(bp, 0); 245 246 xap->in_exists = 1; 247 bp = getblk(vp, metalbn, mp->mnt_stat.f_iosize, 0, 0); 248 if (bp == NULL) { 249 250 /* 251 * getblk() above returns NULL only iff we are 252 * pagedaemon. See the implementation of getblk 253 * for detail. 254 */ 255 256 return SET_ERROR(ENOMEM); 257 } 258 if (bp->b_oflags & (BO_DONE | BO_DELWRI)) { 259 trace(TR_BREADHIT, pack(vp, size), metalbn); 260 } else { 261 KASSERTMSG((daddr != 0), 262 "ufs_bmaparray: indirect block not in cache"); 263 trace(TR_BREADMISS, pack(vp, size), metalbn); 264 bp->b_blkno = blkptrtodb(ump, daddr); 265 bp->b_flags |= B_READ; 266 BIO_SETPRIO(bp, BPRIO_TIMECRITICAL); 267 VOP_STRATEGY(vp, bp); 268 curlwp->l_ru.ru_inblock++; /* XXX */ 269 if ((error = biowait(bp)) != 0) { 270 brelse(bp, 0); 271 return error; 272 } 273 } 274 if (ump->um_fstype == UFS1) { 275 daddr = ufs_rw32(((u_int32_t *)bp->b_data)[xap->in_off], 276 UFS_MPNEEDSWAP(ump)); 277 if (num == 1 && daddr && runp) { 278 for (bn = xap->in_off + 1; 279 bn < MNINDIR(ump) && *runp < maxrun && 280 is_sequential(ump, 281 ufs_rw32(((int32_t *)bp->b_data)[bn-1], 282 UFS_MPNEEDSWAP(ump)), 283 ufs_rw32(((int32_t *)bp->b_data)[bn], 284 UFS_MPNEEDSWAP(ump))); 285 ++bn, ++*runp); 286 } 287 } else { 288 daddr = ufs_rw64(((u_int64_t *)bp->b_data)[xap->in_off], 289 UFS_MPNEEDSWAP(ump)); 290 if (num == 1 && daddr && runp) { 291 for (bn = xap->in_off + 1; 292 bn < MNINDIR(ump) && *runp < maxrun && 293 is_sequential(ump, 294 ufs_rw64(((int64_t *)bp->b_data)[bn-1], 295 UFS_MPNEEDSWAP(ump)), 296 ufs_rw64(((int64_t *)bp->b_data)[bn], 297 UFS_MPNEEDSWAP(ump))); 298 ++bn, ++*runp); 299 } 300 } 301 } 302 if (bp) 303 brelse(bp, 0); 304 305 /* 306 * Since this is FFS independent code, we are out of scope for the 307 * definitions of BLK_NOCOPY and BLK_SNAP, but we do know that they 308 * will fall in the range 1..um_seqinc, so we use that test and 309 * return a request for a zeroed out buffer if attempts are made 310 * to read a BLK_NOCOPY or BLK_SNAP block. 311 */ 312 if ((ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) == SF_SNAPSHOT 313 && daddr > 0 && daddr < ump->um_seqinc) { 314 *bnp = -1; 315 return 0; 316 } 317 *bnp = blkptrtodb(ump, daddr); 318 if (*bnp == 0) { 319 if ((ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) 320 == SF_SNAPSHOT) { 321 *bnp = blkptrtodb(ump, bn * ump->um_seqinc); 322 } else { 323 *bnp = -1; 324 } 325 } 326 return 0; 327 } 328 329 /* 330 * Create an array of logical block number/offset pairs which represent the 331 * path of indirect blocks required to access a data block. The first "pair" 332 * contains the logical block number of the appropriate single, double or 333 * triple indirect block and the offset into the inode indirect block array. 334 * Note, the logical block number of the inode single/double/triple indirect 335 * block appears twice in the array, once with the offset into the i_ffs1_ib and 336 * once with the offset into the page itself. 337 */ 338 int 339 ufs_getlbns(struct vnode *vp, daddr_t bn, struct indir *ap, int *nump) 340 { 341 daddr_t metalbn, realbn; 342 struct ufsmount *ump; 343 int64_t blockcnt; 344 int lbc; 345 int i, numlevels, off; 346 347 ump = VFSTOUFS(vp->v_mount); 348 if (nump) 349 *nump = 0; 350 numlevels = 0; 351 realbn = bn; 352 if (bn < 0) 353 bn = -bn; 354 KASSERT(bn >= UFS_NDADDR); 355 356 /* 357 * Determine the number of levels of indirection. After this loop 358 * is done, blockcnt indicates the number of data blocks possible 359 * at the given level of indirection, and UFS_NIADDR - i is the number 360 * of levels of indirection needed to locate the requested block. 361 */ 362 363 bn -= UFS_NDADDR; 364 for (lbc = 0, i = UFS_NIADDR;; i--, bn -= blockcnt) { 365 if (i == 0) 366 return SET_ERROR(EFBIG); 367 368 lbc += ump->um_lognindir; 369 blockcnt = (int64_t)1 << lbc; 370 371 if (bn < blockcnt) 372 break; 373 } 374 375 /* Calculate the address of the first meta-block. */ 376 metalbn = -((realbn >= 0 ? realbn : -realbn) - bn + UFS_NIADDR - i); 377 378 /* 379 * At each iteration, off is the offset into the bap array which is 380 * an array of disk addresses at the current level of indirection. 381 * The logical block number and the offset in that block are stored 382 * into the argument array. 383 */ 384 ap->in_lbn = metalbn; 385 ap->in_off = off = UFS_NIADDR - i; 386 ap->in_exists = 0; 387 ap++; 388 for (++numlevels; i <= UFS_NIADDR; i++) { 389 /* If searching for a meta-data block, quit when found. */ 390 if (metalbn == realbn) 391 break; 392 393 lbc -= ump->um_lognindir; 394 off = (bn >> lbc) & (MNINDIR(ump) - 1); 395 396 ++numlevels; 397 ap->in_lbn = metalbn; 398 ap->in_off = off; 399 ap->in_exists = 0; 400 ++ap; 401 402 metalbn -= -1 + ((int64_t)off << lbc); 403 } 404 if (nump) 405 *nump = numlevels; 406 return 0; 407 } 408