xref: /dflybsd-src/sys/vfs/ext2fs/ext2_balloc.c (revision e5b38eb588d517bc6924dd57a647f58246c5217b)
1cfe60390STomohiro Kusumi /*-
2cfe60390STomohiro Kusumi  *  modified for Lites 1.1
3cfe60390STomohiro Kusumi  *
4cfe60390STomohiro Kusumi  *  Aug 1995, Godmar Back (gback@cs.utah.edu)
5cfe60390STomohiro Kusumi  *  University of Utah, Department of Computer Science
6cfe60390STomohiro Kusumi  */
7cfe60390STomohiro Kusumi /*-
8cfe60390STomohiro Kusumi  * SPDX-License-Identifier: BSD-3-Clause
9cfe60390STomohiro Kusumi  *
10cfe60390STomohiro Kusumi  * Copyright (c) 1982, 1986, 1989, 1993
11cfe60390STomohiro Kusumi  *	The Regents of the University of California.  All rights reserved.
12cfe60390STomohiro Kusumi  *
13cfe60390STomohiro Kusumi  * Redistribution and use in source and binary forms, with or without
14cfe60390STomohiro Kusumi  * modification, are permitted provided that the following conditions
15cfe60390STomohiro Kusumi  * are met:
16cfe60390STomohiro Kusumi  * 1. Redistributions of source code must retain the above copyright
17cfe60390STomohiro Kusumi  *    notice, this list of conditions and the following disclaimer.
18cfe60390STomohiro Kusumi  * 2. Redistributions in binary form must reproduce the above copyright
19cfe60390STomohiro Kusumi  *    notice, this list of conditions and the following disclaimer in the
20cfe60390STomohiro Kusumi  *    documentation and/or other materials provided with the distribution.
21cfe60390STomohiro Kusumi  * 3. Neither the name of the University nor the names of its contributors
22cfe60390STomohiro Kusumi  *    may be used to endorse or promote products derived from this software
23cfe60390STomohiro Kusumi  *    without specific prior written permission.
24cfe60390STomohiro Kusumi  *
25cfe60390STomohiro Kusumi  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26cfe60390STomohiro Kusumi  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27cfe60390STomohiro Kusumi  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28cfe60390STomohiro Kusumi  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29cfe60390STomohiro Kusumi  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30cfe60390STomohiro Kusumi  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31cfe60390STomohiro Kusumi  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32cfe60390STomohiro Kusumi  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33cfe60390STomohiro Kusumi  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34cfe60390STomohiro Kusumi  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35cfe60390STomohiro Kusumi  * SUCH DAMAGE.
36cfe60390STomohiro Kusumi  *
37cfe60390STomohiro Kusumi  *	@(#)ffs_balloc.c	8.4 (Berkeley) 9/23/93
38cfe60390STomohiro Kusumi  * $FreeBSD$
39cfe60390STomohiro Kusumi  */
40cfe60390STomohiro Kusumi 
41cfe60390STomohiro Kusumi #include <sys/param.h>
42cfe60390STomohiro Kusumi #include <sys/systm.h>
43cfe60390STomohiro Kusumi #include <sys/endian.h>
44cfe60390STomohiro Kusumi #include <sys/bio.h>
45cfe60390STomohiro Kusumi #include <sys/buf2.h>
46cfe60390STomohiro Kusumi #include <sys/limits.h>
47cfe60390STomohiro Kusumi #include <sys/lock.h>
48cfe60390STomohiro Kusumi #include <sys/mount.h>
49cfe60390STomohiro Kusumi #include <sys/vnode.h>
50cfe60390STomohiro Kusumi #include <sys/mutex2.h>
51cfe60390STomohiro Kusumi 
52cfe60390STomohiro Kusumi #include <vfs/ext2fs/fs.h>
53cfe60390STomohiro Kusumi #include <vfs/ext2fs/inode.h>
54cfe60390STomohiro Kusumi #include <vfs/ext2fs/ext2fs.h>
55cfe60390STomohiro Kusumi #include <vfs/ext2fs/ext2_dinode.h>
56cfe60390STomohiro Kusumi #include <vfs/ext2fs/ext2_extern.h>
57cfe60390STomohiro Kusumi #include <vfs/ext2fs/ext2_mount.h>
58cfe60390STomohiro Kusumi 
59cfe60390STomohiro Kusumi static int
ext2_ext_balloc(struct inode * ip,uint32_t lbn,int size,struct ucred * cred,struct buf ** bpp,int flags)60cfe60390STomohiro Kusumi ext2_ext_balloc(struct inode *ip, uint32_t lbn, int size,
61cfe60390STomohiro Kusumi     struct ucred *cred, struct buf **bpp, int flags)
62cfe60390STomohiro Kusumi {
63cfe60390STomohiro Kusumi 	return (EINVAL);
64cfe60390STomohiro Kusumi }
65cfe60390STomohiro Kusumi 
66cfe60390STomohiro Kusumi /*
67cfe60390STomohiro Kusumi  * Balloc defines the structure of filesystem storage
68cfe60390STomohiro Kusumi  * by allocating the physical blocks on a device given
69cfe60390STomohiro Kusumi  * the inode and the logical block number in a file.
70cfe60390STomohiro Kusumi  */
71cfe60390STomohiro Kusumi int
ext2_balloc(struct inode * ip,e2fs_lbn_t lbn,int size,struct ucred * cred,struct buf ** bpp,int flags)72cfe60390STomohiro Kusumi ext2_balloc(struct inode *ip, e2fs_lbn_t lbn, int size, struct ucred *cred,
73cfe60390STomohiro Kusumi     struct buf **bpp, int flags)
74cfe60390STomohiro Kusumi {
75cfe60390STomohiro Kusumi 	struct m_ext2fs *fs;
76cfe60390STomohiro Kusumi 	struct ext2mount *ump;
77cfe60390STomohiro Kusumi 	struct buf *bp, *nbp;
78cfe60390STomohiro Kusumi 	struct vnode *vp = ITOV(ip);
79cfe60390STomohiro Kusumi 	struct indir indirs[EXT2_NIADDR + 2];
80cfe60390STomohiro Kusumi 	e4fs_daddr_t nb, newb;
81cfe60390STomohiro Kusumi 	e2fs_daddr_t *bap, pref;
82cfe60390STomohiro Kusumi 	int num, i, error;
83cfe60390STomohiro Kusumi 
84cfe60390STomohiro Kusumi 	*bpp = NULL;
85cfe60390STomohiro Kusumi 	if (lbn < 0)
86cfe60390STomohiro Kusumi 		return (EFBIG);
87cfe60390STomohiro Kusumi 	fs = ip->i_e2fs;
88cfe60390STomohiro Kusumi 	ump = ip->i_ump;
89cfe60390STomohiro Kusumi 
90cfe60390STomohiro Kusumi 	/*
91cfe60390STomohiro Kusumi 	 * check if this is a sequential block allocation.
92cfe60390STomohiro Kusumi 	 * If so, increment next_alloc fields to allow ext2_blkpref
93cfe60390STomohiro Kusumi 	 * to make a good guess
94cfe60390STomohiro Kusumi 	 */
95cfe60390STomohiro Kusumi 	if (lbn == ip->i_next_alloc_block + 1) {
96cfe60390STomohiro Kusumi 		ip->i_next_alloc_block++;
97cfe60390STomohiro Kusumi 		ip->i_next_alloc_goal++;
98cfe60390STomohiro Kusumi 	}
99cfe60390STomohiro Kusumi 
100cfe60390STomohiro Kusumi 	if (ip->i_flag & IN_E4EXTENTS)
101cfe60390STomohiro Kusumi 		return (ext2_ext_balloc(ip, lbn, size, cred, bpp, flags));
102cfe60390STomohiro Kusumi 
103cfe60390STomohiro Kusumi 	/*
104cfe60390STomohiro Kusumi 	 * The first EXT2_NDADDR blocks are direct blocks
105cfe60390STomohiro Kusumi 	 */
106cfe60390STomohiro Kusumi 	if (lbn < EXT2_NDADDR) {
107cfe60390STomohiro Kusumi 		nb = ip->i_db[lbn];
108cfe60390STomohiro Kusumi 		/*
109cfe60390STomohiro Kusumi 		 * no new block is to be allocated, and no need to expand
110cfe60390STomohiro Kusumi 		 * the file
111cfe60390STomohiro Kusumi 		 */
112cfe60390STomohiro Kusumi 		if (nb != 0) {
113*e5b38eb5STomohiro Kusumi 			error = bread(vp, lblktodoff(fs, lbn), fs->e2fs_bsize,
114*e5b38eb5STomohiro Kusumi 			    &bp);
115cfe60390STomohiro Kusumi 			if (error) {
116*e5b38eb5STomohiro Kusumi 				brelse(bp);
117cfe60390STomohiro Kusumi 				return (error);
118cfe60390STomohiro Kusumi 			}
119cfe60390STomohiro Kusumi 			bp->b_bio2.bio_offset = fsbtodoff(fs, nb);
120cfe60390STomohiro Kusumi 			if (ip->i_size >= (lbn + 1) * fs->e2fs_bsize) {
121cfe60390STomohiro Kusumi 				*bpp = bp;
122cfe60390STomohiro Kusumi 				return (0);
123cfe60390STomohiro Kusumi 			}
124cfe60390STomohiro Kusumi 		} else {
125cfe60390STomohiro Kusumi 			EXT2_LOCK(ump);
126cfe60390STomohiro Kusumi 			error = ext2_alloc(ip, lbn,
127cfe60390STomohiro Kusumi 			    ext2_blkpref(ip, lbn, (int)lbn, &ip->i_db[0], 0),
128cfe60390STomohiro Kusumi 			    fs->e2fs_bsize, cred, &newb);
129cfe60390STomohiro Kusumi 			if (error)
130cfe60390STomohiro Kusumi 				return (error);
131cfe60390STomohiro Kusumi 			/*
132cfe60390STomohiro Kusumi 			 * If the newly allocated block exceeds 32-bit limit,
133cfe60390STomohiro Kusumi 			 * we can not use it in file block maps.
134cfe60390STomohiro Kusumi 			 */
135cfe60390STomohiro Kusumi 			if (newb > UINT_MAX)
136cfe60390STomohiro Kusumi 				return (EFBIG);
137cfe60390STomohiro Kusumi 			bp = getblk(vp, lblktodoff(fs, lbn), fs->e2fs_bsize, 0, 0);
138cfe60390STomohiro Kusumi 			bp->b_bio2.bio_offset = fsbtodoff(fs, newb);
139cfe60390STomohiro Kusumi 			if (flags & BA_CLRBUF)
140cfe60390STomohiro Kusumi 				vfs_bio_clrbuf(bp);
141cfe60390STomohiro Kusumi 		}
142cfe60390STomohiro Kusumi 		ip->i_db[lbn] = dofftofsb(fs, bp->b_bio2.bio_offset);
143cfe60390STomohiro Kusumi 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
144cfe60390STomohiro Kusumi 		*bpp = bp;
145cfe60390STomohiro Kusumi 		return (0);
146cfe60390STomohiro Kusumi 	}
147cfe60390STomohiro Kusumi 	/*
148cfe60390STomohiro Kusumi 	 * Determine the number of levels of indirection.
149cfe60390STomohiro Kusumi 	 */
150cfe60390STomohiro Kusumi 	pref = 0;
151cfe60390STomohiro Kusumi 	if ((error = ext2_getlbns(vp, lbn, indirs, &num)) != 0)
152cfe60390STomohiro Kusumi 		return (error);
153cfe60390STomohiro Kusumi #ifdef INVARIANTS
154cfe60390STomohiro Kusumi 	if (num < 1)
155cfe60390STomohiro Kusumi 		panic("ext2_balloc: ext2_getlbns returned indirect block");
156cfe60390STomohiro Kusumi #endif
157cfe60390STomohiro Kusumi 	/*
158cfe60390STomohiro Kusumi 	 * Fetch the first indirect block allocating if necessary.
159cfe60390STomohiro Kusumi 	 */
160cfe60390STomohiro Kusumi 	--num;
161cfe60390STomohiro Kusumi 	nb = ip->i_ib[indirs[0].in_off];
162cfe60390STomohiro Kusumi 	if (nb == 0) {
163cfe60390STomohiro Kusumi 		EXT2_LOCK(ump);
164cfe60390STomohiro Kusumi 		pref = ext2_blkpref(ip, lbn, indirs[0].in_off +
165cfe60390STomohiro Kusumi 		    EXT2_NDIR_BLOCKS, &ip->i_db[0], 0);
166cfe60390STomohiro Kusumi 		if ((error = ext2_alloc(ip, lbn, pref, fs->e2fs_bsize, cred,
167cfe60390STomohiro Kusumi 		    &newb)))
168cfe60390STomohiro Kusumi 			return (error);
169cfe60390STomohiro Kusumi 		if (newb > UINT_MAX)
170cfe60390STomohiro Kusumi 			return (EFBIG);
171cfe60390STomohiro Kusumi 		nb = newb;
172cfe60390STomohiro Kusumi 		bp = getblk(vp, lblktodoff(fs, indirs[1].in_lbn),
173cfe60390STomohiro Kusumi 		    fs->e2fs_bsize, 0, 0);
174cfe60390STomohiro Kusumi 		bp->b_bio2.bio_offset = fsbtodoff(fs, newb);
175cfe60390STomohiro Kusumi 		vfs_bio_clrbuf(bp);
176cfe60390STomohiro Kusumi 		/*
177cfe60390STomohiro Kusumi 		 * Write synchronously so that indirect blocks
178cfe60390STomohiro Kusumi 		 * never point at garbage.
179cfe60390STomohiro Kusumi 		 */
180cfe60390STomohiro Kusumi 		if ((error = bwrite(bp)) != 0) {
181cfe60390STomohiro Kusumi 			ext2_blkfree(ip, nb, fs->e2fs_bsize);
182cfe60390STomohiro Kusumi 			return (error);
183cfe60390STomohiro Kusumi 		}
184cfe60390STomohiro Kusumi 		ip->i_ib[indirs[0].in_off] = newb;
185cfe60390STomohiro Kusumi 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
186cfe60390STomohiro Kusumi 	}
187cfe60390STomohiro Kusumi 	/*
188cfe60390STomohiro Kusumi 	 * Fetch through the indirect blocks, allocating as necessary.
189cfe60390STomohiro Kusumi 	 */
190cfe60390STomohiro Kusumi 	for (i = 1;;) {
191*e5b38eb5STomohiro Kusumi 		error = bread(vp, lblktodoff(fs, indirs[i].in_lbn),
192*e5b38eb5STomohiro Kusumi 		    (int)fs->e2fs_bsize, &bp);
193cfe60390STomohiro Kusumi 		if (error) {
194*e5b38eb5STomohiro Kusumi 			brelse(bp);
195cfe60390STomohiro Kusumi 			return (error);
196cfe60390STomohiro Kusumi 		}
197cfe60390STomohiro Kusumi 		bap = (e2fs_daddr_t *)bp->b_data;
198cfe60390STomohiro Kusumi 		nb = le32toh(bap[indirs[i].in_off]);
199cfe60390STomohiro Kusumi 		if (i == num)
200cfe60390STomohiro Kusumi 			break;
201cfe60390STomohiro Kusumi 		i += 1;
202cfe60390STomohiro Kusumi 		if (nb != 0) {
203*e5b38eb5STomohiro Kusumi 			bqrelse(bp);
204cfe60390STomohiro Kusumi 			continue;
205cfe60390STomohiro Kusumi 		}
206cfe60390STomohiro Kusumi 		EXT2_LOCK(ump);
207cfe60390STomohiro Kusumi 		if (pref == 0)
208cfe60390STomohiro Kusumi 			pref = ext2_blkpref(ip, lbn, indirs[i].in_off, bap,
209cfe60390STomohiro Kusumi 			    lblkno(fs, bp->b_loffset));
210cfe60390STomohiro Kusumi 		error = ext2_alloc(ip, lbn, pref, (int)fs->e2fs_bsize, cred, &newb);
211cfe60390STomohiro Kusumi 		if (error) {
212*e5b38eb5STomohiro Kusumi 			brelse(bp);
213cfe60390STomohiro Kusumi 			return (error);
214cfe60390STomohiro Kusumi 		}
215f9507b19STomohiro Kusumi 		if (newb > UINT_MAX) {
216*e5b38eb5STomohiro Kusumi 			brelse(bp);
217cfe60390STomohiro Kusumi 			return (EFBIG);
218f9507b19STomohiro Kusumi 		}
219cfe60390STomohiro Kusumi 		nb = newb;
220cfe60390STomohiro Kusumi 		nbp = getblk(vp, lblktodoff(fs, indirs[i].in_lbn),
221cfe60390STomohiro Kusumi 		    fs->e2fs_bsize, 0, 0);
222cfe60390STomohiro Kusumi 		nbp->b_bio2.bio_offset = fsbtodoff(fs, nb);
223cfe60390STomohiro Kusumi 		vfs_bio_clrbuf(nbp);
224cfe60390STomohiro Kusumi 		/*
225cfe60390STomohiro Kusumi 		 * Write synchronously so that indirect blocks
226cfe60390STomohiro Kusumi 		 * never point at garbage.
227cfe60390STomohiro Kusumi 		 */
228cfe60390STomohiro Kusumi 		if ((error = bwrite(nbp)) != 0) {
229cfe60390STomohiro Kusumi 			ext2_blkfree(ip, nb, fs->e2fs_bsize);
230*e5b38eb5STomohiro Kusumi 			brelse(bp);
231cfe60390STomohiro Kusumi 			return (error);
232cfe60390STomohiro Kusumi 		}
233cfe60390STomohiro Kusumi 		bap[indirs[i - 1].in_off] = htole32(nb);
234cfe60390STomohiro Kusumi 		/*
235cfe60390STomohiro Kusumi 		 * If required, write synchronously, otherwise use
236cfe60390STomohiro Kusumi 		 * delayed write.
237cfe60390STomohiro Kusumi 		 */
238cfe60390STomohiro Kusumi 		if (flags & IO_SYNC) {
239cfe60390STomohiro Kusumi 			bwrite(bp);
240cfe60390STomohiro Kusumi 		} else {
241cfe60390STomohiro Kusumi 			if (bp->b_bufsize == fs->e2fs_bsize)
242cfe60390STomohiro Kusumi 				bp->b_flags |= B_CLUSTEROK;
243cfe60390STomohiro Kusumi 			bdwrite(bp);
244cfe60390STomohiro Kusumi 		}
245cfe60390STomohiro Kusumi 	}
246cfe60390STomohiro Kusumi 	/*
247cfe60390STomohiro Kusumi 	 * Get the data block, allocating if necessary.
248cfe60390STomohiro Kusumi 	 */
249cfe60390STomohiro Kusumi 	if (nb == 0) {
250cfe60390STomohiro Kusumi 		EXT2_LOCK(ump);
251cfe60390STomohiro Kusumi 		pref = ext2_blkpref(ip, lbn, indirs[i].in_off, &bap[0],
252cfe60390STomohiro Kusumi 		    lblkno(fs, bp->b_loffset));
253cfe60390STomohiro Kusumi 		if ((error = ext2_alloc(ip,
254cfe60390STomohiro Kusumi 		    lbn, pref, (int)fs->e2fs_bsize, cred, &newb)) != 0) {
255*e5b38eb5STomohiro Kusumi 			brelse(bp);
256cfe60390STomohiro Kusumi 			return (error);
257cfe60390STomohiro Kusumi 		}
258f9507b19STomohiro Kusumi 		if (newb > UINT_MAX) {
259*e5b38eb5STomohiro Kusumi 			brelse(bp);
260cfe60390STomohiro Kusumi 			return (EFBIG);
261f9507b19STomohiro Kusumi 		}
262cfe60390STomohiro Kusumi 		nb = newb;
263cfe60390STomohiro Kusumi 		nbp = getblk(vp, lblktodoff(fs, lbn), fs->e2fs_bsize, 0, 0);
264cfe60390STomohiro Kusumi 		nbp->b_bio2.bio_offset = fsbtodoff(fs, nb);
265cfe60390STomohiro Kusumi 		if (flags & BA_CLRBUF)
266cfe60390STomohiro Kusumi 			vfs_bio_clrbuf(nbp);
267cfe60390STomohiro Kusumi 		bap[indirs[i].in_off] = htole32(nb);
268cfe60390STomohiro Kusumi 		/*
269cfe60390STomohiro Kusumi 		 * If required, write synchronously, otherwise use
270cfe60390STomohiro Kusumi 		 * delayed write.
271cfe60390STomohiro Kusumi 		 */
272cfe60390STomohiro Kusumi 		if (flags & IO_SYNC) {
273cfe60390STomohiro Kusumi 			bwrite(bp);
274cfe60390STomohiro Kusumi 		} else {
275cfe60390STomohiro Kusumi 			if (bp->b_bufsize == fs->e2fs_bsize)
276cfe60390STomohiro Kusumi 				bp->b_flags |= B_CLUSTEROK;
277cfe60390STomohiro Kusumi 			bdwrite(bp);
278cfe60390STomohiro Kusumi 		}
279cfe60390STomohiro Kusumi 		*bpp = nbp;
280cfe60390STomohiro Kusumi 		return (0);
281cfe60390STomohiro Kusumi 	}
282*e5b38eb5STomohiro Kusumi 	brelse(bp);
283cfe60390STomohiro Kusumi 	if (flags & BA_CLRBUF) {
284cfe60390STomohiro Kusumi 		int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT;
285cfe60390STomohiro Kusumi 
286cfe60390STomohiro Kusumi 		if (seqcount && (vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
287*e5b38eb5STomohiro Kusumi 			error = cluster_read(vp, ip->i_size,
288cfe60390STomohiro Kusumi 			    lblktodoff(fs, lbn), (int)fs->e2fs_bsize,
289cfe60390STomohiro Kusumi 			    MAXBSIZE, (size_t)seqcount, &nbp);
290cfe60390STomohiro Kusumi 		} else {
291*e5b38eb5STomohiro Kusumi 			error = bread(vp, lblktodoff(fs, lbn),
292cfe60390STomohiro Kusumi 			    (int)fs->e2fs_bsize, &nbp);
293cfe60390STomohiro Kusumi 		}
294cfe60390STomohiro Kusumi 		if (error) {
295*e5b38eb5STomohiro Kusumi 			brelse(nbp);
296cfe60390STomohiro Kusumi 			return (error);
297cfe60390STomohiro Kusumi 		}
298cfe60390STomohiro Kusumi 	} else {
299cfe60390STomohiro Kusumi 		nbp = getblk(vp, lblktodoff(fs, lbn), fs->e2fs_bsize, 0, 0);
300cfe60390STomohiro Kusumi 		nbp->b_bio2.bio_offset = fsbtodoff(fs, nb);
301cfe60390STomohiro Kusumi 	}
302cfe60390STomohiro Kusumi 	*bpp = nbp;
303cfe60390STomohiro Kusumi 	return (0);
304cfe60390STomohiro Kusumi }
305