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