Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/fs/ext2fs/ext2_balloc.c
39483 views
1
/*-
2
* modified for Lites 1.1
3
*
4
* Aug 1995, Godmar Back ([email protected])
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
38
#include <sys/param.h>
39
#include <sys/systm.h>
40
#include <sys/endian.h>
41
#include <sys/bio.h>
42
#include <sys/buf.h>
43
#include <sys/limits.h>
44
#include <sys/lock.h>
45
#include <sys/mount.h>
46
#include <sys/vnode.h>
47
48
#include <fs/ext2fs/fs.h>
49
#include <fs/ext2fs/inode.h>
50
#include <fs/ext2fs/ext2fs.h>
51
#include <fs/ext2fs/ext2_dinode.h>
52
#include <fs/ext2fs/ext2_extern.h>
53
#include <fs/ext2fs/ext2_mount.h>
54
55
static int
56
ext2_ext_balloc(struct inode *ip, uint32_t lbn, int size,
57
struct ucred *cred, struct buf **bpp, int flags)
58
{
59
struct m_ext2fs *fs;
60
struct buf *bp = NULL;
61
struct vnode *vp = ITOV(ip);
62
daddr_t newblk;
63
int blks, error, allocated;
64
65
fs = ip->i_e2fs;
66
blks = howmany(size, fs->e2fs_bsize);
67
68
error = ext4_ext_get_blocks(ip, lbn, blks, cred, NULL, &allocated, &newblk);
69
if (error)
70
return (error);
71
72
if (allocated) {
73
bp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0);
74
if(!bp)
75
return (EIO);
76
} else {
77
error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp);
78
if (error) {
79
return (error);
80
}
81
}
82
83
bp->b_blkno = fsbtodb(fs, newblk);
84
if (flags & BA_CLRBUF)
85
vfs_bio_clrbuf(bp);
86
87
*bpp = bp;
88
89
return (error);
90
}
91
92
/*
93
* Balloc defines the structure of filesystem storage
94
* by allocating the physical blocks on a device given
95
* the inode and the logical block number in a file.
96
*/
97
int
98
ext2_balloc(struct inode *ip, e2fs_lbn_t lbn, int size, struct ucred *cred,
99
struct buf **bpp, int flags)
100
{
101
struct m_ext2fs *fs;
102
struct ext2mount *ump;
103
struct buf *bp, *nbp;
104
struct vnode *vp = ITOV(ip);
105
struct indir indirs[EXT2_NIADDR + 2];
106
e4fs_daddr_t nb, newb;
107
e2fs_daddr_t *bap, pref;
108
int num, i, error;
109
110
*bpp = NULL;
111
if (lbn < 0)
112
return (EFBIG);
113
fs = ip->i_e2fs;
114
ump = ip->i_ump;
115
116
/*
117
* check if this is a sequential block allocation.
118
* If so, increment next_alloc fields to allow ext2_blkpref
119
* to make a good guess
120
*/
121
if (lbn == ip->i_next_alloc_block + 1) {
122
ip->i_next_alloc_block++;
123
ip->i_next_alloc_goal++;
124
}
125
126
if (ip->i_flag & IN_E4EXTENTS)
127
return (ext2_ext_balloc(ip, lbn, size, cred, bpp, flags));
128
129
/*
130
* The first EXT2_NDADDR blocks are direct blocks
131
*/
132
if (lbn < EXT2_NDADDR) {
133
nb = ip->i_db[lbn];
134
/*
135
* no new block is to be allocated, and no need to expand
136
* the file
137
*/
138
if (nb != 0) {
139
error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp);
140
if (error) {
141
return (error);
142
}
143
bp->b_blkno = fsbtodb(fs, nb);
144
if (ip->i_size >= (lbn + 1) * fs->e2fs_bsize) {
145
*bpp = bp;
146
return (0);
147
}
148
} else {
149
EXT2_LOCK(ump);
150
error = ext2_alloc(ip, lbn,
151
ext2_blkpref(ip, lbn, (int)lbn, &ip->i_db[0], 0),
152
fs->e2fs_bsize, cred, &newb);
153
if (error)
154
return (error);
155
/*
156
* If the newly allocated block exceeds 32-bit limit,
157
* we can not use it in file block maps.
158
*/
159
if (newb > UINT_MAX)
160
return (EFBIG);
161
bp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0);
162
bp->b_blkno = fsbtodb(fs, newb);
163
if (flags & BA_CLRBUF)
164
vfs_bio_clrbuf(bp);
165
}
166
ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno);
167
ip->i_flag |= IN_CHANGE | IN_UPDATE;
168
*bpp = bp;
169
return (0);
170
}
171
/*
172
* Determine the number of levels of indirection.
173
*/
174
pref = 0;
175
if ((error = ext2_getlbns(vp, lbn, indirs, &num)) != 0)
176
return (error);
177
#ifdef INVARIANTS
178
if (num < 1)
179
panic("ext2_balloc: ext2_getlbns returned indirect block");
180
#endif
181
/*
182
* Fetch the first indirect block allocating if necessary.
183
*/
184
--num;
185
nb = ip->i_ib[indirs[0].in_off];
186
if (nb == 0) {
187
EXT2_LOCK(ump);
188
pref = ext2_blkpref(ip, lbn, indirs[0].in_off +
189
EXT2_NDIR_BLOCKS, &ip->i_db[0], 0);
190
if ((error = ext2_alloc(ip, lbn, pref, fs->e2fs_bsize, cred,
191
&newb)))
192
return (error);
193
if (newb > UINT_MAX)
194
return (EFBIG);
195
nb = newb;
196
bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0, 0);
197
bp->b_blkno = fsbtodb(fs, newb);
198
vfs_bio_clrbuf(bp);
199
/*
200
* Write synchronously so that indirect blocks
201
* never point at garbage.
202
*/
203
if ((error = bwrite(bp)) != 0) {
204
ext2_blkfree(ip, nb, fs->e2fs_bsize);
205
return (error);
206
}
207
ip->i_ib[indirs[0].in_off] = newb;
208
ip->i_flag |= IN_CHANGE | IN_UPDATE;
209
}
210
/*
211
* Fetch through the indirect blocks, allocating as necessary.
212
*/
213
for (i = 1;;) {
214
error = bread(vp,
215
indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp);
216
if (error) {
217
return (error);
218
}
219
bap = (e2fs_daddr_t *)bp->b_data;
220
nb = le32toh(bap[indirs[i].in_off]);
221
if (i == num)
222
break;
223
i += 1;
224
if (nb != 0) {
225
bqrelse(bp);
226
continue;
227
}
228
EXT2_LOCK(ump);
229
if (pref == 0)
230
pref = ext2_blkpref(ip, lbn, indirs[i].in_off, bap,
231
bp->b_lblkno);
232
error = ext2_alloc(ip, lbn, pref, (int)fs->e2fs_bsize, cred, &newb);
233
if (error) {
234
brelse(bp);
235
return (error);
236
}
237
if (newb > UINT_MAX)
238
return (EFBIG);
239
nb = newb;
240
nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0, 0);
241
nbp->b_blkno = fsbtodb(fs, nb);
242
vfs_bio_clrbuf(nbp);
243
/*
244
* Write synchronously so that indirect blocks
245
* never point at garbage.
246
*/
247
if ((error = bwrite(nbp)) != 0) {
248
ext2_blkfree(ip, nb, fs->e2fs_bsize);
249
brelse(bp);
250
return (error);
251
}
252
bap[indirs[i - 1].in_off] = htole32(nb);
253
/*
254
* If required, write synchronously, otherwise use
255
* delayed write.
256
*/
257
if (flags & IO_SYNC) {
258
bwrite(bp);
259
} else {
260
if (bp->b_bufsize == fs->e2fs_bsize)
261
bp->b_flags |= B_CLUSTEROK;
262
bdwrite(bp);
263
}
264
}
265
/*
266
* Get the data block, allocating if necessary.
267
*/
268
if (nb == 0) {
269
EXT2_LOCK(ump);
270
pref = ext2_blkpref(ip, lbn, indirs[i].in_off, &bap[0],
271
bp->b_lblkno);
272
if ((error = ext2_alloc(ip,
273
lbn, pref, (int)fs->e2fs_bsize, cred, &newb)) != 0) {
274
brelse(bp);
275
return (error);
276
}
277
if (newb > UINT_MAX)
278
return (EFBIG);
279
nb = newb;
280
nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0);
281
nbp->b_blkno = fsbtodb(fs, nb);
282
if (flags & BA_CLRBUF)
283
vfs_bio_clrbuf(nbp);
284
bap[indirs[i].in_off] = htole32(nb);
285
/*
286
* If required, write synchronously, otherwise use
287
* delayed write.
288
*/
289
if (flags & IO_SYNC) {
290
bwrite(bp);
291
} else {
292
if (bp->b_bufsize == fs->e2fs_bsize)
293
bp->b_flags |= B_CLUSTEROK;
294
bdwrite(bp);
295
}
296
*bpp = nbp;
297
return (0);
298
}
299
brelse(bp);
300
if (flags & BA_CLRBUF) {
301
int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT;
302
303
if (seqcount && (vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
304
error = cluster_read(vp, ip->i_size, lbn,
305
(int)fs->e2fs_bsize, NOCRED,
306
MAXBSIZE, seqcount, 0, &nbp);
307
} else {
308
error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, &nbp);
309
}
310
if (error) {
311
brelse(nbp);
312
return (error);
313
}
314
} else {
315
nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0);
316
nbp->b_blkno = fsbtodb(fs, nb);
317
}
318
*bpp = nbp;
319
return (0);
320
}
321
322