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 * Copyright (c) 1982, 1986, 1989, 1993 9 * The Regents of the University of California. All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 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 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#)ext2_alloc.c 8.8 (Berkeley) 2/21/94
| 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 * Copyright (c) 1982, 1986, 1989, 1993 9 * The Regents of the University of California. All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 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 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#)ext2_alloc.c 8.8 (Berkeley) 2/21/94
|
41 */ 42 43#include "opt_quota.h" 44 45#include <sys/param.h> 46#include <sys/systm.h> 47#include <sys/conf.h> 48#include <sys/vnode.h> 49#include <sys/stat.h> 50#include <sys/mount.h> 51#include <sys/syslog.h> 52 53#include <ufs/ufs/extattr.h> 54#include <ufs/ufs/quota.h> 55#include <ufs/ufs/inode.h> 56#include <ufs/ufs/ufsmount.h> 57 58#include <gnu/ext2fs/ext2_fs.h> 59#include <gnu/ext2fs/ext2_fs_sb.h> 60#include <gnu/ext2fs/fs.h> 61#include <gnu/ext2fs/ext2_extern.h> 62 63static void ext2_fserr __P((struct ext2_sb_info *, u_int, char *)); 64 65/* 66 * Linux calls this functions at the following locations: 67 * (1) the inode is freed 68 * (2) a preallocation miss occurs 69 * (3) truncate is called 70 * (4) release_file is called and f_mode & 2 71 * 72 * I call it in ext2_inactive, ext2_truncate, ext2_vfree and in (2) 73 * the call in vfree might be redundant 74 */ 75void 76ext2_discard_prealloc(ip) 77 struct inode * ip; 78{ 79#ifdef EXT2_PREALLOCATE 80 if (ip->i_prealloc_count) { 81 int i = ip->i_prealloc_count; 82 ip->i_prealloc_count = 0; 83 ext2_free_blocks (ITOV(ip)->v_mount, 84 ip->i_prealloc_block, 85 i); 86 } 87#endif 88} 89 90/* 91 * Allocate a block in the file system. 92 * 93 * this takes the framework from ffs_alloc. To implement the 94 * actual allocation, it calls ext2_new_block, the ported version 95 * of the same Linux routine. 96 * 97 * we note that this is always called in connection with ext2_blkpref 98 * 99 * preallocation is done as Linux does it 100 */ 101int 102ext2_alloc(ip, lbn, bpref, size, cred, bnp) 103 register struct inode *ip; 104 daddr_t lbn, bpref; 105 int size; 106 struct ucred *cred; 107 daddr_t *bnp; 108{ 109 register struct ext2_sb_info *fs; 110 daddr_t bno; 111#if QUOTA 112 int error; 113#endif 114 115 *bnp = 0; 116 fs = ip->i_e2fs; 117#if DIAGNOSTIC 118 if ((u_int)size > fs->s_blocksize || blkoff(fs, size) != 0) { 119 printf("dev = %s, bsize = %lu, size = %d, fs = %s\n", 120 devtoname(ip->i_dev), fs->s_blocksize, size, fs->fs_fsmnt); 121 panic("ext2_alloc: bad size"); 122 } 123 if (cred == NOCRED) 124 panic("ext2_alloc: missing credential"); 125#endif /* DIAGNOSTIC */ 126 if (size == fs->s_blocksize && fs->s_es->s_free_blocks_count == 0) 127 goto nospace; 128 if (cred->cr_uid != 0 && 129 fs->s_es->s_free_blocks_count < fs->s_es->s_r_blocks_count) 130 goto nospace; 131#if QUOTA 132 if ((error = chkdq(ip, (long)btodb(size), cred, 0)) != 0) 133 return (error); 134#endif 135 if (bpref >= fs->s_es->s_blocks_count) 136 bpref = 0; 137 /* call the Linux code */ 138#ifdef EXT2_PREALLOCATE 139 /* To have a preallocation hit, we must 140 * - have at least one block preallocated 141 * - and our preferred block must have that block number or one below 142 */ 143 if (ip->i_prealloc_count && 144 (bpref == ip->i_prealloc_block || 145 bpref + 1 == ip->i_prealloc_block)) 146 { 147 bno = ip->i_prealloc_block++; 148 ip->i_prealloc_count--; 149 /* ext2_debug ("preallocation hit (%lu/%lu).\n", 150 ++alloc_hits, ++alloc_attempts); */ 151 152 /* Linux gets, clears, and releases the buffer at this 153 point - we don't have to that; we leave it to the caller 154 */ 155 } else { 156 ext2_discard_prealloc (ip); 157 /* ext2_debug ("preallocation miss (%lu/%lu).\n", 158 alloc_hits, ++alloc_attempts); */ 159 if (S_ISREG(ip->i_mode)) 160 bno = ext2_new_block 161 (ITOV(ip)->v_mount, bpref, 162 &ip->i_prealloc_count, 163 &ip->i_prealloc_block); 164 else 165 bno = (daddr_t)ext2_new_block(ITOV(ip)->v_mount, 166 bpref, 0, 0); 167 } 168#else 169 bno = (daddr_t)ext2_new_block(ITOV(ip)->v_mount, bpref, 0, 0); 170#endif 171 172 if (bno > 0) { 173 /* set next_alloc fields as done in block_getblk */ 174 ip->i_next_alloc_block = lbn; 175 ip->i_next_alloc_goal = bno; 176 177 ip->i_blocks += btodb(size); 178 ip->i_flag |= IN_CHANGE | IN_UPDATE; 179 *bnp = bno; 180 return (0); 181 } 182#if QUOTA 183 /* 184 * Restore user's disk quota because allocation failed. 185 */ 186 (void) chkdq(ip, (long)-btodb(size), cred, FORCE); 187#endif 188nospace: 189 ext2_fserr(fs, cred->cr_uid, "file system full"); 190 uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 191 return (ENOSPC); 192} 193 194/* 195 * Reallocate a sequence of blocks into a contiguous sequence of blocks. 196 * 197 * The vnode and an array of buffer pointers for a range of sequential 198 * logical blocks to be made contiguous is given. The allocator attempts 199 * to find a range of sequential blocks starting as close as possible to 200 * an fs_rotdelay offset from the end of the allocation for the logical
| 41 */ 42 43#include "opt_quota.h" 44 45#include <sys/param.h> 46#include <sys/systm.h> 47#include <sys/conf.h> 48#include <sys/vnode.h> 49#include <sys/stat.h> 50#include <sys/mount.h> 51#include <sys/syslog.h> 52 53#include <ufs/ufs/extattr.h> 54#include <ufs/ufs/quota.h> 55#include <ufs/ufs/inode.h> 56#include <ufs/ufs/ufsmount.h> 57 58#include <gnu/ext2fs/ext2_fs.h> 59#include <gnu/ext2fs/ext2_fs_sb.h> 60#include <gnu/ext2fs/fs.h> 61#include <gnu/ext2fs/ext2_extern.h> 62 63static void ext2_fserr __P((struct ext2_sb_info *, u_int, char *)); 64 65/* 66 * Linux calls this functions at the following locations: 67 * (1) the inode is freed 68 * (2) a preallocation miss occurs 69 * (3) truncate is called 70 * (4) release_file is called and f_mode & 2 71 * 72 * I call it in ext2_inactive, ext2_truncate, ext2_vfree and in (2) 73 * the call in vfree might be redundant 74 */ 75void 76ext2_discard_prealloc(ip) 77 struct inode * ip; 78{ 79#ifdef EXT2_PREALLOCATE 80 if (ip->i_prealloc_count) { 81 int i = ip->i_prealloc_count; 82 ip->i_prealloc_count = 0; 83 ext2_free_blocks (ITOV(ip)->v_mount, 84 ip->i_prealloc_block, 85 i); 86 } 87#endif 88} 89 90/* 91 * Allocate a block in the file system. 92 * 93 * this takes the framework from ffs_alloc. To implement the 94 * actual allocation, it calls ext2_new_block, the ported version 95 * of the same Linux routine. 96 * 97 * we note that this is always called in connection with ext2_blkpref 98 * 99 * preallocation is done as Linux does it 100 */ 101int 102ext2_alloc(ip, lbn, bpref, size, cred, bnp) 103 register struct inode *ip; 104 daddr_t lbn, bpref; 105 int size; 106 struct ucred *cred; 107 daddr_t *bnp; 108{ 109 register struct ext2_sb_info *fs; 110 daddr_t bno; 111#if QUOTA 112 int error; 113#endif 114 115 *bnp = 0; 116 fs = ip->i_e2fs; 117#if DIAGNOSTIC 118 if ((u_int)size > fs->s_blocksize || blkoff(fs, size) != 0) { 119 printf("dev = %s, bsize = %lu, size = %d, fs = %s\n", 120 devtoname(ip->i_dev), fs->s_blocksize, size, fs->fs_fsmnt); 121 panic("ext2_alloc: bad size"); 122 } 123 if (cred == NOCRED) 124 panic("ext2_alloc: missing credential"); 125#endif /* DIAGNOSTIC */ 126 if (size == fs->s_blocksize && fs->s_es->s_free_blocks_count == 0) 127 goto nospace; 128 if (cred->cr_uid != 0 && 129 fs->s_es->s_free_blocks_count < fs->s_es->s_r_blocks_count) 130 goto nospace; 131#if QUOTA 132 if ((error = chkdq(ip, (long)btodb(size), cred, 0)) != 0) 133 return (error); 134#endif 135 if (bpref >= fs->s_es->s_blocks_count) 136 bpref = 0; 137 /* call the Linux code */ 138#ifdef EXT2_PREALLOCATE 139 /* To have a preallocation hit, we must 140 * - have at least one block preallocated 141 * - and our preferred block must have that block number or one below 142 */ 143 if (ip->i_prealloc_count && 144 (bpref == ip->i_prealloc_block || 145 bpref + 1 == ip->i_prealloc_block)) 146 { 147 bno = ip->i_prealloc_block++; 148 ip->i_prealloc_count--; 149 /* ext2_debug ("preallocation hit (%lu/%lu).\n", 150 ++alloc_hits, ++alloc_attempts); */ 151 152 /* Linux gets, clears, and releases the buffer at this 153 point - we don't have to that; we leave it to the caller 154 */ 155 } else { 156 ext2_discard_prealloc (ip); 157 /* ext2_debug ("preallocation miss (%lu/%lu).\n", 158 alloc_hits, ++alloc_attempts); */ 159 if (S_ISREG(ip->i_mode)) 160 bno = ext2_new_block 161 (ITOV(ip)->v_mount, bpref, 162 &ip->i_prealloc_count, 163 &ip->i_prealloc_block); 164 else 165 bno = (daddr_t)ext2_new_block(ITOV(ip)->v_mount, 166 bpref, 0, 0); 167 } 168#else 169 bno = (daddr_t)ext2_new_block(ITOV(ip)->v_mount, bpref, 0, 0); 170#endif 171 172 if (bno > 0) { 173 /* set next_alloc fields as done in block_getblk */ 174 ip->i_next_alloc_block = lbn; 175 ip->i_next_alloc_goal = bno; 176 177 ip->i_blocks += btodb(size); 178 ip->i_flag |= IN_CHANGE | IN_UPDATE; 179 *bnp = bno; 180 return (0); 181 } 182#if QUOTA 183 /* 184 * Restore user's disk quota because allocation failed. 185 */ 186 (void) chkdq(ip, (long)-btodb(size), cred, FORCE); 187#endif 188nospace: 189 ext2_fserr(fs, cred->cr_uid, "file system full"); 190 uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 191 return (ENOSPC); 192} 193 194/* 195 * Reallocate a sequence of blocks into a contiguous sequence of blocks. 196 * 197 * The vnode and an array of buffer pointers for a range of sequential 198 * logical blocks to be made contiguous is given. The allocator attempts 199 * to find a range of sequential blocks starting as close as possible to 200 * an fs_rotdelay offset from the end of the allocation for the logical
|
202 * physical block numbers in the buffer pointers and in the inode are 203 * changed to reflect the new allocation. If unsuccessful, the allocation 204 * is left unchanged. The success in doing the reallocation is returned. 205 * Note that the error return is not reflected back to the user. Rather 206 * the previous block allocation will be used. 207 */ 208 209#ifdef FANCY_REALLOC 210#include <sys/sysctl.h> 211static int doasyncfree = 1; 212#ifdef OPT_DEBUG 213SYSCTL_INT(_debug, 14, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, ""); 214#endif /* OPT_DEBUG */ 215#endif 216 217int 218ext2_reallocblks(ap) 219 struct vop_reallocblks_args /* { 220 struct vnode *a_vp; 221 struct cluster_save *a_buflist; 222 } */ *ap; 223{ 224#ifndef FANCY_REALLOC 225/* printf("ext2_reallocblks not implemented\n"); */ 226return ENOSPC; 227#else 228 229 struct ext2_sb_info *fs; 230 struct inode *ip; 231 struct vnode *vp; 232 struct buf *sbp, *ebp; 233 daddr_t *bap, *sbap, *ebap; 234 struct cluster_save *buflist; 235 daddr_t start_lbn, end_lbn, soff, eoff, newblk, blkno; 236 struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp; 237 int i, len, start_lvl, end_lvl, pref, ssize; 238 239 vp = ap->a_vp; 240 ip = VTOI(vp); 241 fs = ip->i_e2fs; 242#ifdef UNKLAR 243 if (fs->fs_contigsumsize <= 0) 244 return (ENOSPC); 245#endif 246 buflist = ap->a_buflist; 247 len = buflist->bs_nchildren; 248 start_lbn = buflist->bs_children[0]->b_lblkno; 249 end_lbn = start_lbn + len - 1; 250#if DIAGNOSTIC 251 for (i = 1; i < len; i++) 252 if (buflist->bs_children[i]->b_lblkno != start_lbn + i) 253 panic("ext2_reallocblks: non-cluster"); 254#endif 255 /* 256 * If the latest allocation is in a new cylinder group, assume that 257 * the filesystem has decided to move and do not force it back to 258 * the previous cylinder group. 259 */ 260 if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) != 261 dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno))) 262 return (ENOSPC); 263 if (ufs_getlbns(vp, start_lbn, start_ap, &start_lvl) || 264 ufs_getlbns(vp, end_lbn, end_ap, &end_lvl)) 265 return (ENOSPC); 266 /* 267 * Get the starting offset and block map for the first block. 268 */ 269 if (start_lvl == 0) { 270 sbap = &ip->i_db[0]; 271 soff = start_lbn; 272 } else { 273 idp = &start_ap[start_lvl - 1]; 274 if (bread(vp, idp->in_lbn, (int)fs->s_blocksize, NOCRED, &sbp)) { 275 brelse(sbp); 276 return (ENOSPC); 277 } 278 sbap = (daddr_t *)sbp->b_data; 279 soff = idp->in_off; 280 } 281 /* 282 * Find the preferred location for the cluster. 283 */ 284 pref = ext2_blkpref(ip, start_lbn, soff, sbap); 285 /* 286 * If the block range spans two block maps, get the second map. 287 */ 288 if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) { 289 ssize = len; 290 } else { 291#if DIAGNOSTIC 292 if (start_ap[start_lvl-1].in_lbn == idp->in_lbn) 293 panic("ext2_reallocblk: start == end"); 294#endif 295 ssize = len - (idp->in_off + 1); 296 if (bread(vp, idp->in_lbn, (int)fs->s_blocksize, NOCRED, &ebp)) 297 goto fail; 298 ebap = (daddr_t *)ebp->b_data; 299 } 300 /* 301 * Search the block map looking for an allocation of the desired size. 302 */ 303 if ((newblk = (daddr_t)ext2_hashalloc(ip, dtog(fs, pref), (long)pref, 304 len, (u_long (*)())ext2_clusteralloc)) == 0) 305 goto fail; 306 /* 307 * We have found a new contiguous block. 308 * 309 * First we have to replace the old block pointers with the new 310 * block pointers in the inode and indirect blocks associated 311 * with the file. 312 */ 313 blkno = newblk; 314 for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->s_frags_per_block) { 315 if (i == ssize) 316 bap = ebap; 317#if DIAGNOSTIC 318 if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap)) 319 panic("ext2_reallocblks: alloc mismatch"); 320#endif 321 *bap++ = blkno; 322 } 323 /* 324 * Next we must write out the modified inode and indirect blocks. 325 * For strict correctness, the writes should be synchronous since 326 * the old block values may have been written to disk. In practise 327 * they are almost never written, but if we are concerned about 328 * strict correctness, the `doasyncfree' flag should be set to zero. 329 * 330 * The test on `doasyncfree' should be changed to test a flag 331 * that shows whether the associated buffers and inodes have 332 * been written. The flag should be set when the cluster is 333 * started and cleared whenever the buffer or inode is flushed. 334 * We can then check below to see if it is set, and do the 335 * synchronous write only when it has been cleared. 336 */ 337 if (sbap != &ip->i_db[0]) { 338 if (doasyncfree) 339 bdwrite(sbp); 340 else 341 bwrite(sbp); 342 } else { 343 ip->i_flag |= IN_CHANGE | IN_UPDATE; 344 if (!doasyncfree) 345 UFS_UPDATE(vp, 1); 346 } 347 if (ssize < len) 348 if (doasyncfree) 349 bdwrite(ebp); 350 else 351 bwrite(ebp); 352 /* 353 * Last, free the old blocks and assign the new blocks to the buffers. 354 */ 355 for (blkno = newblk, i = 0; i < len; i++, blkno += fs->s_frags_per_block) { 356 ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno), 357 fs->s_blocksize); 358 buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); 359 } 360 return (0); 361 362fail: 363 if (ssize < len) 364 brelse(ebp); 365 if (sbap != &ip->i_db[0]) 366 brelse(sbp); 367 return (ENOSPC); 368 369#endif /* FANCY_REALLOC */ 370} 371 372/* 373 * Allocate an inode in the file system. 374 * 375 * we leave the actual allocation strategy to the (modified) 376 * ext2_new_inode(), to make sure we get the policies right 377 */ 378int 379ext2_valloc(pvp, mode, cred, vpp) 380 struct vnode *pvp; 381 int mode; 382 struct ucred *cred; 383 struct vnode **vpp; 384{ 385 register struct inode *pip; 386 register struct ext2_sb_info *fs; 387 register struct inode *ip; 388 ino_t ino; 389 int i, error; 390 391 *vpp = NULL; 392 pip = VTOI(pvp); 393 fs = pip->i_e2fs; 394 if (fs->s_es->s_free_inodes_count == 0) 395 goto noinodes; 396 397 /* call the Linux routine - it returns the inode number only */ 398 ino = ext2_new_inode(pip, mode); 399 400 if (ino == 0) 401 goto noinodes; 402 error = VFS_VGET(pvp->v_mount, ino, vpp); 403 if (error) { 404 UFS_VFREE(pvp, ino, mode); 405 return (error); 406 } 407 ip = VTOI(*vpp); 408 409 /* 410 the question is whether using VGET was such good idea at all - 411 Linux doesn't read the old inode in when it's allocating a 412 new one. I will set at least i_size & i_blocks the zero. 413 */ 414 ip->i_mode = 0; 415 ip->i_size = 0; 416 ip->i_blocks = 0; 417 ip->i_flags = 0; 418 /* now we want to make sure that the block pointers are zeroed out */ 419 for (i = 0; i < NDADDR; i++) 420 ip->i_db[i] = 0; 421 for (i = 0; i < NIADDR; i++) 422 ip->i_ib[i] = 0; 423 424 /* 425 * Set up a new generation number for this inode. 426 * XXX check if this makes sense in ext2 427 */ 428 if (ip->i_gen == 0 || ++ip->i_gen == 0) 429 ip->i_gen = random() / 2 + 1; 430/* 431printf("ext2_valloc: allocated inode %d\n", ino); 432*/ 433 return (0); 434noinodes: 435 ext2_fserr(fs, cred->cr_uid, "out of inodes"); 436 uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt); 437 return (ENOSPC); 438} 439 440/* 441 * Select the desired position for the next block in a file. 442 * 443 * we try to mimic what Remy does in inode_getblk/block_getblk 444 * 445 * we note: blocknr == 0 means that we're about to allocate either 446 * a direct block or a pointer block at the first level of indirection 447 * (In other words, stuff that will go in i_db[] or i_ib[]) 448 * 449 * blocknr != 0 means that we're allocating a block that is none 450 * of the above. Then, blocknr tells us the number of the block 451 * that will hold the pointer 452 */ 453daddr_t 454ext2_blkpref(ip, lbn, indx, bap, blocknr) 455 struct inode *ip; 456 daddr_t lbn; 457 int indx; 458 daddr_t *bap; 459 daddr_t blocknr; 460{ 461 int tmp; 462 463 /* if the next block is actually what we thought it is, 464 then set the goal to what we thought it should be 465 */ 466 if(ip->i_next_alloc_block == lbn) 467 return ip->i_next_alloc_goal; 468 469 /* now check whether we were provided with an array that basically 470 tells us previous blocks to which we want to stay closeby 471 */ 472 if(bap) 473 for (tmp = indx - 1; tmp >= 0; tmp--) 474 if (bap[tmp]) 475 return bap[tmp]; 476 477 /* else let's fall back to the blocknr, or, if there is none, 478 follow the rule that a block should be allocated near its inode 479 */ 480 return blocknr ? blocknr : 481 (daddr_t)(ip->i_block_group * 482 EXT2_BLOCKS_PER_GROUP(ip->i_e2fs)) + 483 ip->i_e2fs->s_es->s_first_data_block; 484} 485 486/* 487 * Free a block or fragment. 488 * 489 * pass on to the Linux code 490 */ 491void 492ext2_blkfree(ip, bno, size) 493 register struct inode *ip; 494 daddr_t bno; 495 long size; 496{ 497 register struct ext2_sb_info *fs; 498 499 fs = ip->i_e2fs; 500 /* 501 * call Linux code with mount *, block number, count 502 */ 503 ext2_free_blocks(ITOV(ip)->v_mount, bno, size / fs->s_frag_size); 504} 505 506/* 507 * Free an inode. 508 * 509 * the maintenance of the actual bitmaps is again up to the linux code 510 */ 511int 512ext2_vfree(pvp, ino, mode) 513 struct vnode *pvp; 514 ino_t ino; 515 int mode; 516{ 517 register struct ext2_sb_info *fs; 518 register struct inode *pip; 519 register mode_t save_i_mode; 520 521 pip = VTOI(pvp); 522 fs = pip->i_e2fs; 523 if ((u_int)ino >= fs->s_inodes_per_group * fs->s_groups_count) 524 panic("ext2_vfree: range: dev = (%d, %d), ino = %d, fs = %s", 525 major(pip->i_dev), minor(pip->i_dev), ino, fs->fs_fsmnt); 526 527/* ext2_debug("ext2_vfree (%d, %d) called\n", pip->i_number, mode); 528 */ 529 ext2_discard_prealloc(pip); 530 531 /* we need to make sure that ext2_free_inode can adjust the 532 used_dir_counts in the group summary information - I'd 533 really like to know what the rationale behind this 534 'set i_mode to zero to denote an unused inode' is 535 */ 536 save_i_mode = pip->i_mode; 537 pip->i_mode = mode; 538 ext2_free_inode(pip); 539 pip->i_mode = save_i_mode; 540 return (0); 541} 542 543/* 544 * Fserr prints the name of a file system with an error diagnostic. 545 * 546 * The form of the error message is: 547 * fs: error message 548 */ 549static void 550ext2_fserr(fs, uid, cp) 551 struct ext2_sb_info *fs; 552 u_int uid; 553 char *cp; 554{ 555 556 log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->fs_fsmnt, cp); 557}
| 202 * physical block numbers in the buffer pointers and in the inode are 203 * changed to reflect the new allocation. If unsuccessful, the allocation 204 * is left unchanged. The success in doing the reallocation is returned. 205 * Note that the error return is not reflected back to the user. Rather 206 * the previous block allocation will be used. 207 */ 208 209#ifdef FANCY_REALLOC 210#include <sys/sysctl.h> 211static int doasyncfree = 1; 212#ifdef OPT_DEBUG 213SYSCTL_INT(_debug, 14, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, ""); 214#endif /* OPT_DEBUG */ 215#endif 216 217int 218ext2_reallocblks(ap) 219 struct vop_reallocblks_args /* { 220 struct vnode *a_vp; 221 struct cluster_save *a_buflist; 222 } */ *ap; 223{ 224#ifndef FANCY_REALLOC 225/* printf("ext2_reallocblks not implemented\n"); */ 226return ENOSPC; 227#else 228 229 struct ext2_sb_info *fs; 230 struct inode *ip; 231 struct vnode *vp; 232 struct buf *sbp, *ebp; 233 daddr_t *bap, *sbap, *ebap; 234 struct cluster_save *buflist; 235 daddr_t start_lbn, end_lbn, soff, eoff, newblk, blkno; 236 struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp; 237 int i, len, start_lvl, end_lvl, pref, ssize; 238 239 vp = ap->a_vp; 240 ip = VTOI(vp); 241 fs = ip->i_e2fs; 242#ifdef UNKLAR 243 if (fs->fs_contigsumsize <= 0) 244 return (ENOSPC); 245#endif 246 buflist = ap->a_buflist; 247 len = buflist->bs_nchildren; 248 start_lbn = buflist->bs_children[0]->b_lblkno; 249 end_lbn = start_lbn + len - 1; 250#if DIAGNOSTIC 251 for (i = 1; i < len; i++) 252 if (buflist->bs_children[i]->b_lblkno != start_lbn + i) 253 panic("ext2_reallocblks: non-cluster"); 254#endif 255 /* 256 * If the latest allocation is in a new cylinder group, assume that 257 * the filesystem has decided to move and do not force it back to 258 * the previous cylinder group. 259 */ 260 if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) != 261 dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno))) 262 return (ENOSPC); 263 if (ufs_getlbns(vp, start_lbn, start_ap, &start_lvl) || 264 ufs_getlbns(vp, end_lbn, end_ap, &end_lvl)) 265 return (ENOSPC); 266 /* 267 * Get the starting offset and block map for the first block. 268 */ 269 if (start_lvl == 0) { 270 sbap = &ip->i_db[0]; 271 soff = start_lbn; 272 } else { 273 idp = &start_ap[start_lvl - 1]; 274 if (bread(vp, idp->in_lbn, (int)fs->s_blocksize, NOCRED, &sbp)) { 275 brelse(sbp); 276 return (ENOSPC); 277 } 278 sbap = (daddr_t *)sbp->b_data; 279 soff = idp->in_off; 280 } 281 /* 282 * Find the preferred location for the cluster. 283 */ 284 pref = ext2_blkpref(ip, start_lbn, soff, sbap); 285 /* 286 * If the block range spans two block maps, get the second map. 287 */ 288 if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) { 289 ssize = len; 290 } else { 291#if DIAGNOSTIC 292 if (start_ap[start_lvl-1].in_lbn == idp->in_lbn) 293 panic("ext2_reallocblk: start == end"); 294#endif 295 ssize = len - (idp->in_off + 1); 296 if (bread(vp, idp->in_lbn, (int)fs->s_blocksize, NOCRED, &ebp)) 297 goto fail; 298 ebap = (daddr_t *)ebp->b_data; 299 } 300 /* 301 * Search the block map looking for an allocation of the desired size. 302 */ 303 if ((newblk = (daddr_t)ext2_hashalloc(ip, dtog(fs, pref), (long)pref, 304 len, (u_long (*)())ext2_clusteralloc)) == 0) 305 goto fail; 306 /* 307 * We have found a new contiguous block. 308 * 309 * First we have to replace the old block pointers with the new 310 * block pointers in the inode and indirect blocks associated 311 * with the file. 312 */ 313 blkno = newblk; 314 for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->s_frags_per_block) { 315 if (i == ssize) 316 bap = ebap; 317#if DIAGNOSTIC 318 if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap)) 319 panic("ext2_reallocblks: alloc mismatch"); 320#endif 321 *bap++ = blkno; 322 } 323 /* 324 * Next we must write out the modified inode and indirect blocks. 325 * For strict correctness, the writes should be synchronous since 326 * the old block values may have been written to disk. In practise 327 * they are almost never written, but if we are concerned about 328 * strict correctness, the `doasyncfree' flag should be set to zero. 329 * 330 * The test on `doasyncfree' should be changed to test a flag 331 * that shows whether the associated buffers and inodes have 332 * been written. The flag should be set when the cluster is 333 * started and cleared whenever the buffer or inode is flushed. 334 * We can then check below to see if it is set, and do the 335 * synchronous write only when it has been cleared. 336 */ 337 if (sbap != &ip->i_db[0]) { 338 if (doasyncfree) 339 bdwrite(sbp); 340 else 341 bwrite(sbp); 342 } else { 343 ip->i_flag |= IN_CHANGE | IN_UPDATE; 344 if (!doasyncfree) 345 UFS_UPDATE(vp, 1); 346 } 347 if (ssize < len) 348 if (doasyncfree) 349 bdwrite(ebp); 350 else 351 bwrite(ebp); 352 /* 353 * Last, free the old blocks and assign the new blocks to the buffers. 354 */ 355 for (blkno = newblk, i = 0; i < len; i++, blkno += fs->s_frags_per_block) { 356 ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno), 357 fs->s_blocksize); 358 buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); 359 } 360 return (0); 361 362fail: 363 if (ssize < len) 364 brelse(ebp); 365 if (sbap != &ip->i_db[0]) 366 brelse(sbp); 367 return (ENOSPC); 368 369#endif /* FANCY_REALLOC */ 370} 371 372/* 373 * Allocate an inode in the file system. 374 * 375 * we leave the actual allocation strategy to the (modified) 376 * ext2_new_inode(), to make sure we get the policies right 377 */ 378int 379ext2_valloc(pvp, mode, cred, vpp) 380 struct vnode *pvp; 381 int mode; 382 struct ucred *cred; 383 struct vnode **vpp; 384{ 385 register struct inode *pip; 386 register struct ext2_sb_info *fs; 387 register struct inode *ip; 388 ino_t ino; 389 int i, error; 390 391 *vpp = NULL; 392 pip = VTOI(pvp); 393 fs = pip->i_e2fs; 394 if (fs->s_es->s_free_inodes_count == 0) 395 goto noinodes; 396 397 /* call the Linux routine - it returns the inode number only */ 398 ino = ext2_new_inode(pip, mode); 399 400 if (ino == 0) 401 goto noinodes; 402 error = VFS_VGET(pvp->v_mount, ino, vpp); 403 if (error) { 404 UFS_VFREE(pvp, ino, mode); 405 return (error); 406 } 407 ip = VTOI(*vpp); 408 409 /* 410 the question is whether using VGET was such good idea at all - 411 Linux doesn't read the old inode in when it's allocating a 412 new one. I will set at least i_size & i_blocks the zero. 413 */ 414 ip->i_mode = 0; 415 ip->i_size = 0; 416 ip->i_blocks = 0; 417 ip->i_flags = 0; 418 /* now we want to make sure that the block pointers are zeroed out */ 419 for (i = 0; i < NDADDR; i++) 420 ip->i_db[i] = 0; 421 for (i = 0; i < NIADDR; i++) 422 ip->i_ib[i] = 0; 423 424 /* 425 * Set up a new generation number for this inode. 426 * XXX check if this makes sense in ext2 427 */ 428 if (ip->i_gen == 0 || ++ip->i_gen == 0) 429 ip->i_gen = random() / 2 + 1; 430/* 431printf("ext2_valloc: allocated inode %d\n", ino); 432*/ 433 return (0); 434noinodes: 435 ext2_fserr(fs, cred->cr_uid, "out of inodes"); 436 uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt); 437 return (ENOSPC); 438} 439 440/* 441 * Select the desired position for the next block in a file. 442 * 443 * we try to mimic what Remy does in inode_getblk/block_getblk 444 * 445 * we note: blocknr == 0 means that we're about to allocate either 446 * a direct block or a pointer block at the first level of indirection 447 * (In other words, stuff that will go in i_db[] or i_ib[]) 448 * 449 * blocknr != 0 means that we're allocating a block that is none 450 * of the above. Then, blocknr tells us the number of the block 451 * that will hold the pointer 452 */ 453daddr_t 454ext2_blkpref(ip, lbn, indx, bap, blocknr) 455 struct inode *ip; 456 daddr_t lbn; 457 int indx; 458 daddr_t *bap; 459 daddr_t blocknr; 460{ 461 int tmp; 462 463 /* if the next block is actually what we thought it is, 464 then set the goal to what we thought it should be 465 */ 466 if(ip->i_next_alloc_block == lbn) 467 return ip->i_next_alloc_goal; 468 469 /* now check whether we were provided with an array that basically 470 tells us previous blocks to which we want to stay closeby 471 */ 472 if(bap) 473 for (tmp = indx - 1; tmp >= 0; tmp--) 474 if (bap[tmp]) 475 return bap[tmp]; 476 477 /* else let's fall back to the blocknr, or, if there is none, 478 follow the rule that a block should be allocated near its inode 479 */ 480 return blocknr ? blocknr : 481 (daddr_t)(ip->i_block_group * 482 EXT2_BLOCKS_PER_GROUP(ip->i_e2fs)) + 483 ip->i_e2fs->s_es->s_first_data_block; 484} 485 486/* 487 * Free a block or fragment. 488 * 489 * pass on to the Linux code 490 */ 491void 492ext2_blkfree(ip, bno, size) 493 register struct inode *ip; 494 daddr_t bno; 495 long size; 496{ 497 register struct ext2_sb_info *fs; 498 499 fs = ip->i_e2fs; 500 /* 501 * call Linux code with mount *, block number, count 502 */ 503 ext2_free_blocks(ITOV(ip)->v_mount, bno, size / fs->s_frag_size); 504} 505 506/* 507 * Free an inode. 508 * 509 * the maintenance of the actual bitmaps is again up to the linux code 510 */ 511int 512ext2_vfree(pvp, ino, mode) 513 struct vnode *pvp; 514 ino_t ino; 515 int mode; 516{ 517 register struct ext2_sb_info *fs; 518 register struct inode *pip; 519 register mode_t save_i_mode; 520 521 pip = VTOI(pvp); 522 fs = pip->i_e2fs; 523 if ((u_int)ino >= fs->s_inodes_per_group * fs->s_groups_count) 524 panic("ext2_vfree: range: dev = (%d, %d), ino = %d, fs = %s", 525 major(pip->i_dev), minor(pip->i_dev), ino, fs->fs_fsmnt); 526 527/* ext2_debug("ext2_vfree (%d, %d) called\n", pip->i_number, mode); 528 */ 529 ext2_discard_prealloc(pip); 530 531 /* we need to make sure that ext2_free_inode can adjust the 532 used_dir_counts in the group summary information - I'd 533 really like to know what the rationale behind this 534 'set i_mode to zero to denote an unused inode' is 535 */ 536 save_i_mode = pip->i_mode; 537 pip->i_mode = mode; 538 ext2_free_inode(pip); 539 pip->i_mode = save_i_mode; 540 return (0); 541} 542 543/* 544 * Fserr prints the name of a file system with an error diagnostic. 545 * 546 * The form of the error message is: 547 * fs: error message 548 */ 549static void 550ext2_fserr(fs, uid, cp) 551 struct ext2_sb_info *fs; 552 u_int uid; 553 char *cp; 554{ 555 556 log(LOG_ERR, "uid %d on %s: %s\n", uid, fs->fs_fsmnt, cp); 557}
|