123396Smckusick /*
263371Sbostic * Copyright (c) 1982, 1986, 1989, 1993
363371Sbostic * The Regents of the University of California. All rights reserved.
423396Smckusick *
544537Sbostic * %sccs.include.redist.c%
637736Smckusick *
7*69910Smckusick * @(#)ffs_balloc.c 8.8 (Berkeley) 06/16/95
823396Smckusick */
97443Sroot
1051470Sbostic #include <sys/param.h>
1151470Sbostic #include <sys/systm.h>
1251470Sbostic #include <sys/buf.h>
1351470Sbostic #include <sys/proc.h>
1451470Sbostic #include <sys/file.h>
1551470Sbostic #include <sys/vnode.h>
167443Sroot
1753318Smckusick #include <vm/vm.h>
1853318Smckusick
1951470Sbostic #include <ufs/ufs/quota.h>
2051470Sbostic #include <ufs/ufs/inode.h>
2156444Smargo #include <ufs/ufs/ufs_extern.h>
2247571Skarels
2351470Sbostic #include <ufs/ffs/fs.h>
2451470Sbostic #include <ufs/ffs/ffs_extern.h>
2551470Sbostic
267443Sroot /*
2737736Smckusick * Balloc defines the structure of file system storage
2839679Smckusick * by allocating the physical blocks on a device given
2939679Smckusick * the inode and the logical block number in a file.
3037736Smckusick */
ffs_balloc(ip,lbn,size,cred,bpp,flags)3168153Smckusick ffs_balloc(ip, lbn, size, cred, bpp, flags)
3237736Smckusick register struct inode *ip;
3368554Smckusick register ufs_daddr_t lbn;
3437736Smckusick int size;
3553244Smckusick struct ucred *cred;
3639679Smckusick struct buf **bpp;
3737736Smckusick int flags;
3837736Smckusick {
3937736Smckusick register struct fs *fs;
4068554Smckusick register ufs_daddr_t nb;
417443Sroot struct buf *bp, *nbp;
4239679Smckusick struct vnode *vp = ITOV(ip);
4356444Smargo struct indir indirs[NIADDR + 2];
4468554Smckusick ufs_daddr_t newb, *bap, pref;
4569514Smckusick int deallocated, osize, nsize, num, i, error;
46*69910Smckusick ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1];
477443Sroot
4864420Sbostic *bpp = NULL;
4968153Smckusick if (lbn < 0)
5037736Smckusick return (EFBIG);
517443Sroot fs = ip->i_fs;
527443Sroot
537443Sroot /*
547443Sroot * If the next write will extend the file into a new block,
557443Sroot * and the file is currently composed of a fragment
567443Sroot * this fragment has to be extended to be a full block.
577443Sroot */
587443Sroot nb = lblkno(fs, ip->i_size);
5968153Smckusick if (nb < NDADDR && nb < lbn) {
607443Sroot osize = blksize(fs, ip, nb);
617443Sroot if (osize < fs->fs_bsize && osize > 0) {
6251470Sbostic error = ffs_realloccg(ip, nb,
6351470Sbostic ffs_blkpref(ip, nb, (int)nb, &ip->i_db[0]),
6453244Smckusick osize, (int)fs->fs_bsize, cred, &bp);
6539679Smckusick if (error)
6637736Smckusick return (error);
677443Sroot ip->i_size = (nb + 1) * fs->fs_bsize;
6853047Sralph vnode_pager_setsize(vp, (u_long)ip->i_size);
697443Sroot ip->i_db[nb] = dbtofsb(fs, bp->b_blkno);
7064606Sbostic ip->i_flag |= IN_CHANGE | IN_UPDATE;
7139679Smckusick if (flags & B_SYNC)
7239679Smckusick bwrite(bp);
7339679Smckusick else
7439679Smckusick bawrite(bp);
757443Sroot }
767443Sroot }
777443Sroot /*
787443Sroot * The first NDADDR blocks are direct blocks
797443Sroot */
8068153Smckusick if (lbn < NDADDR) {
8168153Smckusick nb = ip->i_db[lbn];
8268153Smckusick if (nb != 0 && ip->i_size >= (lbn + 1) * fs->fs_bsize) {
8368153Smckusick error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp);
8439679Smckusick if (error) {
8539679Smckusick brelse(bp);
8639679Smckusick return (error);
8739679Smckusick }
8839679Smckusick *bpp = bp;
8939679Smckusick return (0);
9039679Smckusick }
9139679Smckusick if (nb != 0) {
9239679Smckusick /*
9339679Smckusick * Consider need to reallocate a fragment.
9439679Smckusick */
9539679Smckusick osize = fragroundup(fs, blkoff(fs, ip->i_size));
9639679Smckusick nsize = fragroundup(fs, size);
9739679Smckusick if (nsize <= osize) {
9868153Smckusick error = bread(vp, lbn, osize, NOCRED, &bp);
9939679Smckusick if (error) {
10039679Smckusick brelse(bp);
10139679Smckusick return (error);
10239679Smckusick }
10339679Smckusick } else {
10468153Smckusick error = ffs_realloccg(ip, lbn,
10568153Smckusick ffs_blkpref(ip, lbn, (int)lbn,
10668153Smckusick &ip->i_db[0]), osize, nsize, cred, &bp);
10739679Smckusick if (error)
10839679Smckusick return (error);
1097443Sroot }
11039679Smckusick } else {
11168153Smckusick if (ip->i_size < (lbn + 1) * fs->fs_bsize)
11239679Smckusick nsize = fragroundup(fs, size);
11339679Smckusick else
11439679Smckusick nsize = fs->fs_bsize;
11568153Smckusick error = ffs_alloc(ip, lbn,
11668153Smckusick ffs_blkpref(ip, lbn, (int)lbn, &ip->i_db[0]),
11753244Smckusick nsize, cred, &newb);
11839679Smckusick if (error)
11937736Smckusick return (error);
12068153Smckusick bp = getblk(vp, lbn, nsize, 0, 0);
12139679Smckusick bp->b_blkno = fsbtodb(fs, newb);
12239679Smckusick if (flags & B_CLRBUF)
12339679Smckusick clrbuf(bp);
1247443Sroot }
12568153Smckusick ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno);
12664606Sbostic ip->i_flag |= IN_CHANGE | IN_UPDATE;
12739679Smckusick *bpp = bp;
12837736Smckusick return (0);
1297443Sroot }
1307443Sroot /*
13139679Smckusick * Determine the number of levels of indirection.
1327443Sroot */
1338258Smckusick pref = 0;
13468153Smckusick if (error = ufs_getlbns(vp, lbn, indirs, &num))
13556444Smargo return(error);
13656444Smargo #ifdef DIAGNOSTIC
13756444Smargo if (num < 1)
13856444Smargo panic ("ffs_balloc: ufs_bmaparray returned indirect block\n");
13956444Smargo #endif
1407443Sroot /*
14139679Smckusick * Fetch the first indirect block allocating if necessary.
1427443Sroot */
14356444Smargo --num;
14456444Smargo nb = ip->i_ib[indirs[0].in_off];
145*69910Smckusick allocib = NULL;
14669514Smckusick allocblk = allociblk;
1477443Sroot if (nb == 0) {
14868554Smckusick pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
14953244Smckusick if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
15053244Smckusick cred, &newb))
15137736Smckusick return (error);
15239679Smckusick nb = newb;
153*69910Smckusick *allocblk++ = nb;
15457802Smckusick bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0);
155*69910Smckusick bp->b_blkno = fsbtodb(fs, nb);
15639679Smckusick clrbuf(bp);
1577443Sroot /*
1587443Sroot * Write synchronously so that indirect blocks
1597443Sroot * never point at garbage.
1607443Sroot */
161*69910Smckusick if (error = bwrite(bp))
162*69910Smckusick goto fail;
16369514Smckusick allocib = &ip->i_ib[indirs[0].in_off];
164*69910Smckusick *allocib = nb;
16564606Sbostic ip->i_flag |= IN_CHANGE | IN_UPDATE;
1667443Sroot }
1677443Sroot /*
16839679Smckusick * Fetch through the indirect blocks, allocating as necessary.
1697443Sroot */
17064420Sbostic for (i = 1;;) {
17164420Sbostic error = bread(vp,
17264420Sbostic indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp);
17339679Smckusick if (error) {
1747443Sroot brelse(bp);
17569514Smckusick goto fail;
1767443Sroot }
17768554Smckusick bap = (ufs_daddr_t *)bp->b_data;
17864420Sbostic nb = bap[indirs[i].in_off];
17964420Sbostic if (i == num)
18039679Smckusick break;
18164420Sbostic i += 1;
18239679Smckusick if (nb != 0) {
18339679Smckusick brelse(bp);
18439679Smckusick continue;
18539679Smckusick }
18639679Smckusick if (pref == 0)
18768554Smckusick pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0);
18851470Sbostic if (error =
18953244Smckusick ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) {
19039679Smckusick brelse(bp);
19169514Smckusick goto fail;
19239679Smckusick }
19339679Smckusick nb = newb;
194*69910Smckusick *allocblk++ = nb;
19564420Sbostic nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0);
19656444Smargo nbp->b_blkno = fsbtodb(fs, nb);
19739679Smckusick clrbuf(nbp);
19839679Smckusick /*
19939679Smckusick * Write synchronously so that indirect blocks
20039679Smckusick * never point at garbage.
20139679Smckusick */
20239679Smckusick if (error = bwrite(nbp)) {
20339679Smckusick brelse(bp);
20469514Smckusick goto fail;
20539679Smckusick }
20664420Sbostic bap[indirs[i - 1].in_off] = nb;
20739878Smckusick /*
20839878Smckusick * If required, write synchronously, otherwise use
20956444Smargo * delayed write.
21039878Smckusick */
21139878Smckusick if (flags & B_SYNC) {
21239679Smckusick bwrite(bp);
21339878Smckusick } else {
21439878Smckusick bdwrite(bp);
21539878Smckusick }
21639679Smckusick }
21739679Smckusick /*
21839679Smckusick * Get the data block, allocating if necessary.
21939679Smckusick */
22039679Smckusick if (nb == 0) {
22164420Sbostic pref = ffs_blkpref(ip, lbn, indirs[i].in_off, &bap[0]);
22264420Sbostic if (error = ffs_alloc(ip,
22364420Sbostic lbn, pref, (int)fs->fs_bsize, cred, &newb)) {
2247443Sroot brelse(bp);
22569514Smckusick goto fail;
22639679Smckusick }
22739679Smckusick nb = newb;
228*69910Smckusick *allocblk++ = nb;
22957802Smckusick nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
23039679Smckusick nbp->b_blkno = fsbtodb(fs, nb);
23139679Smckusick if (flags & B_CLRBUF)
23239679Smckusick clrbuf(nbp);
23364420Sbostic bap[indirs[i].in_off] = nb;
23439878Smckusick /*
23539878Smckusick * If required, write synchronously, otherwise use
23656444Smargo * delayed write.
23739878Smckusick */
23839878Smckusick if (flags & B_SYNC) {
23939679Smckusick bwrite(bp);
24039878Smckusick } else {
24139878Smckusick bdwrite(bp);
24239878Smckusick }
24339679Smckusick *bpp = nbp;
24439679Smckusick return (0);
2457443Sroot }
24639679Smckusick brelse(bp);
24741333Smckusick if (flags & B_CLRBUF) {
24839679Smckusick error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp);
24939679Smckusick if (error) {
25039679Smckusick brelse(nbp);
25169514Smckusick goto fail;
25239679Smckusick }
25341333Smckusick } else {
25457802Smckusick nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0);
25541333Smckusick nbp->b_blkno = fsbtodb(fs, nb);
25639679Smckusick }
25739679Smckusick *bpp = nbp;
25837736Smckusick return (0);
25969514Smckusick fail:
26069514Smckusick /*
26169514Smckusick * If we have failed part way through block allocation, we
26269514Smckusick * have to deallocate any indirect blocks that we have allocated.
26369514Smckusick */
264*69910Smckusick for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) {
26569514Smckusick ffs_blkfree(ip, *blkp, fs->fs_bsize);
26669514Smckusick deallocated += fs->fs_bsize;
26769514Smckusick }
268*69910Smckusick if (allocib != NULL)
269*69910Smckusick *allocib = 0;
27069514Smckusick if (deallocated) {
27169514Smckusick #ifdef QUOTA
27269514Smckusick /*
27369514Smckusick * Restore user's disk quota because allocation failed.
27469514Smckusick */
27569514Smckusick (void) chkdq(ip, (long)-btodb(deallocated), cred, FORCE);
27669514Smckusick #endif
27769514Smckusick ip->i_blocks -= btodb(deallocated);
27869514Smckusick ip->i_flag |= IN_CHANGE | IN_UPDATE;
27969514Smckusick }
28069514Smckusick return (error);
2817443Sroot }
282