1*76018e64Sart /* $OpenBSD: ffs_balloc.c,v 1.9 1999/05/27 20:36:21 art Exp $ */ 2d28910b8Sniklas /* $NetBSD: ffs_balloc.c,v 1.3 1996/02/09 22:22:21 christos Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /* 5df930be7Sderaadt * Copyright (c) 1982, 1986, 1989, 1993 6df930be7Sderaadt * The Regents of the University of California. All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 9df930be7Sderaadt * modification, are permitted provided that the following conditions 10df930be7Sderaadt * are met: 11df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 12df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 13df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 14df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 15df930be7Sderaadt * documentation and/or other materials provided with the distribution. 16df930be7Sderaadt * 3. All advertising materials mentioning features or use of this software 17df930be7Sderaadt * must display the following acknowledgement: 18df930be7Sderaadt * This product includes software developed by the University of 19df930be7Sderaadt * California, Berkeley and its contributors. 20df930be7Sderaadt * 4. Neither the name of the University nor the names of its contributors 21df930be7Sderaadt * may be used to endorse or promote products derived from this software 22df930be7Sderaadt * without specific prior written permission. 23df930be7Sderaadt * 24df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34df930be7Sderaadt * SUCH DAMAGE. 35df930be7Sderaadt * 36df930be7Sderaadt * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93 37df930be7Sderaadt */ 38df930be7Sderaadt 39df930be7Sderaadt #include <sys/param.h> 40df930be7Sderaadt #include <sys/systm.h> 41df930be7Sderaadt #include <sys/buf.h> 42df930be7Sderaadt #include <sys/proc.h> 43df930be7Sderaadt #include <sys/file.h> 4407feb63cScsapuntz #include <sys/mount.h> 45df930be7Sderaadt #include <sys/vnode.h> 46df930be7Sderaadt 47df930be7Sderaadt #include <vm/vm.h> 48df930be7Sderaadt 496348b7ebSart #if defined(UVM) 506348b7ebSart #include <uvm/uvm_extern.h> 516348b7ebSart #endif 526348b7ebSart 53df930be7Sderaadt #include <ufs/ufs/quota.h> 54df930be7Sderaadt #include <ufs/ufs/inode.h> 55df930be7Sderaadt #include <ufs/ufs/ufs_extern.h> 56df930be7Sderaadt 57df930be7Sderaadt #include <ufs/ffs/fs.h> 58df930be7Sderaadt #include <ufs/ffs/ffs_extern.h> 59df930be7Sderaadt 60df930be7Sderaadt /* 61df930be7Sderaadt * Balloc defines the structure of file system storage 62df930be7Sderaadt * by allocating the physical blocks on a device given 63df930be7Sderaadt * the inode and the logical block number in a file. 64df930be7Sderaadt */ 65d28910b8Sniklas int 6607feb63cScsapuntz ffs_balloc(v) 6707feb63cScsapuntz void *v; 6807feb63cScsapuntz { 6907feb63cScsapuntz struct vop_balloc_args /* { 7007feb63cScsapuntz struct vnode *a_vp; 7107feb63cScsapuntz off_t a_startpoint; 7207feb63cScsapuntz int a_size; 7307feb63cScsapuntz struct ucred *a_cred; 7407feb63cScsapuntz int a_flags; 7507feb63cScsapuntz struct buf *a_bpp; 7607feb63cScsapuntz } */ *ap = v; 7707feb63cScsapuntz 7807feb63cScsapuntz struct inode *ip; 7907feb63cScsapuntz daddr_t lbn; 80df930be7Sderaadt int size; 81df930be7Sderaadt struct ucred *cred; 82df930be7Sderaadt int flags; 8307feb63cScsapuntz struct fs *fs; 8407feb63cScsapuntz daddr_t nb; 85df930be7Sderaadt struct buf *bp, *nbp; 8607feb63cScsapuntz struct vnode *vp; 87df930be7Sderaadt struct indir indirs[NIADDR + 2]; 8807feb63cScsapuntz daddr_t newb, *bap, pref; 8907feb63cScsapuntz int deallocated, osize, nsize, num, i, error; 9007feb63cScsapuntz daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR+1]; 91df930be7Sderaadt 9207feb63cScsapuntz vp = ap->a_vp; 9307feb63cScsapuntz ip = VTOI(vp); 94f6d35f95Sderaadt fs = ip->i_fs; 9507feb63cScsapuntz lbn = lblkno(fs, ap->a_startoffset); 9607feb63cScsapuntz size = blkoff(fs, ap->a_startoffset) + ap->a_size; 9707feb63cScsapuntz if (size > fs->fs_bsize) 9807feb63cScsapuntz panic("ffs_balloc; blk too big"); 9907feb63cScsapuntz *ap->a_bpp = NULL; 10007feb63cScsapuntz if (lbn < 0) 10107feb63cScsapuntz return (EFBIG); 10207feb63cScsapuntz cred = ap->a_cred; 10307feb63cScsapuntz flags = ap->a_flags; 104df930be7Sderaadt 105df930be7Sderaadt /* 106df930be7Sderaadt * If the next write will extend the file into a new block, 107df930be7Sderaadt * and the file is currently composed of a fragment 108df930be7Sderaadt * this fragment has to be extended to be a full block. 109df930be7Sderaadt */ 1107dc61945Sdownsj nb = lblkno(fs, ip->i_ffs_size); 11107feb63cScsapuntz if (nb < NDADDR && nb < lbn) { 112df930be7Sderaadt osize = blksize(fs, ip, nb); 113df930be7Sderaadt if (osize < fs->fs_bsize && osize > 0) { 114df930be7Sderaadt error = ffs_realloccg(ip, nb, 1157dc61945Sdownsj ffs_blkpref(ip, nb, (int)nb, &ip->i_ffs_db[0]), 116df930be7Sderaadt osize, (int)fs->fs_bsize, cred, &bp); 117df930be7Sderaadt if (error) 118df930be7Sderaadt return (error); 11907feb63cScsapuntz if (DOINGSOFTDEP(vp)) 12007feb63cScsapuntz softdep_setup_allocdirect(ip, nb, 12107feb63cScsapuntz dbtofsb(fs, bp->b_blkno), ip->i_ffs_db[nb], 12207feb63cScsapuntz fs->fs_bsize, osize, bp); 12307feb63cScsapuntz 124*76018e64Sart ip->i_ffs_size = lblktosize(fs, nb + 1); 1256348b7ebSart #if defined(UVM) 1266348b7ebSart uvm_vnp_setsize(vp, ip->i_ffs_size); 1276348b7ebSart #else 1287dc61945Sdownsj vnode_pager_setsize(vp, (u_long)ip->i_ffs_size); 1296348b7ebSart #endif 1307dc61945Sdownsj ip->i_ffs_db[nb] = dbtofsb(fs, bp->b_blkno); 131df930be7Sderaadt ip->i_flag |= IN_CHANGE | IN_UPDATE; 132df930be7Sderaadt if (flags & B_SYNC) 133df930be7Sderaadt bwrite(bp); 134df930be7Sderaadt else 135df930be7Sderaadt bawrite(bp); 136df930be7Sderaadt } 137df930be7Sderaadt } 138df930be7Sderaadt /* 139df930be7Sderaadt * The first NDADDR blocks are direct blocks 140df930be7Sderaadt */ 14107feb63cScsapuntz if (lbn < NDADDR) { 14207feb63cScsapuntz nb = ip->i_ffs_db[lbn]; 143*76018e64Sart if (nb != 0 && ip->i_ffs_size >= lblktosize(fs, lbn + 1)) { 14407feb63cScsapuntz error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp); 145df930be7Sderaadt if (error) { 146df930be7Sderaadt brelse(bp); 147df930be7Sderaadt return (error); 148df930be7Sderaadt } 14907feb63cScsapuntz *ap->a_bpp = bp; 150df930be7Sderaadt return (0); 151df930be7Sderaadt } 152df930be7Sderaadt if (nb != 0) { 153df930be7Sderaadt /* 154df930be7Sderaadt * Consider need to reallocate a fragment. 155df930be7Sderaadt */ 1567dc61945Sdownsj osize = fragroundup(fs, blkoff(fs, ip->i_ffs_size)); 157df930be7Sderaadt nsize = fragroundup(fs, size); 158df930be7Sderaadt if (nsize <= osize) { 15907feb63cScsapuntz error = bread(vp, lbn, osize, NOCRED, &bp); 160df930be7Sderaadt if (error) { 161df930be7Sderaadt brelse(bp); 162df930be7Sderaadt return (error); 163df930be7Sderaadt } 164df930be7Sderaadt } else { 16507feb63cScsapuntz error = ffs_realloccg(ip, lbn, 16607feb63cScsapuntz ffs_blkpref(ip, lbn, (int)lbn, 16707feb63cScsapuntz &ip->i_ffs_db[0]), 168df930be7Sderaadt osize, nsize, cred, &bp); 169df930be7Sderaadt if (error) 170df930be7Sderaadt return (error); 17107feb63cScsapuntz if (DOINGSOFTDEP(vp)) 17207feb63cScsapuntz softdep_setup_allocdirect(ip, lbn, 17307feb63cScsapuntz dbtofsb(fs, bp->b_blkno), nb, 17407feb63cScsapuntz nsize, osize, bp); 175df930be7Sderaadt } 176df930be7Sderaadt } else { 177*76018e64Sart if (ip->i_ffs_size < lblktosize(fs, lbn + 1)) 178df930be7Sderaadt nsize = fragroundup(fs, size); 179df930be7Sderaadt else 180df930be7Sderaadt nsize = fs->fs_bsize; 18107feb63cScsapuntz error = ffs_alloc(ip, lbn, 18207feb63cScsapuntz ffs_blkpref(ip, lbn, (int)lbn, &ip->i_ffs_db[0]), 183df930be7Sderaadt nsize, cred, &newb); 184df930be7Sderaadt if (error) 185df930be7Sderaadt return (error); 18607feb63cScsapuntz bp = getblk(vp, lbn, nsize, 0, 0); 187df930be7Sderaadt bp->b_blkno = fsbtodb(fs, newb); 188df930be7Sderaadt if (flags & B_CLRBUF) 189df930be7Sderaadt clrbuf(bp); 19007feb63cScsapuntz if (DOINGSOFTDEP(vp)) 19107feb63cScsapuntz softdep_setup_allocdirect(ip, lbn, newb, 0, 19207feb63cScsapuntz nsize, 0, bp); 19307feb63cScsapuntz 194df930be7Sderaadt } 19507feb63cScsapuntz ip->i_ffs_db[lbn] = dbtofsb(fs, bp->b_blkno); 196df930be7Sderaadt ip->i_flag |= IN_CHANGE | IN_UPDATE; 19707feb63cScsapuntz *ap->a_bpp = bp; 198df930be7Sderaadt return (0); 199df930be7Sderaadt } 200df930be7Sderaadt /* 201df930be7Sderaadt * Determine the number of levels of indirection. 202df930be7Sderaadt */ 203df930be7Sderaadt pref = 0; 20407feb63cScsapuntz if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0) 205df930be7Sderaadt return(error); 206df930be7Sderaadt #ifdef DIAGNOSTIC 207df930be7Sderaadt if (num < 1) 20830ada397Smillert panic ("ffs_balloc: ufs_bmaparray returned indirect block"); 209df930be7Sderaadt #endif 210df930be7Sderaadt /* 211df930be7Sderaadt * Fetch the first indirect block allocating if necessary. 212df930be7Sderaadt */ 213df930be7Sderaadt --num; 2147dc61945Sdownsj nb = ip->i_ffs_ib[indirs[0].in_off]; 21507feb63cScsapuntz 21607feb63cScsapuntz allocib = NULL; 21707feb63cScsapuntz allocblk = allociblk; 218df930be7Sderaadt if (nb == 0) { 219df930be7Sderaadt pref = ffs_blkpref(ip, lbn, 0, (daddr_t *)0); 220d28910b8Sniklas error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, 221d28910b8Sniklas cred, &newb); 222d28910b8Sniklas if (error) 223df930be7Sderaadt return (error); 224df930be7Sderaadt nb = newb; 22507feb63cScsapuntz 22607feb63cScsapuntz *allocblk++ = nb; 227df930be7Sderaadt bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0); 22807feb63cScsapuntz bp->b_blkno = fsbtodb(fs, nb); 229df930be7Sderaadt clrbuf(bp); 23007feb63cScsapuntz 23107feb63cScsapuntz if (DOINGSOFTDEP(vp)) { 23207feb63cScsapuntz softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off, 23307feb63cScsapuntz newb, 0, fs->fs_bsize, 0, bp); 23407feb63cScsapuntz bdwrite(bp); 23507feb63cScsapuntz } else { 236df930be7Sderaadt /* 237df930be7Sderaadt * Write synchronously so that indirect blocks 238df930be7Sderaadt * never point at garbage. 239df930be7Sderaadt */ 24007feb63cScsapuntz if ((error = bwrite(bp)) != 0) 24107feb63cScsapuntz goto fail; 242df930be7Sderaadt } 24307feb63cScsapuntz allocib = &ip->i_ffs_ib[indirs[0].in_off]; 24407feb63cScsapuntz *allocib = nb; 245df930be7Sderaadt ip->i_flag |= IN_CHANGE | IN_UPDATE; 246df930be7Sderaadt } 247df930be7Sderaadt /* 248df930be7Sderaadt * Fetch through the indirect blocks, allocating as necessary. 249df930be7Sderaadt */ 250df930be7Sderaadt for (i = 1;;) { 251df930be7Sderaadt error = bread(vp, 252df930be7Sderaadt indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp); 253df930be7Sderaadt if (error) { 254df930be7Sderaadt brelse(bp); 25507feb63cScsapuntz goto fail; 256df930be7Sderaadt } 257df930be7Sderaadt bap = (daddr_t *)bp->b_data; 258df930be7Sderaadt nb = bap[indirs[i].in_off]; 259df930be7Sderaadt if (i == num) 260df930be7Sderaadt break; 261df930be7Sderaadt i += 1; 262df930be7Sderaadt if (nb != 0) { 263df930be7Sderaadt brelse(bp); 264df930be7Sderaadt continue; 265df930be7Sderaadt } 266df930be7Sderaadt if (pref == 0) 267df930be7Sderaadt pref = ffs_blkpref(ip, lbn, 0, (daddr_t *)0); 268d28910b8Sniklas error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, 269d28910b8Sniklas &newb); 270d28910b8Sniklas if (error) { 271df930be7Sderaadt brelse(bp); 27207feb63cScsapuntz goto fail; 273df930be7Sderaadt } 274df930be7Sderaadt nb = newb; 27507feb63cScsapuntz *allocblk++ = nb; 276df930be7Sderaadt nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0); 277df930be7Sderaadt nbp->b_blkno = fsbtodb(fs, nb); 278df930be7Sderaadt clrbuf(nbp); 27907feb63cScsapuntz 28007feb63cScsapuntz if (DOINGSOFTDEP(vp)) { 28107feb63cScsapuntz softdep_setup_allocindir_meta(nbp, ip, bp, 28207feb63cScsapuntz indirs[i - 1].in_off, nb); 28307feb63cScsapuntz bdwrite(nbp); 28407feb63cScsapuntz } else { 285df930be7Sderaadt /* 286df930be7Sderaadt * Write synchronously so that indirect blocks 287df930be7Sderaadt * never point at garbage. 288df930be7Sderaadt */ 289d28910b8Sniklas if ((error = bwrite(nbp)) != 0) { 290df930be7Sderaadt brelse(bp); 29107feb63cScsapuntz goto fail; 29207feb63cScsapuntz } 293df930be7Sderaadt } 294df930be7Sderaadt bap[indirs[i - 1].in_off] = nb; 295df930be7Sderaadt /* 296df930be7Sderaadt * If required, write synchronously, otherwise use 297df930be7Sderaadt * delayed write. 298df930be7Sderaadt */ 299df930be7Sderaadt if (flags & B_SYNC) { 300df930be7Sderaadt bwrite(bp); 301df930be7Sderaadt } else { 302df930be7Sderaadt bdwrite(bp); 303df930be7Sderaadt } 304df930be7Sderaadt } 305df930be7Sderaadt /* 306df930be7Sderaadt * Get the data block, allocating if necessary. 307df930be7Sderaadt */ 308df930be7Sderaadt if (nb == 0) { 309df930be7Sderaadt pref = ffs_blkpref(ip, lbn, indirs[i].in_off, &bap[0]); 310d28910b8Sniklas error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, 311d28910b8Sniklas &newb); 312d28910b8Sniklas if (error) { 313df930be7Sderaadt brelse(bp); 31407feb63cScsapuntz goto fail; 315df930be7Sderaadt } 316df930be7Sderaadt nb = newb; 31707feb63cScsapuntz *allocblk++ = nb; 318df930be7Sderaadt nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 319df930be7Sderaadt nbp->b_blkno = fsbtodb(fs, nb); 320df930be7Sderaadt if (flags & B_CLRBUF) 321df930be7Sderaadt clrbuf(nbp); 32207feb63cScsapuntz if (DOINGSOFTDEP(vp)) 32307feb63cScsapuntz softdep_setup_allocindir_page(ip, lbn, bp, 32407feb63cScsapuntz indirs[i].in_off, nb, 0, nbp); 325df930be7Sderaadt bap[indirs[i].in_off] = nb; 326df930be7Sderaadt /* 327df930be7Sderaadt * If required, write synchronously, otherwise use 328df930be7Sderaadt * delayed write. 329df930be7Sderaadt */ 330df930be7Sderaadt if (flags & B_SYNC) { 331df930be7Sderaadt bwrite(bp); 332df930be7Sderaadt } else { 333df930be7Sderaadt bdwrite(bp); 334df930be7Sderaadt } 33507feb63cScsapuntz *ap->a_bpp = nbp; 336df930be7Sderaadt return (0); 337df930be7Sderaadt } 338df930be7Sderaadt brelse(bp); 339df930be7Sderaadt if (flags & B_CLRBUF) { 340df930be7Sderaadt error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp); 341df930be7Sderaadt if (error) { 342df930be7Sderaadt brelse(nbp); 34307feb63cScsapuntz goto fail; 344df930be7Sderaadt } 345df930be7Sderaadt } else { 346df930be7Sderaadt nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); 347df930be7Sderaadt nbp->b_blkno = fsbtodb(fs, nb); 348df930be7Sderaadt } 34907feb63cScsapuntz *ap->a_bpp = nbp; 350df930be7Sderaadt return (0); 35107feb63cScsapuntz 35207feb63cScsapuntz fail: 35307feb63cScsapuntz /* 35407feb63cScsapuntz * If we have failed part way through block allocation, we 35507feb63cScsapuntz * have to deallocate any indirect blocks that we have allocated. 35607feb63cScsapuntz */ 35707feb63cScsapuntz for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { 35807feb63cScsapuntz ffs_blkfree(ip, *blkp, fs->fs_bsize); 35907feb63cScsapuntz deallocated += fs->fs_bsize; 36007feb63cScsapuntz } 36107feb63cScsapuntz if (allocib != NULL) 36207feb63cScsapuntz *allocib = 0; 36307feb63cScsapuntz if (deallocated) { 36407feb63cScsapuntz #ifdef QUOTA 36507feb63cScsapuntz /* 36607feb63cScsapuntz * Restore user's disk quota because allocation failed. 36707feb63cScsapuntz */ 36807feb63cScsapuntz (void) chkdq(ip, (long)-btodb(deallocated), cred, FORCE); 36907feb63cScsapuntz #endif 37007feb63cScsapuntz ip->i_ffs_blocks -= btodb(deallocated); 37107feb63cScsapuntz ip->i_flag |= IN_CHANGE | IN_UPDATE; 37207feb63cScsapuntz } 37307feb63cScsapuntz return (error); 37407feb63cScsapuntz 375df930be7Sderaadt } 376