]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/ext2fs/ext2_balloc.c
Merge OpenSSL 1.0.2n.
[FreeBSD/FreeBSD.git] / sys / fs / ext2fs / ext2_balloc.c
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/lock.h>
46 #include <sys/mount.h>
47 #include <sys/vnode.h>
48
49 #include <fs/ext2fs/fs.h>
50 #include <fs/ext2fs/inode.h>
51 #include <fs/ext2fs/ext2fs.h>
52 #include <fs/ext2fs/ext2_dinode.h>
53 #include <fs/ext2fs/ext2_extern.h>
54 #include <fs/ext2fs/ext2_mount.h>
55
56 static int
57 ext2_ext_balloc(struct inode *ip, uint32_t lbn, int size,
58     struct ucred *cred, struct buf **bpp, int flags)
59 {
60         struct m_ext2fs *fs;
61         struct buf *bp = NULL;
62         struct vnode *vp = ITOV(ip);
63         uint32_t nb;
64         int osize, nsize, blks, error, allocated;
65
66         fs = ip->i_e2fs;
67         blks = howmany(size, fs->e2fs_bsize);
68
69         error = ext4_ext_get_blocks(ip, lbn, blks, cred, NULL, &allocated, &nb);
70         if (error)
71                 return (error);
72
73         if (allocated) {
74                 if (ip->i_size < (lbn + 1) * fs->e2fs_bsize)
75                         nsize = fragroundup(fs, size);
76                 else
77                         nsize = fs->e2fs_bsize;
78
79                 bp = getblk(vp, lbn, nsize, 0, 0, 0);
80                 if(!bp)
81                         return (EIO);
82
83                 bp->b_blkno = fsbtodb(fs, nb);
84                 if (flags & BA_CLRBUF)
85                         vfs_bio_clrbuf(bp);
86         } else {
87                 if (ip->i_size >= (lbn + 1) * fs->e2fs_bsize) {
88
89                         error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp);
90                         if (error) {
91                                 brelse(bp);
92                                 return (error);
93                         }
94                         bp->b_blkno = fsbtodb(fs, nb);
95                         *bpp = bp;
96                         return (0);
97                 }
98
99                 /*
100                  * Consider need to reallocate a fragment.
101                  */
102                 osize = fragroundup(fs, blkoff(fs, ip->i_size));
103                 nsize = fragroundup(fs, size);
104                 if (nsize <= osize) {
105                         error = bread(vp, lbn, osize, NOCRED, &bp);
106                         if (error) {
107                                 brelse(bp);
108                                 return (error);
109                         }
110                         bp->b_blkno = fsbtodb(fs, nb);
111                 } else {
112                         error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp);
113                         if (error) {
114                                 brelse(bp);
115                                 return (error);
116                         }
117                         bp->b_blkno = fsbtodb(fs, nb);
118                 }
119         }
120
121         *bpp = bp;
122
123         return (error);
124 }
125
126 /*
127  * Balloc defines the structure of filesystem storage
128  * by allocating the physical blocks on a device given
129  * the inode and the logical block number in a file.
130  */
131 int
132 ext2_balloc(struct inode *ip, e2fs_lbn_t lbn, int size, struct ucred *cred,
133     struct buf **bpp, int flags)
134 {
135         struct m_ext2fs *fs;
136         struct ext2mount *ump;
137         struct buf *bp, *nbp;
138         struct vnode *vp = ITOV(ip);
139         struct indir indirs[EXT2_NIADDR + 2];
140         e4fs_daddr_t nb, newb;
141         e2fs_daddr_t *bap, pref;
142         int osize, nsize, num, i, error;
143
144         *bpp = NULL;
145         if (lbn < 0)
146                 return (EFBIG);
147         fs = ip->i_e2fs;
148         ump = ip->i_ump;
149
150         /*
151          * check if this is a sequential block allocation.
152          * If so, increment next_alloc fields to allow ext2_blkpref
153          * to make a good guess
154          */
155         if (lbn == ip->i_next_alloc_block + 1) {
156                 ip->i_next_alloc_block++;
157                 ip->i_next_alloc_goal++;
158         }
159
160         if (ip->i_flag & IN_E4EXTENTS)
161                 return (ext2_ext_balloc(ip, lbn, size, cred, bpp, flags));
162
163         /*
164          * The first EXT2_NDADDR blocks are direct blocks
165          */
166         if (lbn < EXT2_NDADDR) {
167                 nb = ip->i_db[lbn];
168                 /*
169                  * no new block is to be allocated, and no need to expand
170                  * the file
171                  */
172                 if (nb != 0 && ip->i_size >= (lbn + 1) * fs->e2fs_bsize) {
173                         error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp);
174                         if (error) {
175                                 brelse(bp);
176                                 return (error);
177                         }
178                         bp->b_blkno = fsbtodb(fs, nb);
179                         *bpp = bp;
180                         return (0);
181                 }
182                 if (nb != 0) {
183                         /*
184                          * Consider need to reallocate a fragment.
185                          */
186                         osize = fragroundup(fs, blkoff(fs, ip->i_size));
187                         nsize = fragroundup(fs, size);
188                         if (nsize <= osize) {
189                                 error = bread(vp, lbn, osize, NOCRED, &bp);
190                                 if (error) {
191                                         brelse(bp);
192                                         return (error);
193                                 }
194                                 bp->b_blkno = fsbtodb(fs, nb);
195                         } else {
196                                 /*
197                                  * Godmar thinks: this shouldn't happen w/o
198                                  * fragments
199                                  */
200                                 printf("nsize %d(%d) > osize %d(%d) nb %d\n",
201                                     (int)nsize, (int)size, (int)osize,
202                                     (int)ip->i_size, (int)nb);
203                                 panic(
204                                     "ext2_balloc: Something is terribly wrong");
205 /*
206  * please note there haven't been any changes from here on -
207  * FFS seems to work.
208  */
209                         }
210                 } else {
211                         if (ip->i_size < (lbn + 1) * fs->e2fs_bsize)
212                                 nsize = fragroundup(fs, size);
213                         else
214                                 nsize = fs->e2fs_bsize;
215                         EXT2_LOCK(ump);
216                         error = ext2_alloc(ip, lbn,
217                             ext2_blkpref(ip, lbn, (int)lbn, &ip->i_db[0], 0),
218                             nsize, cred, &newb);
219                         if (error)
220                                 return (error);
221                         bp = getblk(vp, lbn, nsize, 0, 0, 0);
222                         bp->b_blkno = fsbtodb(fs, newb);
223                         if (flags & BA_CLRBUF)
224                                 vfs_bio_clrbuf(bp);
225                 }
226                 ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno);
227                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
228                 *bpp = bp;
229                 return (0);
230         }
231         /*
232          * Determine the number of levels of indirection.
233          */
234         pref = 0;
235         if ((error = ext2_getlbns(vp, lbn, indirs, &num)) != 0)
236                 return (error);
237 #ifdef INVARIANTS
238         if (num < 1)
239                 panic("ext2_balloc: ext2_getlbns returned indirect block");
240 #endif
241         /*
242          * Fetch the first indirect block allocating if necessary.
243          */
244         --num;
245         nb = ip->i_ib[indirs[0].in_off];
246         if (nb == 0) {
247                 EXT2_LOCK(ump);
248                 pref = ext2_blkpref(ip, lbn, indirs[0].in_off +
249                     EXT2_NDIR_BLOCKS, &ip->i_db[0], 0);
250                 if ((error = ext2_alloc(ip, lbn, pref, fs->e2fs_bsize, cred,
251                     &newb)))
252                         return (error);
253                 nb = newb;
254                 bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0, 0);
255                 bp->b_blkno = fsbtodb(fs, newb);
256                 vfs_bio_clrbuf(bp);
257                 /*
258                  * Write synchronously so that indirect blocks
259                  * never point at garbage.
260                  */
261                 if ((error = bwrite(bp)) != 0) {
262                         ext2_blkfree(ip, nb, fs->e2fs_bsize);
263                         return (error);
264                 }
265                 ip->i_ib[indirs[0].in_off] = newb;
266                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
267         }
268         /*
269          * Fetch through the indirect blocks, allocating as necessary.
270          */
271         for (i = 1;;) {
272                 error = bread(vp,
273                     indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp);
274                 if (error) {
275                         brelse(bp);
276                         return (error);
277                 }
278                 bap = (e2fs_daddr_t *)bp->b_data;
279                 nb = bap[indirs[i].in_off];
280                 if (i == num)
281                         break;
282                 i += 1;
283                 if (nb != 0) {
284                         bqrelse(bp);
285                         continue;
286                 }
287                 EXT2_LOCK(ump);
288                 if (pref == 0)
289                         pref = ext2_blkpref(ip, lbn, indirs[i].in_off, bap,
290                             bp->b_lblkno);
291                 error = ext2_alloc(ip, lbn, pref, (int)fs->e2fs_bsize, cred, &newb);
292                 if (error) {
293                         brelse(bp);
294                         return (error);
295                 }
296                 nb = newb;
297                 nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0, 0);
298                 nbp->b_blkno = fsbtodb(fs, nb);
299                 vfs_bio_clrbuf(nbp);
300                 /*
301                  * Write synchronously so that indirect blocks
302                  * never point at garbage.
303                  */
304                 if ((error = bwrite(nbp)) != 0) {
305                         ext2_blkfree(ip, nb, fs->e2fs_bsize);
306                         EXT2_UNLOCK(ump);
307                         brelse(bp);
308                         return (error);
309                 }
310                 bap[indirs[i - 1].in_off] = nb;
311                 /*
312                  * If required, write synchronously, otherwise use
313                  * delayed write.
314                  */
315                 if (flags & IO_SYNC) {
316                         bwrite(bp);
317                 } else {
318                         if (bp->b_bufsize == fs->e2fs_bsize)
319                                 bp->b_flags |= B_CLUSTEROK;
320                         bdwrite(bp);
321                 }
322         }
323         /*
324          * Get the data block, allocating if necessary.
325          */
326         if (nb == 0) {
327                 EXT2_LOCK(ump);
328                 pref = ext2_blkpref(ip, lbn, indirs[i].in_off, &bap[0],
329                     bp->b_lblkno);
330                 if ((error = ext2_alloc(ip,
331                     lbn, pref, (int)fs->e2fs_bsize, cred, &newb)) != 0) {
332                         brelse(bp);
333                         return (error);
334                 }
335                 nb = newb;
336                 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0);
337                 nbp->b_blkno = fsbtodb(fs, nb);
338                 if (flags & BA_CLRBUF)
339                         vfs_bio_clrbuf(nbp);
340                 bap[indirs[i].in_off] = nb;
341                 /*
342                  * If required, write synchronously, otherwise use
343                  * delayed write.
344                  */
345                 if (flags & IO_SYNC) {
346                         bwrite(bp);
347                 } else {
348                         if (bp->b_bufsize == fs->e2fs_bsize)
349                                 bp->b_flags |= B_CLUSTEROK;
350                         bdwrite(bp);
351                 }
352                 *bpp = nbp;
353                 return (0);
354         }
355         brelse(bp);
356         if (flags & BA_CLRBUF) {
357                 int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT;
358
359                 if (seqcount && (vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
360                         error = cluster_read(vp, ip->i_size, lbn,
361                             (int)fs->e2fs_bsize, NOCRED,
362                             MAXBSIZE, seqcount, 0, &nbp);
363                 } else {
364                         error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, &nbp);
365                 }
366                 if (error) {
367                         brelse(nbp);
368                         return (error);
369                 }
370         } else {
371                 nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0);
372                 nbp->b_blkno = fsbtodb(fs, nb);
373         }
374         *bpp = nbp;
375         return (0);
376 }