1*93f62a9eStedu /* $OpenBSD: ffs_balloc.c,v 1.37 2011/07/04 04:30:41 tedu Exp $ */ 2d28910b8Sniklas /* $NetBSD: ffs_balloc.c,v 1.3 1996/02/09 22:22:21 christos Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /* 5f4342418Spedro * Copyright (c) 2002 Networks Associates Technology, Inc. 6f4342418Spedro * All rights reserved. 7f4342418Spedro * 8f4342418Spedro * This software was developed for the FreeBSD Project by Marshall 9f4342418Spedro * Kirk McKusick and Network Associates Laboratories, the Security 10f4342418Spedro * Research Division of Network Associates, Inc. under DARPA/SPAWAR 11f4342418Spedro * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS 12f4342418Spedro * research program. 13f4342418Spedro * 14df930be7Sderaadt * Copyright (c) 1982, 1986, 1989, 1993 15df930be7Sderaadt * The Regents of the University of California. All rights reserved. 16df930be7Sderaadt * 17df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 18df930be7Sderaadt * modification, are permitted provided that the following conditions 19df930be7Sderaadt * are met: 20df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 21df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 22df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 23df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 24df930be7Sderaadt * documentation and/or other materials provided with the distribution. 2529295d1cSmillert * 3. Neither the name of the University nor the names of its contributors 26df930be7Sderaadt * may be used to endorse or promote products derived from this software 27df930be7Sderaadt * without specific prior written permission. 28df930be7Sderaadt * 29df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39df930be7Sderaadt * SUCH DAMAGE. 40df930be7Sderaadt * 41df930be7Sderaadt * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93 42df930be7Sderaadt */ 43df930be7Sderaadt 44df930be7Sderaadt #include <sys/param.h> 45df930be7Sderaadt #include <sys/systm.h> 46df930be7Sderaadt #include <sys/buf.h> 47df930be7Sderaadt #include <sys/proc.h> 48df930be7Sderaadt #include <sys/file.h> 4907feb63cScsapuntz #include <sys/mount.h> 50df930be7Sderaadt #include <sys/vnode.h> 51df930be7Sderaadt 526348b7ebSart #include <uvm/uvm_extern.h> 536348b7ebSart 54df930be7Sderaadt #include <ufs/ufs/quota.h> 55df930be7Sderaadt #include <ufs/ufs/inode.h> 56fb844963Spedro #include <ufs/ufs/ufsmount.h> 57df930be7Sderaadt #include <ufs/ufs/ufs_extern.h> 58df930be7Sderaadt 59df930be7Sderaadt #include <ufs/ffs/fs.h> 60df930be7Sderaadt #include <ufs/ffs/ffs_extern.h> 61df930be7Sderaadt 62f4342418Spedro int ffs1_balloc(struct inode *, off_t, int, struct ucred *, int, struct buf **); 63f4342418Spedro #ifdef FFS2 64f4342418Spedro int ffs2_balloc(struct inode *, off_t, int, struct ucred *, int, struct buf **); 65f4342418Spedro #endif 66f4342418Spedro 67df930be7Sderaadt /* 68df930be7Sderaadt * Balloc defines the structure of file system storage 69df930be7Sderaadt * by allocating the physical blocks on a device given 70df930be7Sderaadt * the inode and the logical block number in a file. 71df930be7Sderaadt */ 72d28910b8Sniklas int 73f4342418Spedro ffs1_balloc(struct inode *ip, off_t startoffset, int size, struct ucred *cred, 74b080ad39Scsapuntz int flags, struct buf **bpp) 7507feb63cScsapuntz { 768add4794Sotto daddr64_t lbn, nb, newb, pref; 7707feb63cScsapuntz struct fs *fs; 78df930be7Sderaadt struct buf *bp, *nbp; 7907feb63cScsapuntz struct vnode *vp; 80fcf048c1Spedro struct proc *p; 81df930be7Sderaadt struct indir indirs[NIADDR + 2]; 828add4794Sotto int32_t *bap; 8307feb63cScsapuntz int deallocated, osize, nsize, num, i, error; 84a09be2a2Spedro int32_t *allocib, *blkp, *allocblk, allociblk[NIADDR+1]; 856cd4677cSart int unwindidx = -1; 86df930be7Sderaadt 87b080ad39Scsapuntz vp = ITOV(ip); 88f6d35f95Sderaadt fs = ip->i_fs; 89fcf048c1Spedro p = curproc; 90b080ad39Scsapuntz lbn = lblkno(fs, startoffset); 91b080ad39Scsapuntz size = blkoff(fs, startoffset) + size; 9207feb63cScsapuntz if (size > fs->fs_bsize) 93f4342418Spedro panic("ffs1_balloc: blk too big"); 94947c4e29Sart if (bpp != NULL) 95b080ad39Scsapuntz *bpp = NULL; 9607feb63cScsapuntz if (lbn < 0) 9707feb63cScsapuntz return (EFBIG); 98df930be7Sderaadt 99df930be7Sderaadt /* 100df930be7Sderaadt * If the next write will extend the file into a new block, 101df930be7Sderaadt * and the file is currently composed of a fragment 102df930be7Sderaadt * this fragment has to be extended to be a full block. 103df930be7Sderaadt */ 104fb844963Spedro nb = lblkno(fs, ip->i_ffs1_size); 10507feb63cScsapuntz if (nb < NDADDR && nb < lbn) { 106df930be7Sderaadt osize = blksize(fs, ip, nb); 107df930be7Sderaadt if (osize < fs->fs_bsize && osize > 0) { 108df930be7Sderaadt error = ffs_realloccg(ip, nb, 109f4342418Spedro ffs1_blkpref(ip, nb, (int)nb, &ip->i_ffs1_db[0]), 110947c4e29Sart osize, (int)fs->fs_bsize, cred, bpp, &newb); 111df930be7Sderaadt if (error) 112df930be7Sderaadt return (error); 11307feb63cScsapuntz if (DOINGSOFTDEP(vp)) 1146c194e8dSart softdep_setup_allocdirect(ip, nb, newb, 115fb844963Spedro ip->i_ffs1_db[nb], fs->fs_bsize, osize, 116947c4e29Sart bpp ? *bpp : NULL); 11707feb63cScsapuntz 118fb844963Spedro ip->i_ffs1_size = lblktosize(fs, nb + 1); 119fb844963Spedro uvm_vnp_setsize(vp, ip->i_ffs1_size); 120fb844963Spedro ip->i_ffs1_db[nb] = newb; 121df930be7Sderaadt ip->i_flag |= IN_CHANGE | IN_UPDATE; 122947c4e29Sart if (bpp != NULL) { 123df930be7Sderaadt if (flags & B_SYNC) 124947c4e29Sart bwrite(*bpp); 125df930be7Sderaadt else 126947c4e29Sart bawrite(*bpp); 127947c4e29Sart } 128df930be7Sderaadt } 129df930be7Sderaadt } 130df930be7Sderaadt /* 131df930be7Sderaadt * The first NDADDR blocks are direct blocks 132df930be7Sderaadt */ 13307feb63cScsapuntz if (lbn < NDADDR) { 134fb844963Spedro nb = ip->i_ffs1_db[lbn]; 135fb844963Spedro if (nb != 0 && ip->i_ffs1_size >= lblktosize(fs, lbn + 1)) { 136947c4e29Sart /* 137947c4e29Sart * The block is an already-allocated direct block 138947c4e29Sart * and the file already extends past this block, 139947c4e29Sart * thus this must be a whole block. 140947c4e29Sart * Just read the block (if requested). 141947c4e29Sart */ 142947c4e29Sart 143947c4e29Sart if (bpp != NULL) { 144*93f62a9eStedu error = bread(vp, lbn, fs->fs_bsize, bpp); 145df930be7Sderaadt if (error) { 146947c4e29Sart brelse(*bpp); 147df930be7Sderaadt return (error); 148df930be7Sderaadt } 149947c4e29Sart } 150df930be7Sderaadt return (0); 151df930be7Sderaadt } 152df930be7Sderaadt if (nb != 0) { 153df930be7Sderaadt /* 154df930be7Sderaadt * Consider need to reallocate a fragment. 155df930be7Sderaadt */ 156fb844963Spedro osize = fragroundup(fs, blkoff(fs, ip->i_ffs1_size)); 157df930be7Sderaadt nsize = fragroundup(fs, size); 158df930be7Sderaadt if (nsize <= osize) { 159947c4e29Sart /* 160947c4e29Sart * The existing block is already 161947c4e29Sart * at least as big as we want. 162947c4e29Sart * Just read the block (if requested). 163947c4e29Sart */ 164947c4e29Sart if (bpp != NULL) { 165f43037e0Spedro error = bread(vp, lbn, fs->fs_bsize, 166*93f62a9eStedu bpp); 167df930be7Sderaadt if (error) { 168947c4e29Sart brelse(*bpp); 169df930be7Sderaadt return (error); 170df930be7Sderaadt } 171f43037e0Spedro (*bpp)->b_bcount = osize; 172947c4e29Sart } 173947c4e29Sart return (0); 174df930be7Sderaadt } else { 175947c4e29Sart /* 176947c4e29Sart * The existing block is smaller than we 177947c4e29Sart * want, grow it. 178947c4e29Sart */ 17907feb63cScsapuntz error = ffs_realloccg(ip, lbn, 180f4342418Spedro ffs1_blkpref(ip, lbn, (int)lbn, 181fb844963Spedro &ip->i_ffs1_db[0]), 182947c4e29Sart osize, nsize, cred, bpp, &newb); 183df930be7Sderaadt if (error) 184df930be7Sderaadt return (error); 18507feb63cScsapuntz if (DOINGSOFTDEP(vp)) 18607feb63cScsapuntz softdep_setup_allocdirect(ip, lbn, 187947c4e29Sart newb, nb, nsize, osize, 188947c4e29Sart bpp ? *bpp : NULL); 189df930be7Sderaadt } 190df930be7Sderaadt } else { 191947c4e29Sart /* 192947c4e29Sart * The block was not previously allocated, 193947c4e29Sart * allocate a new block or fragment. 194947c4e29Sart */ 195947c4e29Sart 196fb844963Spedro if (ip->i_ffs1_size < lblktosize(fs, lbn + 1)) 197df930be7Sderaadt nsize = fragroundup(fs, size); 198df930be7Sderaadt else 199df930be7Sderaadt nsize = fs->fs_bsize; 20007feb63cScsapuntz error = ffs_alloc(ip, lbn, 201f4342418Spedro ffs1_blkpref(ip, lbn, (int)lbn, &ip->i_ffs1_db[0]), 202df930be7Sderaadt nsize, cred, &newb); 203df930be7Sderaadt if (error) 204df930be7Sderaadt return (error); 205947c4e29Sart if (bpp != NULL) { 206f43037e0Spedro *bpp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 207f43037e0Spedro if (nsize < fs->fs_bsize) 208f43037e0Spedro (*bpp)->b_bcount = nsize; 209947c4e29Sart (*bpp)->b_blkno = fsbtodb(fs, newb); 210df930be7Sderaadt if (flags & B_CLRBUF) 211947c4e29Sart clrbuf(*bpp); 212947c4e29Sart } 21307feb63cScsapuntz if (DOINGSOFTDEP(vp)) 21407feb63cScsapuntz softdep_setup_allocdirect(ip, lbn, newb, 0, 215947c4e29Sart nsize, 0, bpp ? *bpp : NULL); 216df930be7Sderaadt } 217fb844963Spedro ip->i_ffs1_db[lbn] = newb; 218df930be7Sderaadt ip->i_flag |= IN_CHANGE | IN_UPDATE; 219df930be7Sderaadt return (0); 220df930be7Sderaadt } 221947c4e29Sart 222df930be7Sderaadt /* 223df930be7Sderaadt * Determine the number of levels of indirection. 224df930be7Sderaadt */ 225df930be7Sderaadt pref = 0; 22607feb63cScsapuntz if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0) 227df930be7Sderaadt return(error); 228df930be7Sderaadt #ifdef DIAGNOSTIC 229df930be7Sderaadt if (num < 1) 230f4342418Spedro panic ("ffs1_balloc: ufs_bmaparray returned indirect block"); 231df930be7Sderaadt #endif 232df930be7Sderaadt /* 233df930be7Sderaadt * Fetch the first indirect block allocating if necessary. 234df930be7Sderaadt */ 235df930be7Sderaadt --num; 236fb844963Spedro nb = ip->i_ffs1_ib[indirs[0].in_off]; 23707feb63cScsapuntz 23807feb63cScsapuntz allocib = NULL; 23907feb63cScsapuntz allocblk = allociblk; 240df930be7Sderaadt if (nb == 0) { 2418add4794Sotto pref = ffs1_blkpref(ip, lbn, 0, (int32_t *)0); 242d28910b8Sniklas error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, 243d28910b8Sniklas cred, &newb); 244d28910b8Sniklas if (error) 245947c4e29Sart goto fail; 246df930be7Sderaadt nb = newb; 24707feb63cScsapuntz 24807feb63cScsapuntz *allocblk++ = nb; 249df930be7Sderaadt bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0); 25007feb63cScsapuntz bp->b_blkno = fsbtodb(fs, nb); 251df930be7Sderaadt clrbuf(bp); 25207feb63cScsapuntz 25307feb63cScsapuntz if (DOINGSOFTDEP(vp)) { 25407feb63cScsapuntz softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off, 25507feb63cScsapuntz newb, 0, fs->fs_bsize, 0, bp); 25607feb63cScsapuntz bdwrite(bp); 25707feb63cScsapuntz } else { 258df930be7Sderaadt /* 259df930be7Sderaadt * Write synchronously so that indirect blocks 260df930be7Sderaadt * never point at garbage. 261df930be7Sderaadt */ 26207feb63cScsapuntz if ((error = bwrite(bp)) != 0) 26307feb63cScsapuntz goto fail; 264df930be7Sderaadt } 265fb844963Spedro allocib = &ip->i_ffs1_ib[indirs[0].in_off]; 26607feb63cScsapuntz *allocib = nb; 267df930be7Sderaadt ip->i_flag |= IN_CHANGE | IN_UPDATE; 268df930be7Sderaadt } 269947c4e29Sart 270df930be7Sderaadt /* 271df930be7Sderaadt * Fetch through the indirect blocks, allocating as necessary. 272df930be7Sderaadt */ 273df930be7Sderaadt for (i = 1;;) { 274*93f62a9eStedu error = bread(vp, indirs[i].in_lbn, (int)fs->fs_bsize, &bp); 275df930be7Sderaadt if (error) { 276df930be7Sderaadt brelse(bp); 27707feb63cScsapuntz goto fail; 278df930be7Sderaadt } 2798add4794Sotto bap = (int32_t *)bp->b_data; 280df930be7Sderaadt nb = bap[indirs[i].in_off]; 281df930be7Sderaadt if (i == num) 282df930be7Sderaadt break; 2833853cac8Sart i++; 284df930be7Sderaadt if (nb != 0) { 285df930be7Sderaadt brelse(bp); 286df930be7Sderaadt continue; 287df930be7Sderaadt } 288df930be7Sderaadt if (pref == 0) 2898add4794Sotto pref = ffs1_blkpref(ip, lbn, 0, (int32_t *)0); 290d28910b8Sniklas error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, 291d28910b8Sniklas &newb); 292d28910b8Sniklas if (error) { 293df930be7Sderaadt brelse(bp); 29407feb63cScsapuntz goto fail; 295df930be7Sderaadt } 296df930be7Sderaadt nb = newb; 29707feb63cScsapuntz *allocblk++ = nb; 298df930be7Sderaadt nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0); 299df930be7Sderaadt nbp->b_blkno = fsbtodb(fs, nb); 300df930be7Sderaadt clrbuf(nbp); 30107feb63cScsapuntz 30207feb63cScsapuntz if (DOINGSOFTDEP(vp)) { 30307feb63cScsapuntz softdep_setup_allocindir_meta(nbp, ip, bp, 30407feb63cScsapuntz indirs[i - 1].in_off, nb); 30507feb63cScsapuntz bdwrite(nbp); 30607feb63cScsapuntz } else { 307df930be7Sderaadt /* 308df930be7Sderaadt * Write synchronously so that indirect blocks 309df930be7Sderaadt * never point at garbage. 310df930be7Sderaadt */ 311d28910b8Sniklas if ((error = bwrite(nbp)) != 0) { 312df930be7Sderaadt brelse(bp); 31307feb63cScsapuntz goto fail; 31407feb63cScsapuntz } 315df930be7Sderaadt } 316df930be7Sderaadt bap[indirs[i - 1].in_off] = nb; 3176cd4677cSart if (allocib == NULL && unwindidx < 0) 3186cd4677cSart unwindidx = i - 1; 319df930be7Sderaadt /* 320df930be7Sderaadt * If required, write synchronously, otherwise use 321df930be7Sderaadt * delayed write. 322df930be7Sderaadt */ 323df930be7Sderaadt if (flags & B_SYNC) { 324df930be7Sderaadt bwrite(bp); 325df930be7Sderaadt } else { 326df930be7Sderaadt bdwrite(bp); 327df930be7Sderaadt } 328df930be7Sderaadt } 329df930be7Sderaadt /* 330df930be7Sderaadt * Get the data block, allocating if necessary. 331df930be7Sderaadt */ 332df930be7Sderaadt if (nb == 0) { 333f4342418Spedro pref = ffs1_blkpref(ip, lbn, indirs[i].in_off, &bap[0]); 334d28910b8Sniklas error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, 335d28910b8Sniklas &newb); 336d28910b8Sniklas if (error) { 337df930be7Sderaadt brelse(bp); 33807feb63cScsapuntz goto fail; 339df930be7Sderaadt } 340df930be7Sderaadt nb = newb; 34107feb63cScsapuntz *allocblk++ = nb; 342947c4e29Sart if (bpp != NULL) { 343df930be7Sderaadt nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 344df930be7Sderaadt nbp->b_blkno = fsbtodb(fs, nb); 345df930be7Sderaadt if (flags & B_CLRBUF) 346df930be7Sderaadt clrbuf(nbp); 347947c4e29Sart *bpp = nbp; 348947c4e29Sart } 34907feb63cScsapuntz if (DOINGSOFTDEP(vp)) 35007feb63cScsapuntz softdep_setup_allocindir_page(ip, lbn, bp, 351947c4e29Sart indirs[i].in_off, nb, 0, bpp ? *bpp : NULL); 352df930be7Sderaadt bap[indirs[i].in_off] = nb; 353df930be7Sderaadt /* 354df930be7Sderaadt * If required, write synchronously, otherwise use 355df930be7Sderaadt * delayed write. 356df930be7Sderaadt */ 357df930be7Sderaadt if (flags & B_SYNC) { 358df930be7Sderaadt bwrite(bp); 359df930be7Sderaadt } else { 360df930be7Sderaadt bdwrite(bp); 361df930be7Sderaadt } 362df930be7Sderaadt return (0); 363df930be7Sderaadt } 364df930be7Sderaadt brelse(bp); 365947c4e29Sart if (bpp != NULL) { 366df930be7Sderaadt if (flags & B_CLRBUF) { 367*93f62a9eStedu error = bread(vp, lbn, (int)fs->fs_bsize, &nbp); 368df930be7Sderaadt if (error) { 369df930be7Sderaadt brelse(nbp); 37007feb63cScsapuntz goto fail; 371df930be7Sderaadt } 372df930be7Sderaadt } else { 373df930be7Sderaadt nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 374df930be7Sderaadt nbp->b_blkno = fsbtodb(fs, nb); 375df930be7Sderaadt } 376b080ad39Scsapuntz *bpp = nbp; 377947c4e29Sart } 378df930be7Sderaadt return (0); 37907feb63cScsapuntz 38007feb63cScsapuntz fail: 38107feb63cScsapuntz /* 382fcf048c1Spedro * If we have failed to allocate any blocks, simply return the error. 383fcf048c1Spedro * This is the usual case and avoids the need to fsync the file. 38407feb63cScsapuntz */ 385fcf048c1Spedro if (allocblk == allociblk && allocib == NULL && unwindidx == -1) 386fcf048c1Spedro return (error); 387fcf048c1Spedro /* 388fcf048c1Spedro * If we have failed part way through block allocation, we have to 389fcf048c1Spedro * deallocate any indirect blocks that we have allocated. We have to 390fcf048c1Spedro * fsync the file before we start to get rid of all of its 391fcf048c1Spedro * dependencies so that we do not leave them dangling. We have to sync 392fcf048c1Spedro * it at the end so that the softdep code does not find any untracked 393fcf048c1Spedro * changes. Although this is really slow, running out of disk space is 39480adcad8Smartynas * not expected to be a common occurrence. The error return from fsync 395fcf048c1Spedro * is ignored as we already have an error to return to the user. 396fcf048c1Spedro */ 397fcf048c1Spedro VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p); 39807feb63cScsapuntz for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { 39907feb63cScsapuntz ffs_blkfree(ip, *blkp, fs->fs_bsize); 40007feb63cScsapuntz deallocated += fs->fs_bsize; 40107feb63cScsapuntz } 4026cd4677cSart if (allocib != NULL) { 40307feb63cScsapuntz *allocib = 0; 4046cd4677cSart } else if (unwindidx >= 0) { 4056cd4677cSart int r; 4066cd4677cSart 407*93f62a9eStedu r = bread(vp, indirs[unwindidx].in_lbn, (int)fs->fs_bsize, &bp); 4086cd4677cSart if (r) 4096cd4677cSart panic("Could not unwind indirect block, error %d", r); 4108add4794Sotto bap = (int32_t *)bp->b_data; 4116cd4677cSart bap[indirs[unwindidx].in_off] = 0; 4126cd4677cSart if (flags & B_SYNC) { 4136cd4677cSart bwrite(bp); 4146cd4677cSart } else { 4156cd4677cSart bdwrite(bp); 4166cd4677cSart } 4176cd4677cSart } 41807feb63cScsapuntz if (deallocated) { 41907feb63cScsapuntz /* 42007feb63cScsapuntz * Restore user's disk quota because allocation failed. 42107feb63cScsapuntz */ 4225f7d6642Scsapuntz (void)ufs_quota_free_blocks(ip, btodb(deallocated), cred); 4235f7d6642Scsapuntz 424fb844963Spedro ip->i_ffs1_blocks -= btodb(deallocated); 42507feb63cScsapuntz ip->i_flag |= IN_CHANGE | IN_UPDATE; 42607feb63cScsapuntz } 427fcf048c1Spedro VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p); 4286cd4677cSart return (error); 429df930be7Sderaadt } 430f4342418Spedro 431f4342418Spedro #ifdef FFS2 432f4342418Spedro int 433f4342418Spedro ffs2_balloc(struct inode *ip, off_t off, int size, struct ucred *cred, 434f4342418Spedro int flags, struct buf **bpp) 435f4342418Spedro { 4368add4794Sotto daddr64_t lbn, lastlbn, nb, newb, *blkp; 4378add4794Sotto daddr64_t pref, *allocblk, allociblk[NIADDR + 1]; 4381ac585afSderaadt daddr64_t *bap, *allocib; 439f4342418Spedro int deallocated, osize, nsize, num, i, error, unwindidx, r; 440f4342418Spedro struct buf *bp, *nbp; 441f4342418Spedro struct indir indirs[NIADDR + 2]; 442f4342418Spedro struct fs *fs; 443f4342418Spedro struct vnode *vp; 444c1df8807Ssturm struct proc *p; 445f4342418Spedro 446f4342418Spedro vp = ITOV(ip); 447f4342418Spedro fs = ip->i_fs; 448c1df8807Ssturm p = curproc; 44916a60b30Ssturm unwindidx = -1; 450f4342418Spedro 451f4342418Spedro lbn = lblkno(fs, off); 452f4342418Spedro size = blkoff(fs, off) + size; 453f4342418Spedro 454f4342418Spedro if (size > fs->fs_bsize) 455f4342418Spedro panic("ffs2_balloc: block too big"); 456f4342418Spedro 457f4342418Spedro if (bpp != NULL) 458f4342418Spedro *bpp = NULL; 459f4342418Spedro 460f4342418Spedro if (lbn < 0) 461f4342418Spedro return (EFBIG); 462f4342418Spedro 463f4342418Spedro /* 464f4342418Spedro * If the next write will extend the file into a new block, and the 465f4342418Spedro * file is currently composed of a fragment, this fragment has to be 466f4342418Spedro * extended to be a full block. 467f4342418Spedro */ 468f4342418Spedro lastlbn = lblkno(fs, ip->i_ffs2_size); 469f4342418Spedro if (lastlbn < NDADDR && lastlbn < lbn) { 470f4342418Spedro nb = lastlbn; 471f4342418Spedro osize = blksize(fs, ip, nb); 472f4342418Spedro if (osize < fs->fs_bsize && osize > 0) { 473f4342418Spedro error = ffs_realloccg(ip, nb, ffs2_blkpref(ip, 474f4342418Spedro lastlbn, nb, &ip->i_ffs2_db[0]), osize, 475f4342418Spedro (int) fs->fs_bsize, cred, bpp, &newb); 476f4342418Spedro if (error) 477f4342418Spedro return (error); 478f4342418Spedro 479f4342418Spedro if (DOINGSOFTDEP(vp)) 480f4342418Spedro softdep_setup_allocdirect(ip, nb, newb, 481f4342418Spedro ip->i_ffs2_db[nb], fs->fs_bsize, osize, 482f4342418Spedro bpp ? *bpp : NULL); 483f4342418Spedro 484f4342418Spedro ip->i_ffs2_size = lblktosize(fs, nb + 1); 485f4342418Spedro uvm_vnp_setsize(vp, ip->i_ffs2_size); 486f4342418Spedro ip->i_ffs2_db[nb] = newb; 487f4342418Spedro ip->i_flag |= IN_CHANGE | IN_UPDATE; 488f4342418Spedro 489f4342418Spedro if (bpp) { 490f4342418Spedro if (flags & B_SYNC) 491f4342418Spedro bwrite(*bpp); 492f4342418Spedro else 493f4342418Spedro bawrite(*bpp); 494f4342418Spedro } 495f4342418Spedro } 496f4342418Spedro } 497f4342418Spedro 498f4342418Spedro /* 499f4342418Spedro * The first NDADDR blocks are direct. 500f4342418Spedro */ 501f4342418Spedro if (lbn < NDADDR) { 502f4342418Spedro 503f4342418Spedro nb = ip->i_ffs2_db[lbn]; 504f4342418Spedro 505f4342418Spedro if (nb != 0 && ip->i_ffs2_size >= lblktosize(fs, lbn + 1)) { 506f4342418Spedro /* 507f4342418Spedro * The direct block is already allocated and the file 508f4342418Spedro * extends past this block, thus this must be a whole 509f4342418Spedro * block. Just read it, if requested. 510f4342418Spedro */ 511f4342418Spedro if (bpp != NULL) { 512*93f62a9eStedu error = bread(vp, lbn, fs->fs_bsize, bpp); 513f4342418Spedro if (error) { 514f4342418Spedro brelse(*bpp); 515f4342418Spedro return (error); 516f4342418Spedro } 517f4342418Spedro } 518f4342418Spedro 519f4342418Spedro return (0); 520f4342418Spedro } 521f4342418Spedro 522f4342418Spedro if (nb != 0) { 523f4342418Spedro /* 524f4342418Spedro * Consider the need to allocate a fragment. 525f4342418Spedro */ 526f4342418Spedro osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size)); 527f4342418Spedro nsize = fragroundup(fs, size); 528f4342418Spedro 529f4342418Spedro if (nsize <= osize) { 530f4342418Spedro /* 531f4342418Spedro * The existing block is already at least as 532f4342418Spedro * big as we want. Just read it, if requested. 533f4342418Spedro */ 534f4342418Spedro if (bpp != NULL) { 535f43037e0Spedro error = bread(vp, lbn, fs->fs_bsize, 536*93f62a9eStedu bpp); 537f4342418Spedro if (error) { 538f4342418Spedro brelse(*bpp); 539f4342418Spedro return (error); 540f4342418Spedro } 541f43037e0Spedro (*bpp)->b_bcount = osize; 542f4342418Spedro } 543f4342418Spedro 544f4342418Spedro return (0); 545f4342418Spedro } else { 546f4342418Spedro /* 547f4342418Spedro * The existing block is smaller than we want, 548f4342418Spedro * grow it. 549f4342418Spedro */ 550f4342418Spedro error = ffs_realloccg(ip, lbn, 551f4342418Spedro ffs2_blkpref(ip, lbn, (int) lbn, 552f4342418Spedro &ip->i_ffs2_db[0]), osize, nsize, cred, 553f4342418Spedro bpp, &newb); 554f4342418Spedro if (error) 555f4342418Spedro return (error); 556f4342418Spedro 557f4342418Spedro if (DOINGSOFTDEP(vp)) 558f4342418Spedro softdep_setup_allocdirect(ip, lbn, 559f4342418Spedro newb, nb, nsize, osize, 560f4342418Spedro bpp ? *bpp : NULL); 561f4342418Spedro } 562f4342418Spedro } else { 563f4342418Spedro /* 564f4342418Spedro * The block was not previously allocated, allocate a 565f4342418Spedro * new block or fragment. 566f4342418Spedro */ 567f4342418Spedro if (ip->i_ffs2_size < lblktosize(fs, lbn + 1)) 568f4342418Spedro nsize = fragroundup(fs, size); 569f4342418Spedro else 570f4342418Spedro nsize = fs->fs_bsize; 571f4342418Spedro 572f4342418Spedro error = ffs_alloc(ip, lbn, ffs2_blkpref(ip, lbn, 573f4342418Spedro (int) lbn, &ip->i_ffs2_db[0]), nsize, cred, &newb); 574f4342418Spedro if (error) 575f4342418Spedro return (error); 576f4342418Spedro 577f4342418Spedro if (bpp != NULL) { 578f43037e0Spedro bp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 579f43037e0Spedro if (nsize < fs->fs_bsize) 580f43037e0Spedro bp->b_bcount = nsize; 581f4342418Spedro bp->b_blkno = fsbtodb(fs, newb); 582f4342418Spedro if (flags & B_CLRBUF) 583f4342418Spedro clrbuf(bp); 584f4342418Spedro *bpp = bp; 585f4342418Spedro } 586f4342418Spedro 587f4342418Spedro if (DOINGSOFTDEP(vp)) 588f4342418Spedro softdep_setup_allocdirect(ip, lbn, newb, 0, 589f4342418Spedro nsize, 0, bpp ? *bpp : NULL); 5905d1e8defSpedro } 591f4342418Spedro 592f4342418Spedro ip->i_ffs2_db[lbn] = newb; 593f4342418Spedro ip->i_flag |= IN_CHANGE | IN_UPDATE; 594f4342418Spedro 595f4342418Spedro return (0); 596f4342418Spedro } 597f4342418Spedro 598f4342418Spedro /* 599f4342418Spedro * Determine the number of levels of indirection. 600f4342418Spedro */ 601f4342418Spedro pref = 0; 602f4342418Spedro error = ufs_getlbns(vp, lbn, indirs, &num); 603f4342418Spedro if (error) 604f4342418Spedro return (error); 605f4342418Spedro 606244cffc3Spedro #ifdef DIAGNOSTIC 607244cffc3Spedro if (num < 1) 608244cffc3Spedro panic("ffs2_balloc: ufs_bmaparray returned indirect block"); 609244cffc3Spedro #endif 610244cffc3Spedro 611f4342418Spedro /* 612f4342418Spedro * Fetch the first indirect block allocating it necessary. 613f4342418Spedro */ 614f4342418Spedro --num; 615f4342418Spedro nb = ip->i_ffs2_ib[indirs[0].in_off]; 616f4342418Spedro allocib = NULL; 617f4342418Spedro allocblk = allociblk; 618f4342418Spedro 619f4342418Spedro if (nb == 0) { 620f4342418Spedro pref = ffs2_blkpref(ip, lbn, 0, NULL); 621f4342418Spedro error = ffs_alloc(ip, lbn, pref, (int) fs->fs_bsize, cred, 622f4342418Spedro &newb); 623f4342418Spedro if (error) 624f4342418Spedro goto fail; 625f4342418Spedro 626f4342418Spedro nb = newb; 627f4342418Spedro *allocblk++ = nb; 628f4342418Spedro bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0); 629f4342418Spedro bp->b_blkno = fsbtodb(fs, nb); 630f4342418Spedro clrbuf(bp); 631f4342418Spedro 632f4342418Spedro if (DOINGSOFTDEP(vp)) { 633f4342418Spedro softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off, 634f4342418Spedro newb, 0, fs->fs_bsize, 0, bp); 635f4342418Spedro bdwrite(bp); 636f4342418Spedro } else { 637f4342418Spedro /* 638f4342418Spedro * Write synchronously so that indirect blocks never 639f4342418Spedro * point at garbage. 640f4342418Spedro */ 641f4342418Spedro error = bwrite(bp); 642f4342418Spedro if (error) 643f4342418Spedro goto fail; 644f4342418Spedro } 645f4342418Spedro 646f4342418Spedro unwindidx = 0; 647f4342418Spedro allocib = &ip->i_ffs2_ib[indirs[0].in_off]; 648f4342418Spedro *allocib = nb; 649f4342418Spedro ip->i_flag |= IN_CHANGE | IN_UPDATE; 650f4342418Spedro } 651f4342418Spedro 652f4342418Spedro /* 653f4342418Spedro * Fetch through the indirect blocks, allocating as necessary. 654f4342418Spedro */ 655f4342418Spedro for (i = 1;;) { 656*93f62a9eStedu error = bread(vp, indirs[i].in_lbn, (int)fs->fs_bsize, &bp); 657f4342418Spedro if (error) { 658f4342418Spedro brelse(bp); 659f4342418Spedro goto fail; 660f4342418Spedro } 661f4342418Spedro 662f4342418Spedro bap = (int64_t *) bp->b_data; 663f4342418Spedro nb = bap[indirs[i].in_off]; 664f4342418Spedro 665f4342418Spedro if (i == num) 666f4342418Spedro break; 667f4342418Spedro 668f4342418Spedro i++; 669f4342418Spedro 670f4342418Spedro if (nb != 0) { 671f4342418Spedro brelse(bp); 672f4342418Spedro continue; 673f4342418Spedro } 674f4342418Spedro 675f4342418Spedro if (pref == 0) 676f4342418Spedro pref = ffs2_blkpref(ip, lbn, 0, NULL); 677f4342418Spedro 678f4342418Spedro error = ffs_alloc(ip, lbn, pref, (int) fs->fs_bsize, cred, 679f4342418Spedro &newb); 680f4342418Spedro if (error) { 681f4342418Spedro brelse(bp); 682f4342418Spedro goto fail; 683f4342418Spedro } 684f4342418Spedro 685f4342418Spedro nb = newb; 686f4342418Spedro *allocblk++ = nb; 687f4342418Spedro nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0); 688f4342418Spedro nbp->b_blkno = fsbtodb(fs, nb); 689f4342418Spedro clrbuf(nbp); 690f4342418Spedro 691f4342418Spedro if (DOINGSOFTDEP(vp)) { 692f4342418Spedro softdep_setup_allocindir_meta(nbp, ip, bp, 693f4342418Spedro indirs[i - 1].in_off, nb); 694f4342418Spedro bdwrite(nbp); 695f4342418Spedro } else { 696f4342418Spedro /* 697f4342418Spedro * Write synchronously so that indirect blocks never 698f4342418Spedro * point at garbage. 699f4342418Spedro */ 700f4342418Spedro error = bwrite(nbp); 701f4342418Spedro if (error) { 702f4342418Spedro brelse(bp); 703f4342418Spedro goto fail; 704f4342418Spedro } 705f4342418Spedro } 706f4342418Spedro 707f4342418Spedro if (unwindidx < 0) 708f4342418Spedro unwindidx = i - 1; 709f4342418Spedro 710f4342418Spedro bap[indirs[i - 1].in_off] = nb; 711f4342418Spedro 712f4342418Spedro /* 713f4342418Spedro * If required, write synchronously, otherwise use delayed 714f4342418Spedro * write. 715f4342418Spedro */ 716f4342418Spedro if (flags & B_SYNC) 717f4342418Spedro bwrite(bp); 718f4342418Spedro else 719f4342418Spedro bdwrite(bp); 720f4342418Spedro } 721f4342418Spedro 722f4342418Spedro /* 723f4342418Spedro * Get the data block, allocating if necessary. 724f4342418Spedro */ 725f4342418Spedro if (nb == 0) { 726f4342418Spedro pref = ffs2_blkpref(ip, lbn, indirs[num].in_off, &bap[0]); 727f4342418Spedro 728f4342418Spedro error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, 729f4342418Spedro &newb); 730f4342418Spedro if (error) { 731f4342418Spedro brelse(bp); 732f4342418Spedro goto fail; 733f4342418Spedro } 734f4342418Spedro 735f4342418Spedro nb = newb; 736f4342418Spedro *allocblk++ = nb; 737f4342418Spedro 738f4342418Spedro if (bpp != NULL) { 739f4342418Spedro nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 740f4342418Spedro nbp->b_blkno = fsbtodb(fs, nb); 741f4342418Spedro if (flags & B_CLRBUF) 742f4342418Spedro clrbuf(nbp); 743f4342418Spedro *bpp = nbp; 744f4342418Spedro } 745f4342418Spedro 746f4342418Spedro if (DOINGSOFTDEP(vp)) 747f4342418Spedro softdep_setup_allocindir_page(ip, lbn, bp, 748f4342418Spedro indirs[num].in_off, nb, 0, bpp ? *bpp : NULL); 749f4342418Spedro 750f4342418Spedro bap[indirs[num].in_off] = nb; 751f4342418Spedro 752f4342418Spedro if (allocib == NULL && unwindidx < 0) 753f4342418Spedro unwindidx = i - 1; 754f4342418Spedro 755f4342418Spedro /* 756f4342418Spedro * If required, write synchronously, otherwise use delayed 757f4342418Spedro * write. 758f4342418Spedro */ 759f4342418Spedro if (flags & B_SYNC) 760f4342418Spedro bwrite(bp); 761f4342418Spedro else 762f4342418Spedro bdwrite(bp); 763f4342418Spedro 764f4342418Spedro return (0); 765f4342418Spedro } 766f4342418Spedro 767f4342418Spedro brelse(bp); 768f4342418Spedro 769f4342418Spedro if (bpp != NULL) { 770f4342418Spedro if (flags & B_CLRBUF) { 771*93f62a9eStedu error = bread(vp, lbn, (int)fs->fs_bsize, &nbp); 772f4342418Spedro if (error) { 773f4342418Spedro brelse(nbp); 774f4342418Spedro goto fail; 775f4342418Spedro } 776f4342418Spedro } else { 777f4342418Spedro nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 778f4342418Spedro nbp->b_blkno = fsbtodb(fs, nb); 779f4342418Spedro clrbuf(nbp); 780f4342418Spedro } 781f4342418Spedro 782f4342418Spedro *bpp = nbp; 783f4342418Spedro } 784f4342418Spedro 785f4342418Spedro return (0); 786f4342418Spedro 787f4342418Spedro fail: 788c1df8807Ssturm /* 789c1df8807Ssturm * If we have failed to allocate any blocks, simply return the error. 790c1df8807Ssturm * This is the usual case and avoids the need to fsync the file. 791c1df8807Ssturm */ 792c1df8807Ssturm if (allocblk == allociblk && allocib == NULL && unwindidx == -1) 793c1df8807Ssturm return (error); 794f4342418Spedro /* 795f4342418Spedro * If we have failed part way through block allocation, we have to 796c1df8807Ssturm * deallocate any indirect blocks that we have allocated. We have to 797c1df8807Ssturm * fsync the file before we start to get rid of all of its 798c1df8807Ssturm * dependencies so that we do not leave them dangling. We have to sync 799c1df8807Ssturm * it at the end so that the softdep code does not find any untracked 800c1df8807Ssturm * changes. Although this is really slow, running out of disk space is 80180adcad8Smartynas * not expected to be a common occurrence. The error return from fsync 802c1df8807Ssturm * is ignored as we already have an error to return to the user. 803f4342418Spedro */ 804c1df8807Ssturm VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p); 805f4342418Spedro if (unwindidx >= 0) { 806f4342418Spedro /* 807f4342418Spedro * First write out any buffers we've created to resolve their 808f4342418Spedro * softdeps. This must be done in reverse order of creation so 809f4342418Spedro * that we resolve the dependencies in one pass. 810f4342418Spedro * Write the cylinder group buffers for these buffers too. 811f4342418Spedro */ 812f4342418Spedro for (i = num; i >= unwindidx; i--) { 813f4342418Spedro if (i == 0) 814f4342418Spedro break; 815f4342418Spedro 816f4342418Spedro bp = getblk(vp, indirs[i].in_lbn, (int) fs->fs_bsize, 817f4342418Spedro 0, 0); 818f4342418Spedro if (bp->b_flags & B_DELWRI) { 819f4342418Spedro nb = fsbtodb(fs, cgtod(fs, dtog(fs, 820f4342418Spedro dbtofsb(fs, bp->b_blkno)))); 821f4342418Spedro bwrite(bp); 822f4342418Spedro bp = getblk(ip->i_devvp, nb, 823f4342418Spedro (int) fs->fs_cgsize, 0, 0); 824f4342418Spedro if (bp->b_flags & B_DELWRI) 825f4342418Spedro bwrite(bp); 826f4342418Spedro else { 827f4342418Spedro bp->b_flags |= B_INVAL; 828f4342418Spedro brelse(bp); 829f4342418Spedro } 830f4342418Spedro } else { 831f4342418Spedro bp->b_flags |= B_INVAL; 832f4342418Spedro brelse(bp); 833f4342418Spedro } 834f4342418Spedro } 835f4342418Spedro 836f4342418Spedro if (DOINGSOFTDEP(vp) && unwindidx == 0) { 837f4342418Spedro ip->i_flag |= IN_CHANGE | IN_UPDATE; 838f4342418Spedro ffs_update(ip, NULL, NULL, MNT_WAIT); 839f4342418Spedro } 840f4342418Spedro 841f4342418Spedro /* 842f4342418Spedro * Now that any dependencies that we created have been 843f4342418Spedro * resolved, we can undo the partial allocation. 844f4342418Spedro */ 845f4342418Spedro if (unwindidx == 0) { 846f4342418Spedro *allocib = 0; 847f4342418Spedro ip->i_flag |= IN_CHANGE | IN_UPDATE; 848f4342418Spedro if (DOINGSOFTDEP(vp)) 849f4342418Spedro ffs_update(ip, NULL, NULL, MNT_WAIT); 850f4342418Spedro } else { 851f4342418Spedro r = bread(vp, indirs[unwindidx].in_lbn, 852*93f62a9eStedu (int)fs->fs_bsize, &bp); 853f4342418Spedro if (r) 854f4342418Spedro panic("ffs2_balloc: unwind failed"); 855f4342418Spedro 856f4342418Spedro bap = (int64_t *) bp->b_data; 857f4342418Spedro bap[indirs[unwindidx].in_off] = 0; 858f4342418Spedro bwrite(bp); 859f4342418Spedro } 860f4342418Spedro 861f4342418Spedro for (i = unwindidx + 1; i <= num; i++) { 862f4342418Spedro bp = getblk(vp, indirs[i].in_lbn, (int)fs->fs_bsize, 0, 863f4342418Spedro 0); 864f4342418Spedro bp->b_flags |= B_INVAL; 865f4342418Spedro brelse(bp); 866f4342418Spedro } 867f4342418Spedro } 868f4342418Spedro 869f4342418Spedro for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { 870f4342418Spedro ffs_blkfree(ip, *blkp, fs->fs_bsize); 871f4342418Spedro deallocated += fs->fs_bsize; 872f4342418Spedro } 873f4342418Spedro 874f4342418Spedro if (deallocated) { 875f4342418Spedro /* 876f4342418Spedro * Restore user's disk quota because allocation failed. 877f4342418Spedro */ 878f4342418Spedro (void) ufs_quota_free_blocks(ip, btodb(deallocated), cred); 879f4342418Spedro 880f4342418Spedro ip->i_ffs2_blocks -= btodb(deallocated); 881f4342418Spedro ip->i_flag |= IN_CHANGE | IN_UPDATE; 882f4342418Spedro } 883c1df8807Ssturm VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p); 884f4342418Spedro return (error); 885f4342418Spedro } 886f4342418Spedro #endif /* FFS2 */ 887f4342418Spedro 888f4342418Spedro /* 889f4342418Spedro * Balloc defines the structure of file system storage by allocating the 890f4342418Spedro * physical blocks given the inode and the logical block number in a file. 891f4342418Spedro */ 892f4342418Spedro int 893f4342418Spedro ffs_balloc(struct inode *ip, off_t off, int size, struct ucred *cred, 894f4342418Spedro int flags, struct buf **bpp) 895f4342418Spedro { 896f4342418Spedro #ifdef FFS2 897f4342418Spedro if (ip->i_fs->fs_magic == FS_UFS2_MAGIC) 898f4342418Spedro return (ffs2_balloc(ip, off, size, cred, flags, bpp)); 899f4342418Spedro else 900f4342418Spedro #endif 901f4342418Spedro return (ffs1_balloc(ip, off, size, cred, flags, bpp)); 902f4342418Spedro } 903