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_inode.c 8.5 (Berkeley) 12/30/93 38 * $FreeBSD$ 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/mount.h> 44 #include <sys/bio.h> 45 #include <sys/buf2.h> 46 #include <sys/endian.h> 47 #include <sys/vnode.h> 48 #include <sys/malloc.h> 49 50 #include <vm/vm.h> 51 #include <vm/vm_extern.h> 52 53 #include <vfs/ext2fs/fs.h> 54 #include <vfs/ext2fs/inode.h> 55 #include <vfs/ext2fs/ext2_mount.h> 56 #include <vfs/ext2fs/ext2fs.h> 57 #include <vfs/ext2fs/ext2_extern.h> 58 59 /* 60 * Update the access, modified, and inode change times as specified by the 61 * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively. Write the inode 62 * to disk if the IN_MODIFIED flag is set (it may be set initially, or by 63 * the timestamp update). The IN_LAZYMOD flag is set to force a write 64 * later if not now. If we write now, then clear both IN_MODIFIED and 65 * IN_LAZYMOD to reflect the presumably successful write, and if waitfor is 66 * set, then wait for the write to complete. 67 */ 68 int 69 ext2_update(struct vnode *vp, int waitfor) 70 { 71 struct m_ext2fs *fs; 72 struct buf *bp; 73 struct inode *ip; 74 int error; 75 76 ASSERT_VOP_ELOCKED(vp, "ext2_update"); 77 ext2_itimes(vp); 78 ip = VTOI(vp); 79 if ((ip->i_flag & IN_MODIFIED) == 0 && waitfor == 0) 80 return (0); 81 ip->i_flag &= ~(IN_LAZYACCESS | IN_LAZYMOD | IN_MODIFIED); 82 fs = ip->i_e2fs; 83 if (fs->e2fs_ronly) 84 return (0); 85 if ((error = bread(ip->i_devvp, 86 fsbtodoff(fs, ino_to_fsba(fs, ip->i_number)), 87 (int)fs->e2fs_bsize, &bp)) != 0) { 88 brelse(bp); 89 return (error); 90 } 91 error = ext2_i2ei(ip, (struct ext2fs_dinode *)((char *)bp->b_data + 92 EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number))); 93 if (error) { 94 brelse(bp); 95 return (error); 96 } 97 if (waitfor && !DOINGASYNC(vp)) 98 return (bwrite(bp)); 99 else { 100 bdwrite(bp); 101 return (0); 102 } 103 } 104 105 #define SINGLE 0 /* index of single indirect block */ 106 #define DOUBLE 1 /* index of double indirect block */ 107 #define TRIPLE 2 /* index of triple indirect block */ 108 109 /* 110 * Release blocks associated with the inode ip and stored in the indirect 111 * block bn. Blocks are free'd in LIFO order up to (but not including) 112 * lastbn. If level is greater than SINGLE, the block is an indirect block 113 * and recursive calls to indirtrunc must be used to cleanse other indirect 114 * blocks. 115 * 116 * NB: triple indirect blocks are untested. 117 */ 118 static int 119 ext2_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn, 120 daddr_t lastbn, int level, e4fs_daddr_t *countp) 121 { 122 struct buf *bp; 123 struct m_ext2fs *fs = ip->i_e2fs; 124 struct vnode *vp; 125 e2fs_daddr_t *bap, *copy; 126 int i, nblocks, error = 0, allerror = 0; 127 e2fs_lbn_t nb, nlbn, last; 128 e4fs_daddr_t blkcount, factor, blocksreleased = 0; 129 130 /* 131 * Calculate index in current block of last 132 * block to be kept. -1 indicates the entire 133 * block so we need not calculate the index. 134 */ 135 factor = 1; 136 for (i = SINGLE; i < level; i++) 137 factor *= NINDIR(fs); 138 last = lastbn; 139 if (lastbn > 0) 140 last /= factor; 141 nblocks = btodb(fs->e2fs_bsize); 142 /* 143 * Get buffer of block pointers, zero those entries corresponding 144 * to blocks to be free'd, and update on disk copy first. Since 145 * double(triple) indirect before single(double) indirect, calls 146 * to bmap on these blocks will fail. However, we already have 147 * the on disk address, so we have to set the b_blkno field 148 * explicitly instead of letting bread do everything for us. 149 */ 150 vp = ITOV(ip); 151 bp = getblk(vp, lblktodoff(fs, lbn), (int)fs->e2fs_bsize, 0, 0); 152 if ((bp->b_flags & B_CACHE) == 0) { 153 bp->b_flags &= ~(B_ERROR | B_INVAL); 154 bp->b_cmd = BUF_CMD_READ; 155 if (bp->b_bcount > bp->b_bufsize) 156 panic("ext2_indirtrunc: bad buffer size"); 157 bp->b_bio2.bio_offset = dbtodoff(fs, dbn); 158 bp->b_bio1.bio_done = biodone_sync; 159 bp->b_bio1.bio_flags |= BIO_SYNC; 160 vfs_busy_pages(bp->b_vp, bp); 161 vn_strategy(vp, &bp->b_bio1); 162 error = biowait(&bp->b_bio1, "biord"); 163 } 164 if (error) { 165 brelse(bp); 166 *countp = 0; 167 return (error); 168 } 169 bap = (e2fs_daddr_t *)bp->b_data; 170 copy = malloc(fs->e2fs_bsize, M_TEMP, M_WAITOK); 171 bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->e2fs_bsize); 172 bzero((caddr_t)&bap[last + 1], 173 (NINDIR(fs) - (last + 1)) * sizeof(e2fs_daddr_t)); 174 if (last == -1) 175 bp->b_flags |= B_INVAL; 176 if (DOINGASYNC(vp)) { 177 bdwrite(bp); 178 } else { 179 error = bwrite(bp); 180 if (error) 181 allerror = error; 182 } 183 bap = copy; 184 185 /* 186 * Recursively free totally unused blocks. 187 */ 188 for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last; 189 i--, nlbn += factor) { 190 nb = le32toh(bap[i]); 191 if (nb == 0) 192 continue; 193 if (level > SINGLE) { 194 if ((error = ext2_indirtrunc(ip, nlbn, 195 fsbtodb(fs, nb), (int32_t)-1, level - 1, &blkcount)) != 0) 196 allerror = error; 197 blocksreleased += blkcount; 198 } 199 ext2_blkfree(ip, nb, fs->e2fs_bsize); 200 blocksreleased += nblocks; 201 } 202 203 /* 204 * Recursively free last partial block. 205 */ 206 if (level > SINGLE && lastbn >= 0) { 207 last = lastbn % factor; 208 nb = le32toh(bap[i]); 209 if (nb != 0) { 210 if ((error = ext2_indirtrunc(ip, nlbn, fsbtodb(fs, nb), 211 last, level - 1, &blkcount)) != 0) 212 allerror = error; 213 blocksreleased += blkcount; 214 } 215 } 216 free(copy, M_TEMP); 217 *countp = blocksreleased; 218 return (allerror); 219 } 220 221 /* 222 * Truncate the inode oip to at most length size, freeing the 223 * disk blocks. 224 */ 225 static int 226 ext2_ind_truncate(struct vnode *vp, off_t length, int flags, struct ucred *cred) 227 { 228 struct vnode *ovp = vp; 229 e4fs_daddr_t lastblock; 230 struct inode *oip; 231 e4fs_daddr_t bn, lbn, lastiblock[EXT2_NIADDR], indir_lbn[EXT2_NIADDR]; 232 uint32_t oldblks[EXT2_NDADDR + EXT2_NIADDR]; 233 uint32_t newblks[EXT2_NDADDR + EXT2_NIADDR]; 234 struct m_ext2fs *fs; 235 struct buf *bp; 236 int offset, size, level; 237 e4fs_daddr_t count, nblocks, blocksreleased = 0; 238 int error, i, allerror; 239 off_t osize; 240 241 oip = VTOI(ovp); 242 243 fs = oip->i_e2fs; 244 osize = oip->i_size; 245 /* 246 * Lengthen the size of the file. We must ensure that the 247 * last byte of the file is allocated. Since the smallest 248 * value of osize is 0, length will be at least 1. 249 */ 250 if (osize < length) { 251 if (length > oip->i_e2fs->e2fs_maxfilesize) 252 return (EFBIG); 253 vnode_pager_setsize(ovp, length); 254 offset = blkoff(fs, length - 1); 255 lbn = lblkno(fs, length - 1); 256 flags |= BA_CLRBUF; 257 error = ext2_balloc(oip, lbn, offset + 1, cred, &bp, flags); 258 if (error) { 259 vnode_pager_setsize(vp, osize); 260 return (error); 261 } 262 oip->i_size = length; 263 if (bp->b_bufsize == fs->e2fs_bsize) 264 bp->b_flags |= B_CLUSTEROK; 265 if (flags & IO_SYNC) 266 bwrite(bp); 267 else if (DOINGASYNC(ovp)) 268 bdwrite(bp); 269 else 270 bawrite(bp); 271 oip->i_flag |= IN_CHANGE | IN_UPDATE; 272 return (ext2_update(ovp, !DOINGASYNC(ovp))); 273 } 274 /* 275 * Shorten the size of the file. If the file is not being 276 * truncated to a block boundary, the contents of the 277 * partial block following the end of the file must be 278 * zero'ed in case it ever become accessible again because 279 * of subsequent file growth. 280 */ 281 /* I don't understand the comment above */ 282 offset = blkoff(fs, length); 283 if (offset == 0) { 284 oip->i_size = length; 285 } else { 286 lbn = lblkno(fs, length); 287 flags |= BA_CLRBUF; 288 error = ext2_balloc(oip, lbn, offset, cred, &bp, flags); 289 if (error) 290 return (error); 291 oip->i_size = length; 292 size = blksize(fs, oip, lbn); 293 bzero((char *)bp->b_data + offset, (u_int)(size - offset)); 294 allocbuf(bp, size); 295 if (bp->b_bufsize == fs->e2fs_bsize) 296 bp->b_flags |= B_CLUSTEROK; 297 if (flags & IO_SYNC) 298 bwrite(bp); 299 else if (DOINGASYNC(ovp)) 300 bdwrite(bp); 301 else 302 bawrite(bp); 303 } 304 /* 305 * Calculate index into inode's block list of 306 * last direct and indirect blocks (if any) 307 * which we want to keep. Lastblock is -1 when 308 * the file is truncated to 0. 309 */ 310 lastblock = lblkno(fs, length + fs->e2fs_bsize - 1) - 1; 311 lastiblock[SINGLE] = lastblock - EXT2_NDADDR; 312 lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 313 lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 314 nblocks = btodb(fs->e2fs_bsize); 315 /* 316 * Update file and block pointers on disk before we start freeing 317 * blocks. If we crash before free'ing blocks below, the blocks 318 * will be returned to the free list. lastiblock values are also 319 * normalized to -1 for calls to ext2_indirtrunc below. 320 */ 321 for (level = TRIPLE; level >= SINGLE; level--) { 322 oldblks[EXT2_NDADDR + level] = oip->i_ib[level]; 323 if (lastiblock[level] < 0) { 324 oip->i_ib[level] = 0; 325 lastiblock[level] = -1; 326 } 327 } 328 for (i = 0; i < EXT2_NDADDR; i++) { 329 oldblks[i] = oip->i_db[i]; 330 if (i > lastblock) 331 oip->i_db[i] = 0; 332 } 333 oip->i_flag |= IN_CHANGE | IN_UPDATE; 334 allerror = ext2_update(ovp, !DOINGASYNC(ovp)); 335 336 /* 337 * Having written the new inode to disk, save its new configuration 338 * and put back the old block pointers long enough to process them. 339 * Note that we save the new block configuration so we can check it 340 * when we are done. 341 */ 342 for (i = 0; i < EXT2_NDADDR; i++) { 343 newblks[i] = oip->i_db[i]; 344 oip->i_db[i] = oldblks[i]; 345 } 346 for (i = 0; i < EXT2_NIADDR; i++) { 347 newblks[EXT2_NDADDR + i] = oip->i_ib[i]; 348 oip->i_ib[i] = oldblks[EXT2_NDADDR + i]; 349 } 350 oip->i_size = osize; 351 error = vtruncbuf(ovp, length, (int)fs->e2fs_bsize); 352 if (error && (allerror == 0)) 353 allerror = error; 354 vnode_pager_setsize(ovp, length); 355 356 /* 357 * Indirect blocks first. 358 */ 359 indir_lbn[SINGLE] = -EXT2_NDADDR; 360 indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1; 361 indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1; 362 for (level = TRIPLE; level >= SINGLE; level--) { 363 bn = oip->i_ib[level]; 364 if (bn != 0) { 365 error = ext2_indirtrunc(oip, indir_lbn[level], 366 fsbtodb(fs, bn), lastiblock[level], level, &count); 367 if (error) 368 allerror = error; 369 blocksreleased += count; 370 if (lastiblock[level] < 0) { 371 oip->i_ib[level] = 0; 372 ext2_blkfree(oip, bn, fs->e2fs_fsize); 373 blocksreleased += nblocks; 374 } 375 } 376 if (lastiblock[level] >= 0) 377 goto done; 378 } 379 380 /* 381 * All whole direct blocks or frags. 382 */ 383 for (i = EXT2_NDADDR - 1; i > lastblock; i--) { 384 long bsize; 385 386 bn = oip->i_db[i]; 387 if (bn == 0) 388 continue; 389 oip->i_db[i] = 0; 390 bsize = blksize(fs, oip, i); 391 ext2_blkfree(oip, bn, bsize); 392 blocksreleased += btodb(bsize); 393 } 394 if (lastblock < 0) 395 goto done; 396 397 /* 398 * Finally, look for a change in size of the 399 * last direct block; release any frags. 400 */ 401 bn = oip->i_db[lastblock]; 402 if (bn != 0) { 403 long oldspace, newspace; 404 405 /* 406 * Calculate amount of space we're giving 407 * back as old block size minus new block size. 408 */ 409 oldspace = blksize(fs, oip, lastblock); 410 oip->i_size = length; 411 newspace = blksize(fs, oip, lastblock); 412 if (newspace == 0) 413 panic("ext2_truncate: newspace"); 414 if (oldspace - newspace > 0) { 415 /* 416 * Block number of space to be free'd is 417 * the old block # plus the number of frags 418 * required for the storage we're keeping. 419 */ 420 bn += numfrags(fs, newspace); 421 ext2_blkfree(oip, bn, oldspace - newspace); 422 blocksreleased += btodb(oldspace - newspace); 423 } 424 } 425 done: 426 #ifdef INVARIANTS 427 for (level = SINGLE; level <= TRIPLE; level++) 428 if (newblks[EXT2_NDADDR + level] != oip->i_ib[level]) 429 panic("itrunc1"); 430 for (i = 0; i < EXT2_NDADDR; i++) 431 if (newblks[i] != oip->i_db[i]) 432 panic("itrunc2"); 433 #endif /* INVARIANTS */ 434 /* 435 * Put back the real size. 436 */ 437 oip->i_size = length; 438 if (oip->i_blocks >= blocksreleased) 439 oip->i_blocks -= blocksreleased; 440 else /* sanity */ 441 oip->i_blocks = 0; 442 oip->i_flag |= IN_CHANGE; 443 vnode_pager_setsize(ovp, length); 444 return (allerror); 445 } 446 447 static int 448 ext2_ext_truncate(struct vnode *vp, off_t length, int flags, struct ucred *cred) 449 { 450 return (EINVAL); 451 } 452 453 /* 454 * Truncate the inode ip to at most length size, freeing the 455 * disk blocks. 456 */ 457 int 458 ext2_truncate(struct vnode *vp, off_t length, int flags, struct ucred *cred) 459 { 460 struct inode *ip; 461 int error; 462 463 ASSERT_VOP_LOCKED(vp, "ext2_truncate"); 464 465 if (length < 0) 466 return (EINVAL); 467 468 ip = VTOI(vp); 469 if (vp->v_type == VLNK && 470 ip->i_size < vp->v_mount->mnt_maxsymlinklen) { 471 #ifdef INVARIANTS 472 if (length != 0) 473 panic("ext2_truncate: partial truncate of symlink"); 474 #endif 475 bzero((char *)&ip->i_shortlink, (u_int)ip->i_size); 476 ip->i_size = 0; 477 ip->i_flag |= IN_CHANGE | IN_UPDATE; 478 return (ext2_update(vp, 1)); 479 } 480 if (ip->i_size == length) { 481 ip->i_flag |= IN_CHANGE | IN_UPDATE; 482 return (ext2_update(vp, 0)); 483 } 484 485 if (ip->i_flag & IN_E4EXTENTS) 486 error = ext2_ext_truncate(vp, length, flags, cred); 487 else 488 error = ext2_ind_truncate(vp, length, flags, cred); 489 490 return (error); 491 } 492 493 /* 494 * discard preallocated blocks 495 */ 496 int 497 ext2_inactive(struct vop_inactive_args *ap) 498 { 499 struct vnode *vp = ap->a_vp; 500 struct inode *ip = VTOI(vp); 501 int mode, error = 0; 502 503 if (prtactive && VREFCNT(vp) > 1) 504 vprint("ext2_inactive: pushing active", vp); 505 506 /* 507 * Ignore inodes related to stale file handles. 508 */ 509 if (ip == NULL || ip->i_mode == 0) 510 goto out; 511 if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 512 error = ext2_truncate(vp, (off_t)0, 0, NOCRED); 513 if (!(ip->i_flag & IN_E4EXTENTS)) 514 ip->i_rdev = 0; 515 mode = ip->i_mode; 516 ip->i_mode = 0; 517 ip->i_flag |= IN_CHANGE | IN_UPDATE; 518 ext2_vfree(vp, ip->i_number, mode); 519 } 520 if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) 521 ext2_update(vp, 0); 522 out: 523 /* 524 * If we are done with the inode, reclaim it 525 * so that it can be reused immediately. 526 */ 527 if (ip == NULL || ip->i_mode == 0) 528 vrecycle(vp); 529 return (error); 530 } 531 532 /* 533 * Reclaim an inode so that it can be used for other purposes. 534 */ 535 int 536 ext2_reclaim(struct vop_reclaim_args *ap) 537 { 538 struct inode *ip; 539 struct vnode *vp = ap->a_vp; 540 541 if (prtactive && VREFCNT(vp) > 1) 542 vprint("ext2_reclaim: pushing active", vp); 543 544 ip = VTOI(vp); 545 if (ip && (ip->i_flag & IN_LAZYMOD)) { 546 ip->i_flag |= IN_MODIFIED; 547 ext2_update(vp, 0); 548 } 549 550 #ifdef INVARIANTS 551 if (ip && (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE))) { 552 printf("WARNING: INODE %ld flags %08x: modified inode being released!\n", 553 (long)ip->i_number, (int)ip->i_flag); 554 ip->i_flag |= IN_MODIFIED; 555 ext2_update(vp, 0); 556 } 557 #endif 558 /* 559 * Remove the inode from its hash chain and purge namecache 560 * data associated with the vnode. 561 */ 562 vp->v_data = NULL; 563 if (ip) { 564 ext2_ihashrem(ip); 565 if (ip->i_devvp) { 566 vrele(ip->i_devvp); 567 //ip->i_devvp = 0; /* ip->i_ump->um_devvp */ 568 } 569 free(ip, M_EXT2NODE); 570 } 571 return (0); 572 } 573