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