1139778Simp/*- 212115Sdyson * modified for Lites 1.1 312115Sdyson * 412115Sdyson * Aug 1995, Godmar Back (gback@cs.utah.edu) 512115Sdyson * University of Utah, Department of Computer Science 612115Sdyson */ 7139778Simp/*- 812115Sdyson * Copyright (c) 1982, 1986, 1989, 1993 912115Sdyson * The Regents of the University of California. All rights reserved. 1012115Sdyson * 1112115Sdyson * Redistribution and use in source and binary forms, with or without 1212115Sdyson * modification, are permitted provided that the following conditions 1312115Sdyson * are met: 1412115Sdyson * 1. Redistributions of source code must retain the above copyright 1512115Sdyson * notice, this list of conditions and the following disclaimer. 1612115Sdyson * 2. Redistributions in binary form must reproduce the above copyright 1712115Sdyson * notice, this list of conditions and the following disclaimer in the 1812115Sdyson * documentation and/or other materials provided with the distribution. 1912115Sdyson * 4. Neither the name of the University nor the names of its contributors 2012115Sdyson * may be used to endorse or promote products derived from this software 2112115Sdyson * without specific prior written permission. 2212115Sdyson * 2312115Sdyson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2412115Sdyson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2512115Sdyson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2612115Sdyson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2712115Sdyson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2812115Sdyson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2912115Sdyson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3012115Sdyson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3112115Sdyson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3212115Sdyson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3312115Sdyson * SUCH DAMAGE. 3412115Sdyson * 3512115Sdyson * @(#)ffs_balloc.c 8.4 (Berkeley) 9/23/93 3660041Sphk * $FreeBSD$ 3712115Sdyson */ 3812115Sdyson 3912115Sdyson#include <sys/param.h> 4012115Sdyson#include <sys/systm.h> 4160041Sphk#include <sys/bio.h> 4212115Sdyson#include <sys/buf.h> 4331561Sbde#include <sys/lock.h> 44221166Sjhb#include <sys/mount.h> 4512115Sdyson#include <sys/vnode.h> 4612115Sdyson 47251809Spfg#include <fs/ext2fs/fs.h> 48202283Slulf#include <fs/ext2fs/inode.h> 49202283Slulf#include <fs/ext2fs/ext2fs.h> 50251809Spfg#include <fs/ext2fs/ext2_dinode.h> 51202283Slulf#include <fs/ext2fs/ext2_extern.h> 52202283Slulf#include <fs/ext2fs/ext2_mount.h> 53251809Spfg 5412115Sdyson/* 55251612Spfg * Balloc defines the structure of filesystem storage 5612115Sdyson * by allocating the physical blocks on a device given 5712115Sdyson * the inode and the logical block number in a file. 5812115Sdyson */ 5912115Sdysonint 60252103Spfgext2_balloc(struct inode *ip, e2fs_lbn_t lbn, int size, struct ucred *cred, 61246634Spfg struct buf **bpp, int flags) 6212115Sdyson{ 63202283Slulf struct m_ext2fs *fs; 64202283Slulf struct ext2mount *ump; 6512115Sdyson struct buf *bp, *nbp; 6612115Sdyson struct vnode *vp = ITOV(ip); 6712115Sdyson struct indir indirs[NIADDR + 2]; 68254283Spfg e4fs_daddr_t nb, newb; 69254283Spfg e2fs_daddr_t *bap, pref; 7012115Sdyson int osize, nsize, num, i, error; 71202283Slulf 7212115Sdyson *bpp = NULL; 73202283Slulf if (lbn < 0) 7412115Sdyson return (EFBIG); 7512115Sdyson fs = ip->i_e2fs; 76202283Slulf ump = ip->i_ump; 7712115Sdyson 7812115Sdyson /* 7912115Sdyson * check if this is a sequential block allocation. 8012115Sdyson * If so, increment next_alloc fields to allow ext2_blkpref 8112115Sdyson * to make a good guess 8212115Sdyson */ 8312115Sdyson if (lbn == ip->i_next_alloc_block + 1) { 8412115Sdyson ip->i_next_alloc_block++; 8512115Sdyson ip->i_next_alloc_goal++; 8612115Sdyson } 8712115Sdyson 8812115Sdyson /* 8912115Sdyson * The first NDADDR blocks are direct blocks 9012115Sdyson */ 91202283Slulf if (lbn < NDADDR) { 92202283Slulf nb = ip->i_db[lbn]; 9312115Sdyson /* no new block is to be allocated, and no need to expand 9412115Sdyson the file */ 95202283Slulf if (nb != 0 && ip->i_size >= (lbn + 1) * fs->e2fs_bsize) { 96202283Slulf error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp); 9712115Sdyson if (error) { 9812115Sdyson brelse(bp); 9912115Sdyson return (error); 10012115Sdyson } 10175951Sbde bp->b_blkno = fsbtodb(fs, nb); 10212115Sdyson *bpp = bp; 10312115Sdyson return (0); 10412115Sdyson } 10512115Sdyson if (nb != 0) { 10612115Sdyson /* 10712115Sdyson * Consider need to reallocate a fragment. 10812115Sdyson */ 10912115Sdyson osize = fragroundup(fs, blkoff(fs, ip->i_size)); 11012115Sdyson nsize = fragroundup(fs, size); 11112115Sdyson if (nsize <= osize) { 112202283Slulf error = bread(vp, lbn, osize, NOCRED, &bp); 11312115Sdyson if (error) { 11412115Sdyson brelse(bp); 11512115Sdyson return (error); 11612115Sdyson } 11775951Sbde bp->b_blkno = fsbtodb(fs, nb); 11812115Sdyson } else { 11912115Sdyson /* Godmar thinks: this shouldn't happen w/o fragments */ 12012115Sdyson printf("nsize %d(%d) > osize %d(%d) nb %d\n", 12112115Sdyson (int)nsize, (int)size, (int)osize, 12212115Sdyson (int)ip->i_size, (int)nb); 12324492Sbde panic( 12424492Sbde "ext2_balloc: Something is terribly wrong"); 12512115Sdyson/* 12612115Sdyson * please note there haven't been any changes from here on - 12712115Sdyson * FFS seems to work. 12812115Sdyson */ 12912115Sdyson } 13012115Sdyson } else { 131202283Slulf if (ip->i_size < (lbn + 1) * fs->e2fs_bsize) 13212115Sdyson nsize = fragroundup(fs, size); 13312115Sdyson else 134202283Slulf nsize = fs->e2fs_bsize; 135202283Slulf EXT2_LOCK(ump); 136202283Slulf error = ext2_alloc(ip, lbn, 137202283Slulf ext2_blkpref(ip, lbn, (int)lbn, &ip->i_db[0], 0), 13812115Sdyson nsize, cred, &newb); 13912115Sdyson if (error) 14012115Sdyson return (error); 141202283Slulf bp = getblk(vp, lbn, nsize, 0, 0, 0); 14212115Sdyson bp->b_blkno = fsbtodb(fs, newb); 143221166Sjhb if (flags & BA_CLRBUF) 14412115Sdyson vfs_bio_clrbuf(bp); 14512115Sdyson } 146202283Slulf ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno); 14712115Sdyson ip->i_flag |= IN_CHANGE | IN_UPDATE; 14812115Sdyson *bpp = bp; 14912115Sdyson return (0); 15012115Sdyson } 15112115Sdyson /* 15212115Sdyson * Determine the number of levels of indirection. 15312115Sdyson */ 15412115Sdyson pref = 0; 155202283Slulf if ((error = ext2_getlbns(vp, lbn, indirs, &num)) != 0) 156228583Spfg return (error); 157251658Spfg#ifdef INVARIANTS 15812115Sdyson if (num < 1) 15996749Siedowse panic ("ext2_balloc: ext2_getlbns returned indirect block"); 16012115Sdyson#endif 16112115Sdyson /* 16212115Sdyson * Fetch the first indirect block allocating if necessary. 16312115Sdyson */ 16412115Sdyson --num; 16512115Sdyson nb = ip->i_ib[indirs[0].in_off]; 16612115Sdyson if (nb == 0) { 167202283Slulf EXT2_LOCK(ump); 16812115Sdyson pref = ext2_blkpref(ip, lbn, indirs[0].in_off + 16912115Sdyson EXT2_NDIR_BLOCKS, &ip->i_db[0], 0); 170251677Spfg if ((error = ext2_alloc(ip, lbn, pref, fs->e2fs_bsize, cred, 171251677Spfg &newb))) 17212115Sdyson return (error); 17312115Sdyson nb = newb; 174202283Slulf bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0, 0); 17512115Sdyson bp->b_blkno = fsbtodb(fs, newb); 17612115Sdyson vfs_bio_clrbuf(bp); 17712115Sdyson /* 17812115Sdyson * Write synchronously so that indirect blocks 17912115Sdyson * never point at garbage. 18012115Sdyson */ 18143301Sdillon if ((error = bwrite(bp)) != 0) { 182202283Slulf ext2_blkfree(ip, nb, fs->e2fs_bsize); 18312115Sdyson return (error); 18412115Sdyson } 18512115Sdyson ip->i_ib[indirs[0].in_off] = newb; 18612115Sdyson ip->i_flag |= IN_CHANGE | IN_UPDATE; 18712115Sdyson } 18812115Sdyson /* 18912115Sdyson * Fetch through the indirect blocks, allocating as necessary. 19012115Sdyson */ 19112115Sdyson for (i = 1;;) { 19212115Sdyson error = bread(vp, 193202283Slulf indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp); 19412115Sdyson if (error) { 19512115Sdyson brelse(bp); 19612115Sdyson return (error); 19712115Sdyson } 198254283Spfg bap = (e2fs_daddr_t *)bp->b_data; 19912115Sdyson nb = bap[indirs[i].in_off]; 20012115Sdyson if (i == num) 20112115Sdyson break; 20212115Sdyson i += 1; 20312115Sdyson if (nb != 0) { 204202283Slulf bqrelse(bp); 20512115Sdyson continue; 20612115Sdyson } 207202283Slulf EXT2_LOCK(ump); 208202283Slulf if (pref == 0) 20912115Sdyson pref = ext2_blkpref(ip, lbn, indirs[i].in_off, bap, 21012115Sdyson bp->b_lblkno); 211202283Slulf error = ext2_alloc(ip, lbn, pref, (int)fs->e2fs_bsize, cred, &newb); 212202283Slulf if (error) { 21312115Sdyson brelse(bp); 21412115Sdyson return (error); 21512115Sdyson } 21612115Sdyson nb = newb; 217202283Slulf nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0, 0); 21812115Sdyson nbp->b_blkno = fsbtodb(fs, nb); 21912115Sdyson vfs_bio_clrbuf(nbp); 22012115Sdyson /* 22112115Sdyson * Write synchronously so that indirect blocks 22212115Sdyson * never point at garbage. 22312115Sdyson */ 22443301Sdillon if ((error = bwrite(nbp)) != 0) { 225202283Slulf ext2_blkfree(ip, nb, fs->e2fs_bsize); 226202283Slulf EXT2_UNLOCK(ump); 22712115Sdyson brelse(bp); 22812115Sdyson return (error); 22912115Sdyson } 23012115Sdyson bap[indirs[i - 1].in_off] = nb; 23112115Sdyson /* 23212115Sdyson * If required, write synchronously, otherwise use 23312115Sdyson * delayed write. 23412115Sdyson */ 235221166Sjhb if (flags & IO_SYNC) { 23612115Sdyson bwrite(bp); 23712115Sdyson } else { 238202283Slulf if (bp->b_bufsize == fs->e2fs_bsize) 239202283Slulf bp->b_flags |= B_CLUSTEROK; 24012115Sdyson bdwrite(bp); 24112115Sdyson } 24212115Sdyson } 24312115Sdyson /* 24412115Sdyson * Get the data block, allocating if necessary. 24512115Sdyson */ 24612115Sdyson if (nb == 0) { 247202283Slulf EXT2_LOCK(ump); 24812115Sdyson pref = ext2_blkpref(ip, lbn, indirs[i].in_off, &bap[0], 24912115Sdyson bp->b_lblkno); 25043301Sdillon if ((error = ext2_alloc(ip, 251202283Slulf lbn, pref, (int)fs->e2fs_bsize, cred, &newb)) != 0) { 25212115Sdyson brelse(bp); 25312115Sdyson return (error); 25412115Sdyson } 25512115Sdyson nb = newb; 256202283Slulf nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0); 25712115Sdyson nbp->b_blkno = fsbtodb(fs, nb); 258221166Sjhb if (flags & BA_CLRBUF) 25912115Sdyson vfs_bio_clrbuf(nbp); 26012115Sdyson bap[indirs[i].in_off] = nb; 26112115Sdyson /* 26212115Sdyson * If required, write synchronously, otherwise use 26312115Sdyson * delayed write. 26412115Sdyson */ 265221166Sjhb if (flags & IO_SYNC) { 26612115Sdyson bwrite(bp); 26712115Sdyson } else { 268202283Slulf if (bp->b_bufsize == fs->e2fs_bsize) 269202283Slulf bp->b_flags |= B_CLUSTEROK; 27012115Sdyson bdwrite(bp); 27112115Sdyson } 27212115Sdyson *bpp = nbp; 27312115Sdyson return (0); 27412115Sdyson } 27512115Sdyson brelse(bp); 276221166Sjhb if (flags & BA_CLRBUF) { 277221166Sjhb int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT; 278221166Sjhb if (seqcount && (vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { 279221166Sjhb error = cluster_read(vp, ip->i_size, lbn, 280221166Sjhb (int)fs->e2fs_bsize, NOCRED, 281248282Skib MAXBSIZE, seqcount, 0, &nbp); 282221166Sjhb } else { 283221166Sjhb error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, &nbp); 284221166Sjhb } 28512115Sdyson if (error) { 28612115Sdyson brelse(nbp); 28712115Sdyson return (error); 28812115Sdyson } 28912115Sdyson } else { 290202283Slulf nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0); 29112115Sdyson nbp->b_blkno = fsbtodb(fs, nb); 29212115Sdyson } 29312115Sdyson *bpp = nbp; 29412115Sdyson return (0); 29512115Sdyson} 296202283Slulf 297