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