1*7f065009Sdholland /* $NetBSD: lfs.c,v 1.54 2015/08/12 18:26:26 dholland Exp $ */ 2ba10361aSperseant /*- 3ba10361aSperseant * Copyright (c) 2003 The NetBSD Foundation, Inc. 4ba10361aSperseant * All rights reserved. 5ba10361aSperseant * 6ba10361aSperseant * This code is derived from software contributed to The NetBSD Foundation 7ba10361aSperseant * by Konrad E. Schroder <perseant@hhhh.org>. 8ba10361aSperseant * 9ba10361aSperseant * Redistribution and use in source and binary forms, with or without 10ba10361aSperseant * modification, are permitted provided that the following conditions 11ba10361aSperseant * are met: 12ba10361aSperseant * 1. Redistributions of source code must retain the above copyright 13ba10361aSperseant * notice, this list of conditions and the following disclaimer. 14ba10361aSperseant * 2. Redistributions in binary form must reproduce the above copyright 15ba10361aSperseant * notice, this list of conditions and the following disclaimer in the 16ba10361aSperseant * documentation and/or other materials provided with the distribution. 17ba10361aSperseant * 18ba10361aSperseant * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19ba10361aSperseant * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20ba10361aSperseant * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21ba10361aSperseant * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22ba10361aSperseant * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23ba10361aSperseant * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24ba10361aSperseant * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25ba10361aSperseant * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26ba10361aSperseant * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27ba10361aSperseant * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28ba10361aSperseant * POSSIBILITY OF SUCH DAMAGE. 29ba10361aSperseant */ 30ba10361aSperseant /* 31ba10361aSperseant * Copyright (c) 1989, 1991, 1993 32ba10361aSperseant * The Regents of the University of California. All rights reserved. 33ba10361aSperseant * (c) UNIX System Laboratories, Inc. 34ba10361aSperseant * All or some portions of this file are derived from material licensed 35ba10361aSperseant * to the University of California by American Telephone and Telegraph 36ba10361aSperseant * Co. or Unix System Laboratories, Inc. and are reproduced herein with 37ba10361aSperseant * the permission of UNIX System Laboratories, Inc. 38ba10361aSperseant * 39ba10361aSperseant * Redistribution and use in source and binary forms, with or without 40ba10361aSperseant * modification, are permitted provided that the following conditions 41ba10361aSperseant * are met: 42ba10361aSperseant * 1. Redistributions of source code must retain the above copyright 43ba10361aSperseant * notice, this list of conditions and the following disclaimer. 44ba10361aSperseant * 2. Redistributions in binary form must reproduce the above copyright 45ba10361aSperseant * notice, this list of conditions and the following disclaimer in the 46ba10361aSperseant * documentation and/or other materials provided with the distribution. 47276d62f6Sagc * 3. Neither the name of the University nor the names of its contributors 48ba10361aSperseant * may be used to endorse or promote products derived from this software 49ba10361aSperseant * without specific prior written permission. 50ba10361aSperseant * 51ba10361aSperseant * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52ba10361aSperseant * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53ba10361aSperseant * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54ba10361aSperseant * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55ba10361aSperseant * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56ba10361aSperseant * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57ba10361aSperseant * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58ba10361aSperseant * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59ba10361aSperseant * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60ba10361aSperseant * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61ba10361aSperseant * SUCH DAMAGE. 62ba10361aSperseant * 63ba10361aSperseant * @(#)ufs_bmap.c 8.8 (Berkeley) 8/11/95 64ba10361aSperseant */ 65ba10361aSperseant 66ba10361aSperseant 67ba10361aSperseant #include <sys/types.h> 68ba10361aSperseant #include <sys/param.h> 69ba10361aSperseant #include <sys/time.h> 70ba10361aSperseant #include <sys/buf.h> 71ba10361aSperseant #include <sys/mount.h> 72ba10361aSperseant 73f5ac0b5fSdholland #define vnode uvnode 74ba10361aSperseant #include <ufs/lfs/lfs.h> 7579e35bebSdholland #include <ufs/lfs/lfs_inode.h> 76fec5e985Sdholland #include <ufs/lfs/lfs_accessors.h> 77ba10361aSperseant #undef vnode 78ba10361aSperseant 79ba10361aSperseant #include <assert.h> 80ba10361aSperseant #include <err.h> 81ba10361aSperseant #include <errno.h> 82ba10361aSperseant #include <stdarg.h> 83ba10361aSperseant #include <stdio.h> 84ba10361aSperseant #include <stdlib.h> 85ba10361aSperseant #include <string.h> 86ba10361aSperseant #include <unistd.h> 87b6479e9fSchristos #include <util.h> 88ba10361aSperseant 89ba10361aSperseant #include "bufcache.h" 90ba10361aSperseant #include "vnode.h" 91100801edSchristos #include "lfs_user.h" 92ba10361aSperseant #include "segwrite.h" 93709a4d5bSpooka #include "kernelops.h" 94ba10361aSperseant 95ba10361aSperseant #define panic call_panic 96ba10361aSperseant 97ba10361aSperseant extern u_int32_t cksum(void *, size_t); 98ce7ab97dSdholland extern u_int32_t lfs_sb_cksum(struct lfs *); 995d2f3e49Sperseant extern void pwarn(const char *, ...); 100ba10361aSperseant 101ba10361aSperseant extern struct uvnodelst vnodelist; 1021d4cc6a1Sperseant extern struct uvnodelst getvnodelist[VNODE_HASH_MAX]; 103ba10361aSperseant extern int nvnodes; 104ba10361aSperseant 105d3dff438Smlelstv long dev_bsize = DEV_BSIZE; 10679748725Smlelstv 10729f1062bSperseant static int 10829f1062bSperseant lfs_fragextend(struct uvnode *, int, int, daddr_t, struct ubuf **); 10929f1062bSperseant 110ba10361aSperseant int fsdirty = 0; 11117c417f1Sdholland void (*panic_func)(int, const char *, va_list) = my_vpanic; 112ba10361aSperseant 113ba10361aSperseant /* 114ba10361aSperseant * LFS buffer and uvnode operations 115ba10361aSperseant */ 116ba10361aSperseant 117ba10361aSperseant int 118ba10361aSperseant lfs_vop_strategy(struct ubuf * bp) 119ba10361aSperseant { 120ba10361aSperseant int count; 121ba10361aSperseant 122ba10361aSperseant if (bp->b_flags & B_READ) { 123709a4d5bSpooka count = kops.ko_pread(bp->b_vp->v_fd, bp->b_data, bp->b_bcount, 12479748725Smlelstv bp->b_blkno * dev_bsize); 125ba10361aSperseant if (count == bp->b_bcount) 126ba10361aSperseant bp->b_flags |= B_DONE; 127ba10361aSperseant } else { 128709a4d5bSpooka count = kops.ko_pwrite(bp->b_vp->v_fd, bp->b_data, bp->b_bcount, 12979748725Smlelstv bp->b_blkno * dev_bsize); 130ba10361aSperseant if (count == 0) { 131657e8b00Schristos perror("pwrite"); 132ba10361aSperseant return -1; 133ba10361aSperseant } 134ba10361aSperseant bp->b_flags &= ~B_DELWRI; 135ba10361aSperseant reassignbuf(bp, bp->b_vp); 136ba10361aSperseant } 137ba10361aSperseant return 0; 138ba10361aSperseant } 139ba10361aSperseant 140ba10361aSperseant int 141ba10361aSperseant lfs_vop_bwrite(struct ubuf * bp) 142ba10361aSperseant { 143ba10361aSperseant struct lfs *fs; 144ba10361aSperseant 145ba10361aSperseant fs = bp->b_vp->v_fs; 146ba10361aSperseant if (!(bp->b_flags & B_DELWRI)) { 147576195d5Sdholland lfs_sb_subavail(fs, lfs_btofsb(fs, bp->b_bcount)); 148ba10361aSperseant } 149ba10361aSperseant bp->b_flags |= B_DELWRI | B_LOCKED; 150ba10361aSperseant reassignbuf(bp, bp->b_vp); 151fe44973fSad brelse(bp, 0); 152ba10361aSperseant return 0; 153ba10361aSperseant } 154ba10361aSperseant 155ba10361aSperseant /* 1564f8bc7f7Sdholland * ulfs_bmaparray does the bmap conversion, and if requested returns the 157ba10361aSperseant * array of logical blocks which must be traversed to get to a block. 158ba10361aSperseant * Each entry contains the offset into that block that gets you to the 159ba10361aSperseant * next block and the disk address of the block (if it is assigned). 160ba10361aSperseant */ 161ba10361aSperseant int 1624f8bc7f7Sdholland ulfs_bmaparray(struct lfs * fs, struct uvnode * vp, daddr_t bn, daddr_t * bnp, struct indir * ap, int *nump) 163ba10361aSperseant { 164ba10361aSperseant struct inode *ip; 165ba10361aSperseant struct ubuf *bp; 1664f8bc7f7Sdholland struct indir a[ULFS_NIADDR + 1], *xap; 167ba10361aSperseant daddr_t daddr; 168ba10361aSperseant daddr_t metalbn; 169ba10361aSperseant int error, num; 170ba10361aSperseant 171ba10361aSperseant ip = VTOI(vp); 172ba10361aSperseant 1734f8bc7f7Sdholland if (bn >= 0 && bn < ULFS_NDADDR) { 174ba10361aSperseant if (nump != NULL) 175ba10361aSperseant *nump = 0; 1769ae6af71Schristos *bnp = LFS_FSBTODB(fs, ip->i_ffs1_db[bn]); 177ba10361aSperseant if (*bnp == 0) 178ba10361aSperseant *bnp = -1; 179ba10361aSperseant return (0); 180ba10361aSperseant } 181ba10361aSperseant xap = ap == NULL ? a : ap; 182ba10361aSperseant if (!nump) 183ba10361aSperseant nump = # 1844f8bc7f7Sdholland if ((error = ulfs_getlbns(fs, vp, bn, xap, nump)) != 0) 185ba10361aSperseant return (error); 186ba10361aSperseant 187ba10361aSperseant num = *nump; 188ba10361aSperseant 189ba10361aSperseant /* Get disk address out of indirect block array */ 19042614ed3Sfvdl daddr = ip->i_ffs1_ib[xap->in_off]; 191ba10361aSperseant 192ba10361aSperseant for (bp = NULL, ++xap; --num; ++xap) { 193ba10361aSperseant /* Exit the loop if there is no disk address assigned yet and 194ba10361aSperseant * the indirect block isn't in the cache, or if we were 195ba10361aSperseant * looking for an indirect block and we've found it. */ 196ba10361aSperseant 197ba10361aSperseant metalbn = xap->in_lbn; 198ba10361aSperseant if ((daddr == 0 && !incore(vp, metalbn)) || metalbn == bn) 199ba10361aSperseant break; 200ba10361aSperseant /* 201ba10361aSperseant * If we get here, we've either got the block in the cache 202ba10361aSperseant * or we have a disk address for it, go fetch it. 203ba10361aSperseant */ 204ba10361aSperseant if (bp) 205fe44973fSad brelse(bp, 0); 206ba10361aSperseant 207ba10361aSperseant xap->in_exists = 1; 208576195d5Sdholland bp = getblk(vp, metalbn, lfs_sb_getbsize(fs)); 209ba10361aSperseant 210ba10361aSperseant if (!(bp->b_flags & (B_DONE | B_DELWRI))) { 2119ae6af71Schristos bp->b_blkno = LFS_FSBTODB(fs, daddr); 212ba10361aSperseant bp->b_flags |= B_READ; 213ba10361aSperseant VOP_STRATEGY(bp); 214ba10361aSperseant } 2154f8bc7f7Sdholland daddr = ((ulfs_daddr_t *) bp->b_data)[xap->in_off]; 216ba10361aSperseant } 217ba10361aSperseant if (bp) 218fe44973fSad brelse(bp, 0); 219ba10361aSperseant 2209ae6af71Schristos daddr = LFS_FSBTODB(fs, (ulfs_daddr_t) daddr); 221ba10361aSperseant *bnp = daddr == 0 ? -1 : daddr; 222ba10361aSperseant return (0); 223ba10361aSperseant } 224ba10361aSperseant 225ba10361aSperseant /* 226ba10361aSperseant * Create an array of logical block number/offset pairs which represent the 227ba10361aSperseant * path of indirect blocks required to access a data block. The first "pair" 228ba10361aSperseant * contains the logical block number of the appropriate single, double or 229ba10361aSperseant * triple indirect block and the offset into the inode indirect block array. 230ba10361aSperseant * Note, the logical block number of the inode single/double/triple indirect 23142614ed3Sfvdl * block appears twice in the array, once with the offset into the i_ffs1_ib and 232ba10361aSperseant * once with the offset into the page itself. 233ba10361aSperseant */ 234ba10361aSperseant int 2354f8bc7f7Sdholland ulfs_getlbns(struct lfs * fs, struct uvnode * vp, daddr_t bn, struct indir * ap, int *nump) 236ba10361aSperseant { 237ba10361aSperseant daddr_t metalbn, realbn; 238ba10361aSperseant int64_t blockcnt; 239ba10361aSperseant int lbc; 240ba10361aSperseant int i, numlevels, off; 241ba10361aSperseant int lognindir, indir; 242ba10361aSperseant 24349c83b8eSjmc metalbn = 0; /* XXXGCC -Wuninitialized [sh3] */ 24449c83b8eSjmc 245ba10361aSperseant if (nump) 246ba10361aSperseant *nump = 0; 247ba10361aSperseant numlevels = 0; 248ba10361aSperseant realbn = bn; 249ba10361aSperseant if (bn < 0) 250ba10361aSperseant bn = -bn; 251ba10361aSperseant 252ba10361aSperseant lognindir = -1; 253958ff91fSdholland for (indir = lfs_sb_getnindir(fs); indir; indir >>= 1) 254ba10361aSperseant ++lognindir; 255ba10361aSperseant 256ba10361aSperseant /* Determine the number of levels of indirection. After this loop is 257ba10361aSperseant * done, blockcnt indicates the number of data blocks possible at the 2584f8bc7f7Sdholland * given level of indirection, and ULFS_NIADDR - i is the number of levels 259ba10361aSperseant * of indirection needed to locate the requested block. */ 260ba10361aSperseant 2614f8bc7f7Sdholland bn -= ULFS_NDADDR; 2624f8bc7f7Sdholland for (lbc = 0, i = ULFS_NIADDR;; i--, bn -= blockcnt) { 263ba10361aSperseant if (i == 0) 264ba10361aSperseant return (EFBIG); 265ba10361aSperseant 266ba10361aSperseant lbc += lognindir; 267ba10361aSperseant blockcnt = (int64_t) 1 << lbc; 268ba10361aSperseant 269ba10361aSperseant if (bn < blockcnt) 270ba10361aSperseant break; 271ba10361aSperseant } 272ba10361aSperseant 273ba10361aSperseant /* Calculate the address of the first meta-block. */ 2744f8bc7f7Sdholland metalbn = -((realbn >= 0 ? realbn : -realbn) - bn + ULFS_NIADDR - i); 275ba10361aSperseant 276ba10361aSperseant /* At each iteration, off is the offset into the bap array which is an 277ba10361aSperseant * array of disk addresses at the current level of indirection. The 278ba10361aSperseant * logical block number and the offset in that block are stored into 279ba10361aSperseant * the argument array. */ 280ba10361aSperseant ap->in_lbn = metalbn; 2814f8bc7f7Sdholland ap->in_off = off = ULFS_NIADDR - i; 282ba10361aSperseant ap->in_exists = 0; 283ba10361aSperseant ap++; 2844f8bc7f7Sdholland for (++numlevels; i <= ULFS_NIADDR; i++) { 285ba10361aSperseant /* If searching for a meta-data block, quit when found. */ 286ba10361aSperseant if (metalbn == realbn) 287ba10361aSperseant break; 288ba10361aSperseant 289ba10361aSperseant lbc -= lognindir; 290ba10361aSperseant blockcnt = (int64_t) 1 << lbc; 291958ff91fSdholland off = (bn >> lbc) & (lfs_sb_getnindir(fs) - 1); 292ba10361aSperseant 293ba10361aSperseant ++numlevels; 294ba10361aSperseant ap->in_lbn = metalbn; 295ba10361aSperseant ap->in_off = off; 296ba10361aSperseant ap->in_exists = 0; 297ba10361aSperseant ++ap; 298ba10361aSperseant 299ba10361aSperseant metalbn -= -1 + (off << lbc); 300ba10361aSperseant } 301ba10361aSperseant if (nump) 302ba10361aSperseant *nump = numlevels; 303ba10361aSperseant return (0); 304ba10361aSperseant } 305ba10361aSperseant 306ba10361aSperseant int 307ba10361aSperseant lfs_vop_bmap(struct uvnode * vp, daddr_t lbn, daddr_t * daddrp) 308ba10361aSperseant { 3094f8bc7f7Sdholland return ulfs_bmaparray(vp->v_fs, vp, lbn, daddrp, NULL, NULL); 310ba10361aSperseant } 311ba10361aSperseant 312ba10361aSperseant /* Search a block for a specific dinode. */ 3134f8bc7f7Sdholland struct ulfs1_dinode * 314ba10361aSperseant lfs_ifind(struct lfs * fs, ino_t ino, struct ubuf * bp) 315ba10361aSperseant { 3164f8bc7f7Sdholland struct ulfs1_dinode *dip = (struct ulfs1_dinode *) bp->b_data; 3174f8bc7f7Sdholland struct ulfs1_dinode *ldip, *fin; 318ba10361aSperseant 3199ae6af71Schristos fin = dip + LFS_INOPB(fs); 320ba10361aSperseant 321ba10361aSperseant /* 322ba10361aSperseant * Read the inode block backwards, since later versions of the 323ba10361aSperseant * inode will supercede earlier ones. Though it is unlikely, it is 324ba10361aSperseant * possible that the same inode will appear in the same inode block. 325ba10361aSperseant */ 326ba10361aSperseant for (ldip = fin - 1; ldip >= dip; --ldip) 327ba10361aSperseant if (ldip->di_inumber == ino) 328ba10361aSperseant return (ldip); 329ba10361aSperseant return NULL; 330ba10361aSperseant } 331ba10361aSperseant 332ba10361aSperseant /* 333ba10361aSperseant * lfs_raw_vget makes us a new vnode from the inode at the given disk address. 334ba10361aSperseant * XXX it currently loses atime information. 335ba10361aSperseant */ 336ba10361aSperseant struct uvnode * 3374f8bc7f7Sdholland lfs_raw_vget(struct lfs * fs, ino_t ino, int fd, ulfs_daddr_t daddr) 338ba10361aSperseant { 339ba10361aSperseant struct uvnode *vp; 340ba10361aSperseant struct inode *ip; 3414f8bc7f7Sdholland struct ulfs1_dinode *dip; 342ba10361aSperseant struct ubuf *bp; 3431d4cc6a1Sperseant int i, hash; 344ba10361aSperseant 345b6479e9fSchristos vp = ecalloc(1, sizeof(*vp)); 346ba10361aSperseant vp->v_fd = fd; 347ba10361aSperseant vp->v_fs = fs; 348ba10361aSperseant vp->v_usecount = 0; 349ba10361aSperseant vp->v_strategy_op = lfs_vop_strategy; 350ba10361aSperseant vp->v_bwrite_op = lfs_vop_bwrite; 351ba10361aSperseant vp->v_bmap_op = lfs_vop_bmap; 352e01ace1fSyamt LIST_INIT(&vp->v_cleanblkhd); 353e01ace1fSyamt LIST_INIT(&vp->v_dirtyblkhd); 354ba10361aSperseant 355b6479e9fSchristos ip = ecalloc(1, sizeof(*ip)); 356ba10361aSperseant 357b6479e9fSchristos ip->i_din.ffs1_din = ecalloc(1, sizeof(*ip->i_din.ffs1_din)); 35842614ed3Sfvdl 359ba10361aSperseant /* Initialize the inode -- from lfs_vcreate. */ 360b6479e9fSchristos ip->inode_ext.lfs = ecalloc(1, sizeof(*ip->inode_ext.lfs)); 361ba10361aSperseant vp->v_data = ip; 362ba10361aSperseant /* ip->i_vnode = vp; */ 363ba10361aSperseant ip->i_number = ino; 364ba10361aSperseant ip->i_lockf = 0; 365ba10361aSperseant ip->i_lfs_effnblks = 0; 366ba10361aSperseant ip->i_flag = 0; 367ba10361aSperseant 368ba10361aSperseant /* Load inode block and find inode */ 3695d2f3e49Sperseant if (daddr > 0) { 370958ff91fSdholland bread(fs->lfs_devvp, LFS_FSBTODB(fs, daddr), lfs_sb_getibsize(fs), 3714ec44e9dSchopps 0, &bp); 372ba10361aSperseant bp->b_flags |= B_AGE; 373ba10361aSperseant dip = lfs_ifind(fs, ino, bp); 374ba10361aSperseant if (dip == NULL) { 375fe44973fSad brelse(bp, 0); 376a7f5ddbfSyamt free(ip); 377ba10361aSperseant free(vp); 378ba10361aSperseant return NULL; 379ba10361aSperseant } 38042614ed3Sfvdl memcpy(ip->i_din.ffs1_din, dip, sizeof(*dip)); 381fe44973fSad brelse(bp, 0); 3825d2f3e49Sperseant } 383ba10361aSperseant ip->i_number = ino; 384dcba0206Sperseant /* ip->i_devvp = fs->lfs_devvp; */ 385ba10361aSperseant ip->i_lfs = fs; 386ba10361aSperseant 38742614ed3Sfvdl ip->i_lfs_effnblks = ip->i_ffs1_blocks; 38842614ed3Sfvdl ip->i_lfs_osize = ip->i_ffs1_size; 389ba10361aSperseant #if 0 390ba10361aSperseant if (fs->lfs_version > 1) { 39142614ed3Sfvdl ip->i_ffs1_atime = ts.tv_sec; 39242614ed3Sfvdl ip->i_ffs1_atimensec = ts.tv_nsec; 393ba10361aSperseant } 394ba10361aSperseant #endif 395ba10361aSperseant 3964f8bc7f7Sdholland memset(ip->i_lfs_fragsize, 0, ULFS_NDADDR * sizeof(*ip->i_lfs_fragsize)); 3974f8bc7f7Sdholland for (i = 0; i < ULFS_NDADDR; i++) 39842614ed3Sfvdl if (ip->i_ffs1_db[i] != 0) 3999ae6af71Schristos ip->i_lfs_fragsize[i] = lfs_blksize(fs, ip, i); 400ba10361aSperseant 401a7f5ddbfSyamt ++nvnodes; 4029edc4932Smartin hash = ((int)(intptr_t)fs + ino) & (VNODE_HASH_MAX - 1); 4031d4cc6a1Sperseant LIST_INSERT_HEAD(&getvnodelist[hash], vp, v_getvnodes); 404a7f5ddbfSyamt LIST_INSERT_HEAD(&vnodelist, vp, v_mntvnodes); 405a7f5ddbfSyamt 406ba10361aSperseant return vp; 407ba10361aSperseant } 408ba10361aSperseant 409ba10361aSperseant static struct uvnode * 410ba10361aSperseant lfs_vget(void *vfs, ino_t ino) 411ba10361aSperseant { 412ba10361aSperseant struct lfs *fs = (struct lfs *)vfs; 4134f8bc7f7Sdholland ulfs_daddr_t daddr; 414ba10361aSperseant struct ubuf *bp; 415ba10361aSperseant IFILE *ifp; 416ba10361aSperseant 417ba10361aSperseant LFS_IENTRY(ifp, fs, ino, bp); 418daf91f9bSdholland daddr = lfs_if_getdaddr(fs, ifp); 419fe44973fSad brelse(bp, 0); 420958ff91fSdholland if (daddr <= 0 || lfs_dtosn(fs, daddr) >= lfs_sb_getnseg(fs)) 421ba10361aSperseant return NULL; 422ba10361aSperseant return lfs_raw_vget(fs, ino, fs->lfs_ivnode->v_fd, daddr); 423ba10361aSperseant } 424ba10361aSperseant 425ba10361aSperseant /* Check superblock magic number and checksum */ 426ba10361aSperseant static int 427ba10361aSperseant check_sb(struct lfs *fs) 428ba10361aSperseant { 429ba10361aSperseant u_int32_t checksum; 430ce7ab97dSdholland u_int32_t magic; 431ba10361aSperseant 432ce7ab97dSdholland /* we can read the magic out of either the 32-bit or 64-bit dlfs */ 433ce7ab97dSdholland magic = fs->lfs_dlfs_u.u_32.dlfs_magic; 434ce7ab97dSdholland 435ce7ab97dSdholland if (magic != LFS_MAGIC) { 436ba10361aSperseant printf("Superblock magic number (0x%lx) does not match " 437ce7ab97dSdholland "expected 0x%lx\n", (unsigned long) magic, 438ba10361aSperseant (unsigned long) LFS_MAGIC); 439ba10361aSperseant return 1; 440ba10361aSperseant } 441ba10361aSperseant /* checksum */ 442ce7ab97dSdholland checksum = lfs_sb_cksum(fs); 443958ff91fSdholland if (lfs_sb_getcksum(fs) != checksum) { 444ba10361aSperseant printf("Superblock checksum (%lx) does not match computed checksum (%lx)\n", 445958ff91fSdholland (unsigned long) lfs_sb_getcksum(fs), (unsigned long) checksum); 446ba10361aSperseant return 1; 447ba10361aSperseant } 448ba10361aSperseant return 0; 449ba10361aSperseant } 450ba10361aSperseant 451ba10361aSperseant /* Initialize LFS library; load superblocks and choose which to use. */ 452ba10361aSperseant struct lfs * 4535d2f3e49Sperseant lfs_init(int devfd, daddr_t sblkno, daddr_t idaddr, int dummy_read, int debug) 454ba10361aSperseant { 455ba10361aSperseant struct uvnode *devvp; 456ba10361aSperseant struct ubuf *bp; 457ba10361aSperseant int tryalt; 458ba10361aSperseant struct lfs *fs, *altfs; 459ba10361aSperseant 460ba10361aSperseant vfs_init(); 461ba10361aSperseant 462b6479e9fSchristos devvp = ecalloc(1, sizeof(*devvp)); 463ba10361aSperseant devvp->v_fs = NULL; 464ba10361aSperseant devvp->v_fd = devfd; 465ba10361aSperseant devvp->v_strategy_op = raw_vop_strategy; 466ba10361aSperseant devvp->v_bwrite_op = raw_vop_bwrite; 467ba10361aSperseant devvp->v_bmap_op = raw_vop_bmap; 468e01ace1fSyamt LIST_INIT(&devvp->v_cleanblkhd); 469e01ace1fSyamt LIST_INIT(&devvp->v_dirtyblkhd); 470ba10361aSperseant 471ba10361aSperseant tryalt = 0; 4725d2f3e49Sperseant if (dummy_read) { 4735d2f3e49Sperseant if (sblkno == 0) 47479748725Smlelstv sblkno = LFS_LABELPAD / dev_bsize; 475b6479e9fSchristos fs = ecalloc(1, sizeof(*fs)); 476dcba0206Sperseant fs->lfs_devvp = devvp; 4775d2f3e49Sperseant } else { 478ba10361aSperseant if (sblkno == 0) { 47979748725Smlelstv sblkno = LFS_LABELPAD / dev_bsize; 480ba10361aSperseant tryalt = 1; 481ba10361aSperseant } else if (debug) { 482ba10361aSperseant printf("No -b flag given, not attempting to verify checkpoint\n"); 483ba10361aSperseant } 48479748725Smlelstv 48579748725Smlelstv dev_bsize = DEV_BSIZE; 48679748725Smlelstv 4874ec44e9dSchopps (void)bread(devvp, sblkno, LFS_SBPAD, 0, &bp); 488b6479e9fSchristos fs = ecalloc(1, sizeof(*fs)); 489ce7ab97dSdholland __CTASSERT(sizeof(struct dlfs) == sizeof(struct dlfs64)); 490ce7ab97dSdholland memcpy(&fs->lfs_dlfs_u, bp->b_data, sizeof(struct dlfs)); 491dcba0206Sperseant fs->lfs_devvp = devvp; 492ba10361aSperseant bp->b_flags |= B_INVAL; 493fe44973fSad brelse(bp, 0); 494ba10361aSperseant 495958ff91fSdholland dev_bsize = lfs_sb_getfsize(fs) >> lfs_sb_getfsbtodb(fs); 49679748725Smlelstv 497ba10361aSperseant if (tryalt) { 498958ff91fSdholland (void)bread(devvp, LFS_FSBTODB(fs, lfs_sb_getsboff(fs, 1)), 4994ec44e9dSchopps LFS_SBPAD, 0, &bp); 500b6479e9fSchristos altfs = ecalloc(1, sizeof(*altfs)); 501ce7ab97dSdholland memcpy(&altfs->lfs_dlfs_u, bp->b_data, 502ce7ab97dSdholland sizeof(struct dlfs)); 503dcba0206Sperseant altfs->lfs_devvp = devvp; 504ba10361aSperseant bp->b_flags |= B_INVAL; 505fe44973fSad brelse(bp, 0); 506ba10361aSperseant 507576195d5Sdholland if (check_sb(fs) || lfs_sb_getidaddr(fs) <= 0) { 508ba10361aSperseant if (debug) 509ba10361aSperseant printf("Primary superblock is no good, using first alternate\n"); 510ba10361aSperseant free(fs); 511ba10361aSperseant fs = altfs; 512ba10361aSperseant } else { 513ba10361aSperseant /* If both superblocks check out, try verification */ 514ba10361aSperseant if (check_sb(altfs)) { 515ba10361aSperseant if (debug) 516ba10361aSperseant printf("First alternate superblock is no good, using primary\n"); 517ba10361aSperseant free(altfs); 518ba10361aSperseant } else { 519ba10361aSperseant if (lfs_verify(fs, altfs, devvp, debug) == fs) { 520ba10361aSperseant free(altfs); 521ba10361aSperseant } else { 522ba10361aSperseant free(fs); 523ba10361aSperseant fs = altfs; 524ba10361aSperseant } 525ba10361aSperseant } 526ba10361aSperseant } 527ba10361aSperseant } 528ba10361aSperseant if (check_sb(fs)) { 529ba10361aSperseant free(fs); 530ba10361aSperseant return NULL; 531ba10361aSperseant } 5325d2f3e49Sperseant } 5335d2f3e49Sperseant 534ba10361aSperseant /* Compatibility */ 53558e92fa6Sdholland if (lfs_sb_getversion(fs) < 2) { 536958ff91fSdholland lfs_sb_setsumsize(fs, LFS_V1_SUMMARY_SIZE); 537958ff91fSdholland lfs_sb_setibsize(fs, lfs_sb_getbsize(fs)); 538958ff91fSdholland lfs_sb_sets0addr(fs, lfs_sb_getsboff(fs, 0)); 539576195d5Sdholland lfs_sb_settstamp(fs, lfs_sb_getotstamp(fs)); 540958ff91fSdholland lfs_sb_setfsbtodb(fs, 0); 541ba10361aSperseant } 5425d2f3e49Sperseant 5435d2f3e49Sperseant if (!dummy_read) { 544b6479e9fSchristos fs->lfs_suflags = emalloc(2 * sizeof(u_int32_t *)); 545958ff91fSdholland fs->lfs_suflags[0] = emalloc(lfs_sb_getnseg(fs) * sizeof(u_int32_t)); 546958ff91fSdholland fs->lfs_suflags[1] = emalloc(lfs_sb_getnseg(fs) * sizeof(u_int32_t)); 5475d2f3e49Sperseant } 548ba10361aSperseant 549ba10361aSperseant if (idaddr == 0) 550576195d5Sdholland idaddr = lfs_sb_getidaddr(fs); 5511d4cc6a1Sperseant else 552576195d5Sdholland lfs_sb_setidaddr(fs, idaddr); 5535d2f3e49Sperseant /* NB: If dummy_read!=0, idaddr==0 here so we get a fake inode. */ 5545d2f3e49Sperseant fs->lfs_ivnode = lfs_raw_vget(fs, 555576195d5Sdholland (dummy_read ? LFS_IFILE_INUM : lfs_sb_getifile(fs)), 556576195d5Sdholland devvp->v_fd, idaddr); 5577700866eSperseant if (fs->lfs_ivnode == NULL) 5587700866eSperseant return NULL; 559ba10361aSperseant 560ba10361aSperseant register_vget((void *)fs, lfs_vget); 561ba10361aSperseant 562ba10361aSperseant return fs; 563ba10361aSperseant } 564ba10361aSperseant 565ba10361aSperseant /* 566ba10361aSperseant * Check partial segment validity between fs->lfs_offset and the given goal. 567a73b3b19Sperseant * 568a73b3b19Sperseant * If goal == 0, just keep on going until the segments stop making sense, 569a73b3b19Sperseant * and return the address of the last valid partial segment. 570a73b3b19Sperseant * 571a73b3b19Sperseant * If goal != 0, return the address of the first partial segment that failed, 572a73b3b19Sperseant * or "goal" if we reached it without failure (the partial segment *at* goal 573a73b3b19Sperseant * need not be valid). 574ba10361aSperseant */ 5754f8bc7f7Sdholland ulfs_daddr_t 5764f8bc7f7Sdholland try_verify(struct lfs *osb, struct uvnode *devvp, ulfs_daddr_t goal, int debug) 577ba10361aSperseant { 5784f8bc7f7Sdholland ulfs_daddr_t daddr, odaddr; 579ba10361aSperseant SEGSUM *sp; 580cb2499acSperseant int i, bc, hitclean; 581ba10361aSperseant struct ubuf *bp; 5824f8bc7f7Sdholland ulfs_daddr_t nodirop_daddr; 583ba10361aSperseant u_int64_t serial; 584ba10361aSperseant 585cb2499acSperseant bc = 0; 586cb2499acSperseant hitclean = 0; 587a73b3b19Sperseant odaddr = -1; 588576195d5Sdholland daddr = lfs_sb_getoffset(osb); 589ba10361aSperseant nodirop_daddr = daddr; 590576195d5Sdholland serial = lfs_sb_getserial(osb); 591ba10361aSperseant while (daddr != goal) { 59229f1062bSperseant /* 59329f1062bSperseant * Don't mistakenly read a superblock, if there is one here. 59429f1062bSperseant */ 5959ae6af71Schristos if (lfs_sntod(osb, lfs_dtosn(osb, daddr)) == daddr) { 596958ff91fSdholland if (daddr == lfs_sb_gets0addr(osb)) 5979ae6af71Schristos daddr += lfs_btofsb(osb, LFS_LABELPAD); 59829f1062bSperseant for (i = 0; i < LFS_MAXNUMSB; i++) { 599958ff91fSdholland if (lfs_sb_getsboff(osb, i) < daddr) 60029f1062bSperseant break; 601958ff91fSdholland if (lfs_sb_getsboff(osb, i) == daddr) 6029ae6af71Schristos daddr += lfs_btofsb(osb, LFS_SBPAD); 60329f1062bSperseant } 60429f1062bSperseant } 60529f1062bSperseant 606ba10361aSperseant /* Read in summary block */ 607958ff91fSdholland bread(devvp, LFS_FSBTODB(osb, daddr), lfs_sb_getsumsize(osb), 6084ec44e9dSchopps 0, &bp); 609ba10361aSperseant sp = (SEGSUM *)bp->b_data; 610ba10361aSperseant 611ba10361aSperseant /* 61229f1062bSperseant * Check for a valid segment summary belonging to our fs. 613ba10361aSperseant */ 614*7f065009Sdholland if (lfs_ss_getmagic(osb, sp) != SS_MAGIC || 615*7f065009Sdholland lfs_ss_getident(osb, sp) != lfs_sb_getident(osb) || 616*7f065009Sdholland lfs_ss_getserial(osb, sp) < serial || /* XXX strengthen this */ 617*7f065009Sdholland lfs_ss_getsumsum(osb, sp) != 618*7f065009Sdholland cksum((char *)sp + lfs_ss_getsumstart(osb), 619*7f065009Sdholland lfs_sb_getsumsize(osb) - lfs_ss_getsumstart(osb))) { 620fe44973fSad brelse(bp, 0); 62129f1062bSperseant if (debug) { 622*7f065009Sdholland if (lfs_ss_getmagic(osb, sp) != SS_MAGIC) 623958ff91fSdholland pwarn("pseg at 0x%jx: " 62429f1062bSperseant "wrong magic number\n", 625958ff91fSdholland (uintmax_t)daddr); 626*7f065009Sdholland else if (lfs_ss_getident(osb, sp) != lfs_sb_getident(osb)) 627958ff91fSdholland pwarn("pseg at 0x%jx: " 628958ff91fSdholland "expected ident %jx, got %jx\n", 629958ff91fSdholland (uintmax_t)daddr, 630*7f065009Sdholland (uintmax_t)lfs_ss_getident(osb, sp), 631958ff91fSdholland (uintmax_t)lfs_sb_getident(osb)); 632*7f065009Sdholland else if (lfs_ss_getserial(osb, sp) >= serial) 633958ff91fSdholland pwarn("pseg at 0x%jx: " 634958ff91fSdholland "serial %d < %d\n", 635958ff91fSdholland (uintmax_t)daddr, 636*7f065009Sdholland (int)lfs_ss_getserial(osb, sp), (int)serial); 63729f1062bSperseant else 638958ff91fSdholland pwarn("pseg at 0x%jx: " 63929f1062bSperseant "summary checksum wrong\n", 640958ff91fSdholland (uintmax_t)daddr); 641ba10361aSperseant } 642ba10361aSperseant break; 643ba10361aSperseant } 644*7f065009Sdholland if (debug && lfs_ss_getserial(osb, sp) != serial) 645cb2499acSperseant pwarn("warning, serial=%d ss_serial=%d\n", 646*7f065009Sdholland (int)serial, (int)lfs_ss_getserial(osb, sp)); 647ba10361aSperseant ++serial; 648ba10361aSperseant bc = check_summary(osb, sp, daddr, debug, devvp, NULL); 649ba10361aSperseant if (bc == 0) { 650fe44973fSad brelse(bp, 0); 651ba10361aSperseant break; 652ba10361aSperseant } 65329f1062bSperseant if (debug) 6548d3bc7a9Sdholland pwarn("summary good: 0x%x/%d\n", (uintmax_t)daddr, 655*7f065009Sdholland (int)lfs_ss_getserial(osb, sp)); 656ba10361aSperseant assert (bc > 0); 657ba10361aSperseant odaddr = daddr; 658958ff91fSdholland daddr += lfs_btofsb(osb, lfs_sb_getsumsize(osb) + bc); 6599ae6af71Schristos if (lfs_dtosn(osb, odaddr) != lfs_dtosn(osb, daddr) || 6609ae6af71Schristos lfs_dtosn(osb, daddr) != lfs_dtosn(osb, daddr + 661958ff91fSdholland lfs_btofsb(osb, lfs_sb_getsumsize(osb) + lfs_sb_getbsize(osb)) - 1)) { 662*7f065009Sdholland daddr = lfs_ss_getnext(osb, sp); 663ba10361aSperseant } 66429f1062bSperseant 66529f1062bSperseant /* 66629f1062bSperseant * Check for the beginning and ending of a sequence of 667cb2499acSperseant * dirops. Writes from the cleaner never involve new 668cb2499acSperseant * information, and are always checkpoints; so don't try 669cb2499acSperseant * to roll forward through them. Likewise, psegs written 670cb2499acSperseant * by a previous roll-forward attempt are not interesting. 67129f1062bSperseant */ 672*7f065009Sdholland if (lfs_ss_getflags(osb, sp) & (SS_CLEAN | SS_RFW)) 673cb2499acSperseant hitclean = 1; 674*7f065009Sdholland if (hitclean == 0 && (lfs_ss_getflags(osb, sp) & SS_CONT) == 0) 675ba10361aSperseant nodirop_daddr = daddr; 67629f1062bSperseant 677fe44973fSad brelse(bp, 0); 678ba10361aSperseant } 679ba10361aSperseant 680ba10361aSperseant if (goal == 0) 681ba10361aSperseant return nodirop_daddr; 682ba10361aSperseant else 683ba10361aSperseant return daddr; 684ba10361aSperseant } 685ba10361aSperseant 686ba10361aSperseant /* Use try_verify to check whether the newer superblock is valid. */ 687ba10361aSperseant struct lfs * 688ba10361aSperseant lfs_verify(struct lfs *sb0, struct lfs *sb1, struct uvnode *devvp, int debug) 689ba10361aSperseant { 6904f8bc7f7Sdholland ulfs_daddr_t daddr; 691ba10361aSperseant struct lfs *osb, *nsb; 692ba10361aSperseant 693ba10361aSperseant /* 694ba10361aSperseant * Verify the checkpoint of the newer superblock, 695ba10361aSperseant * if the timestamp/serial number of the two superblocks is 696ba10361aSperseant * different. 697ba10361aSperseant */ 698ba10361aSperseant 6992b11c546Slukem osb = NULL; 700ba10361aSperseant if (debug) 701576195d5Sdholland pwarn("sb0 %ju, sb1 %ju", 702576195d5Sdholland (uintmax_t) lfs_sb_getserial(sb0), 703576195d5Sdholland (uintmax_t) lfs_sb_getserial(sb1)); 704ba10361aSperseant 70558e92fa6Sdholland if ((lfs_sb_getversion(sb0) == 1 && 706576195d5Sdholland lfs_sb_getotstamp(sb0) != lfs_sb_getotstamp(sb1)) || 70758e92fa6Sdholland (lfs_sb_getversion(sb0) > 1 && 708576195d5Sdholland lfs_sb_getserial(sb0) != lfs_sb_getserial(sb1))) { 70958e92fa6Sdholland if (lfs_sb_getversion(sb0) == 1) { 710576195d5Sdholland if (lfs_sb_getotstamp(sb0) > lfs_sb_getotstamp(sb1)) { 711ba10361aSperseant osb = sb1; 712ba10361aSperseant nsb = sb0; 713ba10361aSperseant } else { 714ba10361aSperseant osb = sb0; 715ba10361aSperseant nsb = sb1; 716ba10361aSperseant } 717ba10361aSperseant } else { 718576195d5Sdholland if (lfs_sb_getserial(sb0) > lfs_sb_getserial(sb1)) { 719ba10361aSperseant osb = sb1; 720ba10361aSperseant nsb = sb0; 721ba10361aSperseant } else { 722ba10361aSperseant osb = sb0; 723ba10361aSperseant nsb = sb1; 724ba10361aSperseant } 725ba10361aSperseant } 726ba10361aSperseant if (debug) { 727ba10361aSperseant printf("Attempting to verify newer checkpoint..."); 728ba10361aSperseant fflush(stdout); 729ba10361aSperseant } 730576195d5Sdholland daddr = try_verify(osb, devvp, lfs_sb_getoffset(nsb), debug); 731ba10361aSperseant 732ba10361aSperseant if (debug) 733ba10361aSperseant printf("done.\n"); 734576195d5Sdholland if (daddr == lfs_sb_getoffset(nsb)) { 735576195d5Sdholland pwarn("** Newer checkpoint verified; recovered %jd seconds of data\n", 736576195d5Sdholland (intmax_t)(lfs_sb_gettstamp(nsb) - lfs_sb_gettstamp(osb))); 737ba10361aSperseant sbdirty(); 738ba10361aSperseant } else { 739576195d5Sdholland pwarn("** Newer checkpoint invalid; lost %jd seconds of data\n", (intmax_t)(lfs_sb_gettstamp(nsb) - lfs_sb_gettstamp(osb))); 740ba10361aSperseant } 741576195d5Sdholland return (daddr == lfs_sb_getoffset(nsb) ? nsb : osb); 742ba10361aSperseant } 743ba10361aSperseant /* Nothing to check */ 744ba10361aSperseant return osb; 745ba10361aSperseant } 746ba10361aSperseant 747ba10361aSperseant /* Verify a partial-segment summary; return the number of bytes on disk. */ 748ba10361aSperseant int 7494f8bc7f7Sdholland check_summary(struct lfs *fs, SEGSUM *sp, ulfs_daddr_t pseg_addr, int debug, 7504f8bc7f7Sdholland struct uvnode *devvp, void (func(ulfs_daddr_t, FINFO *))) 751ba10361aSperseant { 752ba10361aSperseant FINFO *fp; 753ba10361aSperseant int bc; /* Bytes in partial segment */ 754ba10361aSperseant int nblocks; 7554016dae3Schristos ulfs_daddr_t daddr; 7564f8bc7f7Sdholland ulfs_daddr_t *dp, *idp; 757ba10361aSperseant struct ubuf *bp; 758ba10361aSperseant int i, j, k, datac, len; 759ba10361aSperseant u_int32_t *datap; 760ba10361aSperseant u_int32_t ccksum; 761ba10361aSperseant 762ba10361aSperseant /* We've already checked the sumsum, just do the data bounds and sum */ 763ba10361aSperseant 764ba10361aSperseant /* Count the blocks. */ 765*7f065009Sdholland nblocks = howmany(lfs_ss_getninos(fs, sp), LFS_INOPB(fs)); 76658e92fa6Sdholland bc = nblocks << (lfs_sb_getversion(fs) > 1 ? lfs_sb_getffshift(fs) : lfs_sb_getbshift(fs)); 767ba10361aSperseant assert(bc >= 0); 768ba10361aSperseant 769*7f065009Sdholland fp = SEGSUM_FINFOBASE(fs, sp); 770*7f065009Sdholland for (i = 0; i < lfs_ss_getnfinfo(fs, sp); i++) { 771ba10361aSperseant nblocks += fp->fi_nblocks; 772ba10361aSperseant bc += fp->fi_lastlength + ((fp->fi_nblocks - 1) 773958ff91fSdholland << lfs_sb_getbshift(fs)); 774ba10361aSperseant assert(bc >= 0); 775*7f065009Sdholland fp = NEXT_FINFO(fs, fp); 776958ff91fSdholland if (((char *)fp) - (char *)sp > lfs_sb_getsumsize(fs)) 77729f1062bSperseant return 0; 778ba10361aSperseant } 779b6479e9fSchristos datap = emalloc(nblocks * sizeof(*datap)); 780ba10361aSperseant datac = 0; 781ba10361aSperseant 7824f8bc7f7Sdholland dp = (ulfs_daddr_t *) sp; 783958ff91fSdholland dp += lfs_sb_getsumsize(fs) / sizeof(ulfs_daddr_t); 784ba10361aSperseant dp--; 785ba10361aSperseant 786ba10361aSperseant idp = dp; 787958ff91fSdholland daddr = pseg_addr + lfs_btofsb(fs, lfs_sb_getsumsize(fs)); 788ba10361aSperseant fp = (FINFO *) (sp + 1); 789ba10361aSperseant for (i = 0, j = 0; 790*7f065009Sdholland i < lfs_ss_getnfinfo(fs, sp) || j < howmany(lfs_ss_getninos(fs, sp), LFS_INOPB(fs)); i++) { 791*7f065009Sdholland if (i >= lfs_ss_getnfinfo(fs, sp) && *idp != daddr) { 7925d2f3e49Sperseant pwarn("Not enough inode blocks in pseg at 0x%" PRIx32 793ba10361aSperseant ": found %d, wanted %d\n", 794*7f065009Sdholland pseg_addr, j, howmany(lfs_ss_getninos(fs, sp), 795*7f065009Sdholland LFS_INOPB(fs))); 796ba10361aSperseant if (debug) 7975d2f3e49Sperseant pwarn("*idp=%x, daddr=%" PRIx32 "\n", *idp, 798ba10361aSperseant daddr); 799ba10361aSperseant break; 800ba10361aSperseant } 801*7f065009Sdholland while (j < howmany(lfs_ss_getninos(fs, sp), LFS_INOPB(fs)) && *idp == daddr) { 802958ff91fSdholland bread(devvp, LFS_FSBTODB(fs, daddr), lfs_sb_getibsize(fs), 8034ec44e9dSchopps 0, &bp); 804ba10361aSperseant datap[datac++] = ((u_int32_t *) (bp->b_data))[0]; 805fe44973fSad brelse(bp, 0); 806ba10361aSperseant 807ba10361aSperseant ++j; 808958ff91fSdholland daddr += lfs_btofsb(fs, lfs_sb_getibsize(fs)); 809ba10361aSperseant --idp; 810ba10361aSperseant } 811*7f065009Sdholland if (i < lfs_ss_getnfinfo(fs, sp)) { 812ba10361aSperseant if (func) 813ba10361aSperseant func(daddr, fp); 814ba10361aSperseant for (k = 0; k < fp->fi_nblocks; k++) { 815ba10361aSperseant len = (k == fp->fi_nblocks - 1 ? 816ba10361aSperseant fp->fi_lastlength 817576195d5Sdholland : lfs_sb_getbsize(fs)); 8189ae6af71Schristos bread(devvp, LFS_FSBTODB(fs, daddr), len, 8194ec44e9dSchopps 0, &bp); 820ba10361aSperseant datap[datac++] = ((u_int32_t *) (bp->b_data))[0]; 821fe44973fSad brelse(bp, 0); 8229ae6af71Schristos daddr += lfs_btofsb(fs, len); 823ba10361aSperseant } 824*7f065009Sdholland fp = NEXT_FINFO(fs, fp); 825ba10361aSperseant } 826ba10361aSperseant } 827ba10361aSperseant 828ba10361aSperseant if (datac != nblocks) { 8298d3bc7a9Sdholland pwarn("Partial segment at 0x%jx expected %d blocks counted %d\n", 8308d3bc7a9Sdholland (intmax_t)pseg_addr, nblocks, datac); 831ba10361aSperseant } 832*7f065009Sdholland /* XXX ondisk32 */ 833ba10361aSperseant ccksum = cksum(datap, nblocks * sizeof(u_int32_t)); 834ba10361aSperseant /* Check the data checksum */ 835*7f065009Sdholland if (ccksum != lfs_ss_getdatasum(fs, sp)) { 8368d3bc7a9Sdholland pwarn("Partial segment at 0x%jx data checksum" 837ba10361aSperseant " mismatch: given 0x%x, computed 0x%x\n", 838*7f065009Sdholland (uintmax_t)pseg_addr, lfs_ss_getdatasum(fs, sp), ccksum); 839ba10361aSperseant free(datap); 840ba10361aSperseant return 0; 841ba10361aSperseant } 842ba10361aSperseant free(datap); 843ba10361aSperseant assert(bc >= 0); 844ba10361aSperseant return bc; 845ba10361aSperseant } 846ba10361aSperseant 847ba10361aSperseant /* print message and exit */ 848ba10361aSperseant void 84917c417f1Sdholland my_vpanic(int fatal, const char *fmt, va_list ap) 85017c417f1Sdholland { 85117c417f1Sdholland (void) vprintf(fmt, ap); 85217c417f1Sdholland exit(8); 85317c417f1Sdholland } 85417c417f1Sdholland 85517c417f1Sdholland void 856ba10361aSperseant call_panic(const char *fmt, ...) 857ba10361aSperseant { 858ba10361aSperseant va_list ap; 859ba10361aSperseant 860ba10361aSperseant va_start(ap, fmt); 86117c417f1Sdholland panic_func(1, fmt, ap); 862ba10361aSperseant va_end(ap); 863ba10361aSperseant } 8644b8db838Sperseant 8654b8db838Sperseant /* Allocate a new inode. */ 8664b8db838Sperseant struct uvnode * 8674b8db838Sperseant lfs_valloc(struct lfs *fs, ino_t ino) 8684b8db838Sperseant { 8694b8db838Sperseant struct ubuf *bp, *cbp; 870daf91f9bSdholland IFILE *ifp; 8714b8db838Sperseant ino_t new_ino; 8724b8db838Sperseant int error; 8734b8db838Sperseant CLEANERINFO *cip; 8744b8db838Sperseant 8754b8db838Sperseant /* Get the head of the freelist. */ 8764b8db838Sperseant LFS_GET_HEADFREE(fs, cip, cbp, &new_ino); 8774b8db838Sperseant 8784b8db838Sperseant /* 8794b8db838Sperseant * Remove the inode from the free list and write the new start 8804b8db838Sperseant * of the free list into the superblock. 8814b8db838Sperseant */ 8824b8db838Sperseant LFS_IENTRY(ifp, fs, new_ino, bp); 883daf91f9bSdholland if (lfs_if_getdaddr(fs, ifp) != LFS_UNUSED_DADDR) 8844b8db838Sperseant panic("lfs_valloc: inuse inode %d on the free list", new_ino); 885daf91f9bSdholland LFS_PUT_HEADFREE(fs, cip, cbp, lfs_if_getnextfree(fs, ifp)); 8864b8db838Sperseant 887fe44973fSad brelse(bp, 0); 8884b8db838Sperseant 8894b8db838Sperseant /* Extend IFILE so that the next lfs_valloc will succeed. */ 890576195d5Sdholland if (lfs_sb_getfreehd(fs) == LFS_UNUSED_INUM) { 8914b8db838Sperseant if ((error = extend_ifile(fs)) != 0) { 8924b8db838Sperseant LFS_PUT_HEADFREE(fs, cip, cbp, new_ino); 8934b8db838Sperseant return NULL; 8944b8db838Sperseant } 8954b8db838Sperseant } 8964b8db838Sperseant 8974b8db838Sperseant /* Set superblock modified bit and increment file count. */ 8984b8db838Sperseant sbdirty(); 899576195d5Sdholland lfs_sb_addnfiles(fs, 1); 9004b8db838Sperseant 9014b8db838Sperseant return lfs_raw_vget(fs, ino, fs->lfs_devvp->v_fd, 0x0); 9024b8db838Sperseant } 9034b8db838Sperseant 90429f1062bSperseant #ifdef IN_FSCK_LFS 90529f1062bSperseant void reset_maxino(ino_t); 90629f1062bSperseant #endif 90729f1062bSperseant 9084b8db838Sperseant /* 9094b8db838Sperseant * Add a new block to the Ifile, to accommodate future file creations. 9104b8db838Sperseant */ 9114b8db838Sperseant int 9124b8db838Sperseant extend_ifile(struct lfs *fs) 9134b8db838Sperseant { 9144b8db838Sperseant struct uvnode *vp; 9154b8db838Sperseant struct inode *ip; 916daf91f9bSdholland IFILE64 *ifp64; 917daf91f9bSdholland IFILE32 *ifp32; 9184b8db838Sperseant IFILE_V1 *ifp_v1; 9194b8db838Sperseant struct ubuf *bp, *cbp; 9204b8db838Sperseant daddr_t i, blkno, max; 9214b8db838Sperseant ino_t oldlast; 9224b8db838Sperseant CLEANERINFO *cip; 9234b8db838Sperseant 9244b8db838Sperseant vp = fs->lfs_ivnode; 9254b8db838Sperseant ip = VTOI(vp); 9269ae6af71Schristos blkno = lfs_lblkno(fs, ip->i_ffs1_size); 9274b8db838Sperseant 928576195d5Sdholland lfs_balloc(vp, ip->i_ffs1_size, lfs_sb_getbsize(fs), &bp); 929576195d5Sdholland ip->i_ffs1_size += lfs_sb_getbsize(fs); 93029f1062bSperseant ip->i_flag |= IN_MODIFIED; 9314b8db838Sperseant 932576195d5Sdholland i = (blkno - lfs_sb_getsegtabsz(fs) - lfs_sb_getcleansz(fs)) * 933576195d5Sdholland lfs_sb_getifpb(fs); 9344b8db838Sperseant LFS_GET_HEADFREE(fs, cip, cbp, &oldlast); 9354b8db838Sperseant LFS_PUT_HEADFREE(fs, cip, cbp, i); 936576195d5Sdholland max = i + lfs_sb_getifpb(fs); 937576195d5Sdholland lfs_sb_subbfree(fs, lfs_btofsb(fs, lfs_sb_getbsize(fs))); 9384b8db838Sperseant 939daf91f9bSdholland if (fs->lfs_is64) { 940daf91f9bSdholland for (ifp64 = (IFILE64 *)bp->b_data; i < max; ++ifp64) { 941daf91f9bSdholland ifp64->if_version = 1; 942daf91f9bSdholland ifp64->if_daddr = LFS_UNUSED_DADDR; 943daf91f9bSdholland ifp64->if_nextfree = ++i; 944daf91f9bSdholland } 945daf91f9bSdholland ifp64--; 946daf91f9bSdholland ifp64->if_nextfree = oldlast; 947daf91f9bSdholland } else if (lfs_sb_getversion(fs) > 1) { 948daf91f9bSdholland for (ifp32 = (IFILE32 *)bp->b_data; i < max; ++ifp32) { 949daf91f9bSdholland ifp32->if_version = 1; 950daf91f9bSdholland ifp32->if_daddr = LFS_UNUSED_DADDR; 951daf91f9bSdholland ifp32->if_nextfree = ++i; 952daf91f9bSdholland } 953daf91f9bSdholland ifp32--; 954daf91f9bSdholland ifp32->if_nextfree = oldlast; 955daf91f9bSdholland } else { 9564b8db838Sperseant for (ifp_v1 = (IFILE_V1 *)bp->b_data; i < max; ++ifp_v1) { 9574b8db838Sperseant ifp_v1->if_version = 1; 9584b8db838Sperseant ifp_v1->if_daddr = LFS_UNUSED_DADDR; 9594b8db838Sperseant ifp_v1->if_nextfree = ++i; 9604b8db838Sperseant } 9614b8db838Sperseant ifp_v1--; 9624b8db838Sperseant ifp_v1->if_nextfree = oldlast; 9634b8db838Sperseant } 9644b8db838Sperseant LFS_PUT_TAILFREE(fs, cip, cbp, max - 1); 9654b8db838Sperseant 9664b8db838Sperseant LFS_BWRITE_LOG(bp); 9674b8db838Sperseant 96829f1062bSperseant #ifdef IN_FSCK_LFS 969958ff91fSdholland reset_maxino(((ip->i_ffs1_size >> lfs_sb_getbshift(fs)) 970576195d5Sdholland - lfs_sb_getsegtabsz(fs) 971576195d5Sdholland - lfs_sb_getcleansz(fs)) * lfs_sb_getifpb(fs)); 97229f1062bSperseant #endif 9734b8db838Sperseant return 0; 9744b8db838Sperseant } 9754b8db838Sperseant 97629f1062bSperseant /* 97729f1062bSperseant * Allocate a block, and to inode and filesystem block accounting for it 97829f1062bSperseant * and for any indirect blocks the may need to be created in order for 97929f1062bSperseant * this block to be created. 98029f1062bSperseant * 98129f1062bSperseant * Blocks which have never been accounted for (i.e., which "do not exist") 9824f8bc7f7Sdholland * have disk address 0, which is translated by ulfs_bmap to the special value 9834f8bc7f7Sdholland * UNASSIGNED == -1, as in the historical ULFS. 98429f1062bSperseant * 98529f1062bSperseant * Blocks which have been accounted for but which have not yet been written 98629f1062bSperseant * to disk are given the new special disk address UNWRITTEN == -2, so that 98729f1062bSperseant * they can be differentiated from completely new blocks. 98829f1062bSperseant */ 98929f1062bSperseant int 99029f1062bSperseant lfs_balloc(struct uvnode *vp, off_t startoffset, int iosize, struct ubuf **bpp) 99129f1062bSperseant { 99229f1062bSperseant int offset; 99329f1062bSperseant daddr_t daddr, idaddr; 99429f1062bSperseant struct ubuf *ibp, *bp; 99529f1062bSperseant struct inode *ip; 99629f1062bSperseant struct lfs *fs; 9974f8bc7f7Sdholland struct indir indirs[ULFS_NIADDR+2], *idp; 99829f1062bSperseant daddr_t lbn, lastblock; 99979748725Smlelstv int bcount; 100029f1062bSperseant int error, frags, i, nsize, osize, num; 100129f1062bSperseant 100229f1062bSperseant ip = VTOI(vp); 100329f1062bSperseant fs = ip->i_lfs; 10049ae6af71Schristos offset = lfs_blkoff(fs, startoffset); 10059ae6af71Schristos lbn = lfs_lblkno(fs, startoffset); 100629f1062bSperseant 100729f1062bSperseant /* 100829f1062bSperseant * Three cases: it's a block beyond the end of file, it's a block in 100929f1062bSperseant * the file that may or may not have been assigned a disk address or 101029f1062bSperseant * we're writing an entire block. 101129f1062bSperseant * 101229f1062bSperseant * Note, if the daddr is UNWRITTEN, the block already exists in 101329f1062bSperseant * the cache (it was read or written earlier). If so, make sure 101429f1062bSperseant * we don't count it as a new block or zero out its contents. If 101529f1062bSperseant * it did not, make sure we allocate any necessary indirect 101629f1062bSperseant * blocks. 101729f1062bSperseant * 101829f1062bSperseant * If we are writing a block beyond the end of the file, we need to 101929f1062bSperseant * check if the old last block was a fragment. If it was, we need 102029f1062bSperseant * to rewrite it. 102129f1062bSperseant */ 102229f1062bSperseant 102329f1062bSperseant if (bpp) 102429f1062bSperseant *bpp = NULL; 102529f1062bSperseant 102629f1062bSperseant /* Check for block beyond end of file and fragment extension needed. */ 10279ae6af71Schristos lastblock = lfs_lblkno(fs, ip->i_ffs1_size); 10284f8bc7f7Sdholland if (lastblock < ULFS_NDADDR && lastblock < lbn) { 10299ae6af71Schristos osize = lfs_blksize(fs, ip, lastblock); 1030576195d5Sdholland if (osize < lfs_sb_getbsize(fs) && osize > 0) { 1031576195d5Sdholland if ((error = lfs_fragextend(vp, osize, lfs_sb_getbsize(fs), 103229f1062bSperseant lastblock, 103329f1062bSperseant (bpp ? &bp : NULL)))) 103429f1062bSperseant return (error); 1035576195d5Sdholland ip->i_ffs1_size = (lastblock + 1) * lfs_sb_getbsize(fs); 103629f1062bSperseant ip->i_flag |= IN_CHANGE | IN_UPDATE; 103729f1062bSperseant if (bpp) 103829f1062bSperseant (void) VOP_BWRITE(bp); 103929f1062bSperseant } 104029f1062bSperseant } 104129f1062bSperseant 104229f1062bSperseant /* 104329f1062bSperseant * If the block we are writing is a direct block, it's the last 104429f1062bSperseant * block in the file, and offset + iosize is less than a full 104529f1062bSperseant * block, we can write one or more fragments. There are two cases: 104629f1062bSperseant * the block is brand new and we should allocate it the correct 104729f1062bSperseant * size or it already exists and contains some fragments and 104829f1062bSperseant * may need to extend it. 104929f1062bSperseant */ 10509ae6af71Schristos if (lbn < ULFS_NDADDR && lfs_lblkno(fs, ip->i_ffs1_size) <= lbn) { 10519ae6af71Schristos osize = lfs_blksize(fs, ip, lbn); 10529ae6af71Schristos nsize = lfs_fragroundup(fs, offset + iosize); 10539ae6af71Schristos if (lfs_lblktosize(fs, lbn) >= ip->i_ffs1_size) { 105429f1062bSperseant /* Brand new block or fragment */ 10559ae6af71Schristos frags = lfs_numfrags(fs, nsize); 105629f1062bSperseant if (bpp) { 105729f1062bSperseant *bpp = bp = getblk(vp, lbn, nsize); 105829f1062bSperseant bp->b_blkno = UNWRITTEN; 105929f1062bSperseant } 106079748725Smlelstv ip->i_lfs_effnblks += frags; 1061576195d5Sdholland lfs_sb_subbfree(fs, frags); 106229f1062bSperseant ip->i_ffs1_db[lbn] = UNWRITTEN; 106329f1062bSperseant } else { 106429f1062bSperseant if (nsize <= osize) { 106529f1062bSperseant /* No need to extend */ 10665d2bff06Shannken if (bpp && (error = bread(vp, lbn, osize, 10674ec44e9dSchopps 0, &bp))) 106829f1062bSperseant return error; 106929f1062bSperseant } else { 107029f1062bSperseant /* Extend existing block */ 107129f1062bSperseant if ((error = 107229f1062bSperseant lfs_fragextend(vp, osize, nsize, lbn, 107329f1062bSperseant (bpp ? &bp : NULL)))) 107429f1062bSperseant return error; 107529f1062bSperseant } 107629f1062bSperseant if (bpp) 107729f1062bSperseant *bpp = bp; 107829f1062bSperseant } 107929f1062bSperseant return 0; 108029f1062bSperseant } 108129f1062bSperseant 10824f8bc7f7Sdholland error = ulfs_bmaparray(fs, vp, lbn, &daddr, &indirs[0], &num); 108329f1062bSperseant if (error) 108429f1062bSperseant return (error); 108529f1062bSperseant 108629f1062bSperseant daddr = (daddr_t)((int32_t)daddr); /* XXX ondisk32 */ 108729f1062bSperseant 108829f1062bSperseant /* 108929f1062bSperseant * Do byte accounting all at once, so we can gracefully fail *before* 109029f1062bSperseant * we start assigning blocks. 109129f1062bSperseant */ 10929ae6af71Schristos frags = LFS_FSBTODB(fs, 1); /* frags = VFSTOULFS(vp->v_mount)->um_seqinc; */ 109329f1062bSperseant bcount = 0; 109429f1062bSperseant if (daddr == UNASSIGNED) { 109579748725Smlelstv bcount = frags; 109629f1062bSperseant } 109729f1062bSperseant for (i = 1; i < num; ++i) { 109829f1062bSperseant if (!indirs[i].in_exists) { 109979748725Smlelstv bcount += frags; 110029f1062bSperseant } 110129f1062bSperseant } 1102576195d5Sdholland lfs_sb_subbfree(fs, bcount); 110329f1062bSperseant ip->i_lfs_effnblks += bcount; 110429f1062bSperseant 110529f1062bSperseant if (daddr == UNASSIGNED) { 110629f1062bSperseant if (num > 0 && ip->i_ffs1_ib[indirs[0].in_off] == 0) { 110729f1062bSperseant ip->i_ffs1_ib[indirs[0].in_off] = UNWRITTEN; 110829f1062bSperseant } 110929f1062bSperseant 111029f1062bSperseant /* 111129f1062bSperseant * Create new indirect blocks if necessary 111229f1062bSperseant */ 111329f1062bSperseant if (num > 1) { 111429f1062bSperseant idaddr = ip->i_ffs1_ib[indirs[0].in_off]; 111529f1062bSperseant for (i = 1; i < num; ++i) { 111629f1062bSperseant ibp = getblk(vp, indirs[i].in_lbn, 1117576195d5Sdholland lfs_sb_getbsize(fs)); 111829f1062bSperseant if (!indirs[i].in_exists) { 111929f1062bSperseant memset(ibp->b_data, 0, ibp->b_bufsize); 112029f1062bSperseant ibp->b_blkno = UNWRITTEN; 112129f1062bSperseant } else if (!(ibp->b_flags & (B_DELWRI | B_DONE))) { 11229ae6af71Schristos ibp->b_blkno = LFS_FSBTODB(fs, idaddr); 112329f1062bSperseant ibp->b_flags |= B_READ; 112429f1062bSperseant VOP_STRATEGY(ibp); 112529f1062bSperseant } 112629f1062bSperseant /* 112729f1062bSperseant * This block exists, but the next one may not. 112829f1062bSperseant * If that is the case mark it UNWRITTEN to 112929f1062bSperseant * keep the accounting straight. 113029f1062bSperseant */ 113129f1062bSperseant /* XXX ondisk32 */ 113229f1062bSperseant if (((int32_t *)ibp->b_data)[indirs[i].in_off] == 0) 113329f1062bSperseant ((int32_t *)ibp->b_data)[indirs[i].in_off] = 113429f1062bSperseant UNWRITTEN; 113529f1062bSperseant /* XXX ondisk32 */ 113629f1062bSperseant idaddr = ((int32_t *)ibp->b_data)[indirs[i].in_off]; 113729f1062bSperseant if ((error = VOP_BWRITE(ibp))) 113829f1062bSperseant return error; 113929f1062bSperseant } 114029f1062bSperseant } 114129f1062bSperseant } 114229f1062bSperseant 114329f1062bSperseant 114429f1062bSperseant /* 114529f1062bSperseant * Get the existing block from the cache, if requested. 114629f1062bSperseant */ 114729f1062bSperseant if (bpp) 11489ae6af71Schristos *bpp = bp = getblk(vp, lbn, lfs_blksize(fs, ip, lbn)); 114929f1062bSperseant 115029f1062bSperseant /* 115129f1062bSperseant * The block we are writing may be a brand new block 115229f1062bSperseant * in which case we need to do accounting. 115329f1062bSperseant * 11544f8bc7f7Sdholland * We can tell a truly new block because ulfs_bmaparray will say 115529f1062bSperseant * it is UNASSIGNED. Once we allocate it we will assign it the 115629f1062bSperseant * disk address UNWRITTEN. 115729f1062bSperseant */ 115829f1062bSperseant if (daddr == UNASSIGNED) { 115929f1062bSperseant if (bpp) { 116029f1062bSperseant /* Note the new address */ 116129f1062bSperseant bp->b_blkno = UNWRITTEN; 116229f1062bSperseant } 116329f1062bSperseant 116429f1062bSperseant switch (num) { 116529f1062bSperseant case 0: 116629f1062bSperseant ip->i_ffs1_db[lbn] = UNWRITTEN; 116729f1062bSperseant break; 116829f1062bSperseant case 1: 116929f1062bSperseant ip->i_ffs1_ib[indirs[0].in_off] = UNWRITTEN; 117029f1062bSperseant break; 117129f1062bSperseant default: 117229f1062bSperseant idp = &indirs[num - 1]; 1173576195d5Sdholland if (bread(vp, idp->in_lbn, lfs_sb_getbsize(fs), 0, &ibp)) 117429f1062bSperseant panic("lfs_balloc: bread bno %lld", 117529f1062bSperseant (long long)idp->in_lbn); 117629f1062bSperseant /* XXX ondisk32 */ 117729f1062bSperseant ((int32_t *)ibp->b_data)[idp->in_off] = UNWRITTEN; 117829f1062bSperseant VOP_BWRITE(ibp); 117929f1062bSperseant } 118029f1062bSperseant } else if (bpp && !(bp->b_flags & (B_DONE|B_DELWRI))) { 118129f1062bSperseant /* 118229f1062bSperseant * Not a brand new block, also not in the cache; 118329f1062bSperseant * read it in from disk. 118429f1062bSperseant */ 1185576195d5Sdholland if (iosize == lfs_sb_getbsize(fs)) 118629f1062bSperseant /* Optimization: I/O is unnecessary. */ 118729f1062bSperseant bp->b_blkno = daddr; 118829f1062bSperseant else { 118929f1062bSperseant /* 119029f1062bSperseant * We need to read the block to preserve the 119129f1062bSperseant * existing bytes. 119229f1062bSperseant */ 119329f1062bSperseant bp->b_blkno = daddr; 119429f1062bSperseant bp->b_flags |= B_READ; 119529f1062bSperseant VOP_STRATEGY(bp); 119629f1062bSperseant return 0; 119729f1062bSperseant } 119829f1062bSperseant } 119929f1062bSperseant 120029f1062bSperseant return (0); 120129f1062bSperseant } 120229f1062bSperseant 120329f1062bSperseant int 120429f1062bSperseant lfs_fragextend(struct uvnode *vp, int osize, int nsize, daddr_t lbn, 120529f1062bSperseant struct ubuf **bpp) 120629f1062bSperseant { 120729f1062bSperseant struct inode *ip; 120829f1062bSperseant struct lfs *fs; 120979748725Smlelstv int frags; 121029f1062bSperseant int error; 121129f1062bSperseant 121229f1062bSperseant ip = VTOI(vp); 121329f1062bSperseant fs = ip->i_lfs; 12149ae6af71Schristos frags = (long)lfs_numfrags(fs, nsize - osize); 121529f1062bSperseant error = 0; 121629f1062bSperseant 121729f1062bSperseant /* 121829f1062bSperseant * If we are not asked to actually return the block, all we need 121929f1062bSperseant * to do is allocate space for it. UBC will handle dirtying the 122029f1062bSperseant * appropriate things and making sure it all goes to disk. 122129f1062bSperseant * Don't bother to read in that case. 122229f1062bSperseant */ 12234ec44e9dSchopps if (bpp && (error = bread(vp, lbn, osize, 0, bpp))) { 1224fe44973fSad brelse(*bpp, 0); 122529f1062bSperseant goto out; 122629f1062bSperseant } 122729f1062bSperseant 1228576195d5Sdholland lfs_sb_subbfree(fs, frags); 122979748725Smlelstv ip->i_lfs_effnblks += frags; 123029f1062bSperseant ip->i_flag |= IN_CHANGE | IN_UPDATE; 123129f1062bSperseant 123229f1062bSperseant if (bpp) { 1233b6479e9fSchristos (*bpp)->b_data = erealloc((*bpp)->b_data, nsize); 1234b6479e9fSchristos (void)memset((*bpp)->b_data + osize, 0, nsize - osize); 123529f1062bSperseant } 123629f1062bSperseant 123729f1062bSperseant out: 123829f1062bSperseant return (error); 123929f1062bSperseant } 1240