2 * modified for Lites 1.1
4 * Aug 1995, Godmar Back (gback@cs.utah.edu)
5 * University of Utah, Department of Computer Science
8 * Copyright (c) 1982, 1986, 1989, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * @(#)ffs_alloc.c 8.8 (Berkeley) 2/21/94
39 #include <sys/param.h>
40 #include <sys/systm.h>
42 #include <sys/vnode.h>
43 #include <sys/signalvar.h>
45 #include <sys/mount.h>
46 #include <sys/syslog.h>
48 #include <gnu/fs/ext2fs/inode.h>
49 #include <gnu/fs/ext2fs/ext2_mount.h>
50 #include <gnu/fs/ext2fs/ext2_fs.h>
51 #include <gnu/fs/ext2fs/ext2_fs_sb.h>
52 #include <gnu/fs/ext2fs/fs.h>
53 #include <gnu/fs/ext2fs/ext2_extern.h>
55 static void ext2_fserr(struct ext2_sb_info *, u_int, char *);
58 * Linux calls this functions at the following locations:
59 * (1) the inode is freed
60 * (2) a preallocation miss occurs
61 * (3) truncate is called
62 * (4) release_file is called and f_mode & 2
64 * I call it in ext2_inactive, ext2_truncate, ext2_vfree and in (2)
65 * the call in vfree might be redundant
68 ext2_discard_prealloc(ip)
71 #ifdef EXT2_PREALLOCATE
72 if (ip->i_prealloc_count) {
73 int i = ip->i_prealloc_count;
74 ip->i_prealloc_count = 0;
75 ext2_free_blocks (ITOV(ip)->v_mount,
83 * Allocate a block in the file system.
85 * this takes the framework from ffs_alloc. To implement the
86 * actual allocation, it calls ext2_new_block, the ported version
87 * of the same Linux routine.
89 * we note that this is always called in connection with ext2_blkpref
91 * preallocation is done as Linux does it
94 ext2_alloc(ip, lbn, bpref, size, cred, bnp)
101 struct ext2_sb_info *fs;
107 if ((u_int)size > fs->s_blocksize || blkoff(fs, size) != 0) {
108 vn_printf(ip->i_devvp, "bsize = %lu, size = %d, fs = %s\n",
109 fs->s_blocksize, size, fs->fs_fsmnt);
110 panic("ext2_alloc: bad size");
113 panic("ext2_alloc: missing credential");
114 #endif /* DIAGNOSTIC */
115 if (size == fs->s_blocksize && fs->s_es->s_free_blocks_count == 0)
117 if (cred->cr_uid != 0 &&
118 fs->s_es->s_free_blocks_count < fs->s_es->s_r_blocks_count)
120 if (bpref >= fs->s_es->s_blocks_count)
122 /* call the Linux code */
123 #ifdef EXT2_PREALLOCATE
124 /* To have a preallocation hit, we must
125 * - have at least one block preallocated
126 * - and our preferred block must have that block number or one below
128 if (ip->i_prealloc_count &&
129 (bpref == ip->i_prealloc_block ||
130 bpref + 1 == ip->i_prealloc_block))
132 bno = ip->i_prealloc_block++;
133 ip->i_prealloc_count--;
134 /* ext2_debug ("preallocation hit (%lu/%lu).\n",
135 ++alloc_hits, ++alloc_attempts); */
137 /* Linux gets, clears, and releases the buffer at this
138 point - we don't have to that; we leave it to the caller
141 ext2_discard_prealloc (ip);
142 /* ext2_debug ("preallocation miss (%lu/%lu).\n",
143 alloc_hits, ++alloc_attempts); */
144 if (S_ISREG(ip->i_mode))
146 (ITOV(ip)->v_mount, bpref,
147 &ip->i_prealloc_count,
148 &ip->i_prealloc_block);
150 bno = (int32_t)ext2_new_block(ITOV(ip)->v_mount,
154 bno = (int32_t)ext2_new_block(ITOV(ip)->v_mount, bpref, 0, 0);
158 /* set next_alloc fields as done in block_getblk */
159 ip->i_next_alloc_block = lbn;
160 ip->i_next_alloc_goal = bno;
162 ip->i_blocks += btodb(size);
163 ip->i_flag |= IN_CHANGE | IN_UPDATE;
168 ext2_fserr(fs, cred->cr_uid, "file system full");
169 uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
174 * Reallocate a sequence of blocks into a contiguous sequence of blocks.
176 * The vnode and an array of buffer pointers for a range of sequential
177 * logical blocks to be made contiguous is given. The allocator attempts
178 * to find a range of sequential blocks starting as close as possible to
179 * an fs_rotdelay offset from the end of the allocation for the logical
180 * block immediately preceding the current range. If successful, the
181 * physical block numbers in the buffer pointers and in the inode are
182 * changed to reflect the new allocation. If unsuccessful, the allocation
183 * is left unchanged. The success in doing the reallocation is returned.
184 * Note that the error return is not reflected back to the user. Rather
185 * the previous block allocation will be used.
189 #include <sys/sysctl.h>
190 static int doasyncfree = 1;
192 SYSCTL_INT(_debug, 14, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, "");
193 #endif /* OPT_DEBUG */
198 struct vop_reallocblks_args /* {
200 struct cluster_save *a_buflist;
203 #ifndef FANCY_REALLOC
204 /* printf("ext2_reallocblks not implemented\n"); */
208 struct ext2_sb_info *fs;
211 struct buf *sbp, *ebp;
212 int32_t *bap, *sbap, *ebap;
213 struct cluster_save *buflist;
214 int32_t start_lbn, end_lbn, soff, eoff, newblk, blkno;
215 struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp;
216 int i, len, start_lvl, end_lvl, pref, ssize;
222 if (fs->fs_contigsumsize <= 0)
225 buflist = ap->a_buflist;
226 len = buflist->bs_nchildren;
227 start_lbn = buflist->bs_children[0]->b_lblkno;
228 end_lbn = start_lbn + len - 1;
230 for (i = 1; i < len; i++)
231 if (buflist->bs_children[i]->b_lblkno != start_lbn + i)
232 panic("ext2_reallocblks: non-cluster");
235 * If the latest allocation is in a new cylinder group, assume that
236 * the filesystem has decided to move and do not force it back to
237 * the previous cylinder group.
239 if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) !=
240 dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno)))
242 if (ufs_getlbns(vp, start_lbn, start_ap, &start_lvl) ||
243 ufs_getlbns(vp, end_lbn, end_ap, &end_lvl))
246 * Get the starting offset and block map for the first block.
248 if (start_lvl == 0) {
252 idp = &start_ap[start_lvl - 1];
253 if (bread(vp, idp->in_lbn, (int)fs->s_blocksize, NOCRED, &sbp)) {
257 sbap = (int32_t *)sbp->b_data;
261 * Find the preferred location for the cluster.
263 pref = ext2_blkpref(ip, start_lbn, soff, sbap);
265 * If the block range spans two block maps, get the second map.
267 if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) {
271 if (start_ap[start_lvl-1].in_lbn == idp->in_lbn)
272 panic("ext2_reallocblk: start == end");
274 ssize = len - (idp->in_off + 1);
275 if (bread(vp, idp->in_lbn, (int)fs->s_blocksize, NOCRED, &ebp))
277 ebap = (int32_t *)ebp->b_data;
280 * Search the block map looking for an allocation of the desired size.
282 if ((newblk = (int32_t)ext2_hashalloc(ip, dtog(fs, pref), (long)pref,
283 len, (u_long (*)())ext2_clusteralloc)) == 0)
286 * We have found a new contiguous block.
288 * First we have to replace the old block pointers with the new
289 * block pointers in the inode and indirect blocks associated
293 for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->s_frags_per_block) {
297 if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap))
298 panic("ext2_reallocblks: alloc mismatch");
303 * Next we must write out the modified inode and indirect blocks.
304 * For strict correctness, the writes should be synchronous since
305 * the old block values may have been written to disk. In practise
306 * they are almost never written, but if we are concerned about
307 * strict correctness, the `doasyncfree' flag should be set to zero.
309 * The test on `doasyncfree' should be changed to test a flag
310 * that shows whether the associated buffers and inodes have
311 * been written. The flag should be set when the cluster is
312 * started and cleared whenever the buffer or inode is flushed.
313 * We can then check below to see if it is set, and do the
314 * synchronous write only when it has been cleared.
316 if (sbap != &ip->i_db[0]) {
322 ip->i_flag |= IN_CHANGE | IN_UPDATE;
332 * Last, free the old blocks and assign the new blocks to the buffers.
334 for (blkno = newblk, i = 0; i < len; i++, blkno += fs->s_frags_per_block) {
335 ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno),
337 buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno);
344 if (sbap != &ip->i_db[0])
348 #endif /* FANCY_REALLOC */
352 * Allocate an inode in the file system.
354 * we leave the actual allocation strategy to the (modified)
355 * ext2_new_inode(), to make sure we get the policies right
358 ext2_valloc(pvp, mode, cred, vpp)
365 struct ext2_sb_info *fs;
373 if (fs->s_es->s_free_inodes_count == 0)
376 /* call the Linux routine - it returns the inode number only */
377 ino = ext2_new_inode(pip, mode);
381 error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp);
383 ext2_vfree(pvp, ino, mode);
389 the question is whether using VGET was such good idea at all -
390 Linux doesn't read the old inode in when it's allocating a
391 new one. I will set at least i_size & i_blocks the zero.
397 /* now we want to make sure that the block pointers are zeroed out */
398 for (i = 0; i < NDADDR; i++)
400 for (i = 0; i < NIADDR; i++)
404 * Set up a new generation number for this inode.
405 * XXX check if this makes sense in ext2
407 if (ip->i_gen == 0 || ++ip->i_gen == 0)
408 ip->i_gen = random() / 2 + 1;
410 printf("ext2_valloc: allocated inode %d\n", ino);
414 ext2_fserr(fs, cred->cr_uid, "out of inodes");
415 uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
420 * Select the desired position for the next block in a file.
422 * we try to mimic what Remy does in inode_getblk/block_getblk
424 * we note: blocknr == 0 means that we're about to allocate either
425 * a direct block or a pointer block at the first level of indirection
426 * (In other words, stuff that will go in i_db[] or i_ib[])
428 * blocknr != 0 means that we're allocating a block that is none
429 * of the above. Then, blocknr tells us the number of the block
430 * that will hold the pointer
433 ext2_blkpref(ip, lbn, indx, bap, blocknr)
442 /* if the next block is actually what we thought it is,
443 then set the goal to what we thought it should be
445 if(ip->i_next_alloc_block == lbn)
446 return ip->i_next_alloc_goal;
448 /* now check whether we were provided with an array that basically
449 tells us previous blocks to which we want to stay closeby
452 for (tmp = indx - 1; tmp >= 0; tmp--)
456 /* else let's fall back to the blocknr, or, if there is none,
457 follow the rule that a block should be allocated near its inode
459 return blocknr ? blocknr :
460 (int32_t)(ip->i_block_group *
461 EXT2_BLOCKS_PER_GROUP(ip->i_e2fs)) +
462 ip->i_e2fs->s_es->s_first_data_block;
466 * Free a block or fragment.
468 * pass on to the Linux code
471 ext2_blkfree(ip, bno, size)
476 struct ext2_sb_info *fs;
480 * call Linux code with mount *, block number, count
482 ext2_free_blocks(ITOV(ip)->v_mount, bno, size / fs->s_frag_size);
488 * the maintenance of the actual bitmaps is again up to the linux code
491 ext2_vfree(pvp, ino, mode)
496 struct ext2_sb_info *fs;
502 if ((u_int)ino > fs->s_inodes_per_group * fs->s_groups_count)
503 panic("ext2_vfree: range: devvp = %p, ino = %d, fs = %s",
504 pip->i_devvp, ino, fs->fs_fsmnt);
506 /* ext2_debug("ext2_vfree (%d, %d) called\n", pip->i_number, mode);
508 ext2_discard_prealloc(pip);
510 /* we need to make sure that ext2_free_inode can adjust the
511 used_dir_counts in the group summary information - I'd
512 really like to know what the rationale behind this
513 'set i_mode to zero to denote an unused inode' is
515 save_i_mode = pip->i_mode;
517 ext2_free_inode(pip);
518 pip->i_mode = save_i_mode;
523 * Fserr prints the name of a file system with an error diagnostic.
525 * The form of the error message is:
529 ext2_fserr(fs, uid, cp)
530 struct ext2_sb_info *fs;
535 log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->fs_fsmnt, cp);