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