1 /* $NetBSD: ext2fs_inode.c,v 1.20 2000/06/28 14:16:37 mrg Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Manuel Bouyer. 5 * Copyright (c) 1982, 1986, 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)ffs_inode.c 8.8 (Berkeley) 10/19/94 37 * Modified for ext2fs by Manuel Bouyer. 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/mount.h> 43 #include <sys/proc.h> 44 #include <sys/file.h> 45 #include <sys/buf.h> 46 #include <sys/vnode.h> 47 #include <sys/kernel.h> 48 #include <sys/malloc.h> 49 #include <sys/trace.h> 50 #include <sys/resourcevar.h> 51 52 #include <ufs/ufs/quota.h> 53 #include <ufs/ufs/inode.h> 54 #include <ufs/ufs/ufsmount.h> 55 #include <ufs/ufs/ufs_extern.h> 56 57 #include <ufs/ext2fs/ext2fs.h> 58 #include <ufs/ext2fs/ext2fs_extern.h> 59 60 static int ext2fs_indirtrunc __P((struct inode *, ufs_daddr_t, ufs_daddr_t, 61 ufs_daddr_t, int, long *)); 62 63 /* 64 * Last reference to an inode. If necessary, write or delete it. 65 */ 66 int 67 ext2fs_inactive(v) 68 void *v; 69 { 70 struct vop_inactive_args /* { 71 struct vnode *a_vp; 72 struct proc *a_p; 73 } */ *ap = v; 74 struct vnode *vp = ap->a_vp; 75 struct inode *ip = VTOI(vp); 76 struct proc *p = ap->a_p; 77 struct timespec ts; 78 int error = 0; 79 extern int prtactive; 80 81 if (prtactive && vp->v_usecount != 0) 82 vprint("ext2fs_inactive: pushing active", vp); 83 /* Get rid of inodes related to stale file handles. */ 84 if (ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime != 0) 85 goto out; 86 87 error = 0; 88 if (ip->i_e2fs_nlink == 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 89 error = VOP_TRUNCATE(vp, (off_t)0, 0, NOCRED, NULL); 90 TIMEVAL_TO_TIMESPEC(&time, &ts); 91 ip->i_e2fs_dtime = ts.tv_sec; 92 ip->i_flag |= IN_CHANGE | IN_UPDATE; 93 VOP_VFREE(vp, ip->i_number, ip->i_e2fs_mode); 94 } 95 if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFIED | IN_ACCESSED)) 96 VOP_UPDATE(vp, NULL, NULL, 0); 97 out: 98 VOP_UNLOCK(vp, 0); 99 /* 100 * If we are done with the inode, reclaim it 101 * so that it can be reused immediately. 102 */ 103 if (ip->i_e2fs_dtime != 0) 104 vrecycle(vp, (struct simplelock *)0, p); 105 return (error); 106 } 107 108 109 /* 110 * Update the access, modified, and inode change times as specified by the 111 * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is 112 * used to specify that the inode needs to be updated but that the times have 113 * already been set. The access and modified times are taken from the second 114 * and third parameters; the inode change time is always taken from the current 115 * time. If UPDATE_WAIT or UPDATE_DIROP is set, then wait for the disk 116 * write of the inode to complete. 117 */ 118 int 119 ext2fs_update(v) 120 void *v; 121 { 122 struct vop_update_args /* { 123 struct vnode *a_vp; 124 struct timespec *a_access; 125 struct timespec *a_modify; 126 int a_flags; 127 } */ *ap = v; 128 struct m_ext2fs *fs; 129 struct buf *bp; 130 struct inode *ip; 131 int error; 132 struct timespec ts; 133 caddr_t cp; 134 int flags; 135 136 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 137 return (0); 138 ip = VTOI(ap->a_vp); 139 TIMEVAL_TO_TIMESPEC(&time, &ts); 140 EXT2FS_ITIMES(ip, 141 ap->a_access ? ap->a_access : &ts, 142 ap->a_modify ? ap->a_modify : &ts, &ts); 143 flags = ip->i_flag & (IN_MODIFIED | IN_ACCESSED); 144 if (flags == 0) 145 return (0); 146 fs = ip->i_e2fs; 147 148 error = bread(ip->i_devvp, 149 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 150 (int)fs->e2fs_bsize, NOCRED, &bp); 151 if (error) { 152 brelse(bp); 153 return (error); 154 } 155 ip->i_flag &= ~(IN_MODIFIED | IN_ACCESSED); 156 cp = (caddr_t)bp->b_data + 157 (ino_to_fsbo(fs, ip->i_number) * EXT2_DINODE_SIZE); 158 e2fs_isave(&ip->i_din.e2fs_din, (struct ext2fs_dinode *)cp); 159 if ((ap->a_flags & (UPDATE_WAIT|UPDATE_DIROP)) != 0 && 160 (flags & IN_MODIFIED) != 0 && 161 (ap->a_vp->v_mount->mnt_flag & MNT_ASYNC) == 0) 162 return (bwrite(bp)); 163 else { 164 bdwrite(bp); 165 return (0); 166 } 167 } 168 169 #define SINGLE 0 /* index of single indirect block */ 170 #define DOUBLE 1 /* index of double indirect block */ 171 #define TRIPLE 2 /* index of triple indirect block */ 172 /* 173 * Truncate the inode oip to at most length size, freeing the 174 * disk blocks. 175 */ 176 int 177 ext2fs_truncate(v) 178 void *v; 179 { 180 struct vop_truncate_args /* { 181 struct vnode *a_vp; 182 off_t a_length; 183 int a_flags; 184 struct ucred *a_cred; 185 struct proc *a_p; 186 } */ *ap = v; 187 struct vnode *ovp = ap->a_vp; 188 ufs_daddr_t lastblock; 189 struct inode *oip; 190 ufs_daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR]; 191 ufs_daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR]; 192 off_t length = ap->a_length; 193 struct m_ext2fs *fs; 194 struct buf *bp; 195 int offset, size, level; 196 long count, nblocks, blocksreleased = 0; 197 int i; 198 int aflags, error, allerror = 0; 199 off_t osize; 200 201 if (length < 0) 202 return (EINVAL); 203 204 oip = VTOI(ovp); 205 if (ovp->v_type == VLNK && 206 (oip->i_e2fs_size < ovp->v_mount->mnt_maxsymlinklen || 207 (ovp->v_mount->mnt_maxsymlinklen == 0 && 208 oip->i_e2fs_nblock == 0))) { 209 #ifdef DIAGNOSTIC 210 if (length != 0) 211 panic("ext2fs_truncate: partial truncate of symlink"); 212 #endif 213 memset((char *)&oip->i_din.e2fs_din.e2di_shortlink, 0, 214 (u_int)oip->i_e2fs_size); 215 oip->i_e2fs_size = 0; 216 oip->i_flag |= IN_CHANGE | IN_UPDATE; 217 return (VOP_UPDATE(ovp, NULL, NULL, UPDATE_WAIT)); 218 } 219 if (oip->i_e2fs_size == length) { 220 oip->i_flag |= IN_CHANGE | IN_UPDATE; 221 return (VOP_UPDATE(ovp, NULL, NULL, 0)); 222 } 223 fs = oip->i_e2fs; 224 osize = oip->i_e2fs_size; 225 /* 226 * Lengthen the size of the file. We must ensure that the 227 * last byte of the file is allocated. Since the smallest 228 * value of osize is 0, length will be at least 1. 229 */ 230 if (osize < length) { 231 #if 0 /* XXX */ 232 if (length > fs->fs_maxfilesize) 233 return (EFBIG); 234 #endif 235 offset = blkoff(fs, length - 1); 236 lbn = lblkno(fs, length - 1); 237 aflags = B_CLRBUF; 238 if (ap->a_flags & IO_SYNC) 239 aflags |= B_SYNC; 240 error = ext2fs_balloc(oip, lbn, offset + 1, ap->a_cred, &bp, 241 aflags); 242 if (error) 243 return (error); 244 oip->i_e2fs_size = length; 245 uvm_vnp_setsize(ovp, length); 246 (void) uvm_vnp_uncache(ovp); 247 if (aflags & B_SYNC) 248 bwrite(bp); 249 else 250 bawrite(bp); 251 oip->i_flag |= IN_CHANGE | IN_UPDATE; 252 return (VOP_UPDATE(ovp, NULL, NULL, UPDATE_WAIT)); 253 } 254 /* 255 * Shorten the size of the file. If the file is not being 256 * truncated to a block boundry, the contents of the 257 * partial block following the end of the file must be 258 * zero'ed in case it ever become accessable again because 259 * of subsequent file growth. 260 */ 261 offset = blkoff(fs, length); 262 if (offset == 0) { 263 oip->i_e2fs_size = length; 264 } else { 265 lbn = lblkno(fs, length); 266 aflags = B_CLRBUF; 267 if (ap->a_flags & IO_SYNC) 268 aflags |= B_SYNC; 269 error = ext2fs_balloc(oip, lbn, offset, ap->a_cred, &bp, aflags); 270 if (error) 271 return (error); 272 oip->i_e2fs_size = length; 273 size = fs->e2fs_bsize; 274 (void) uvm_vnp_uncache(ovp); 275 memset((char *)bp->b_data + offset, 0, (u_int)(size - offset)); 276 allocbuf(bp, size); 277 if (aflags & B_SYNC) 278 bwrite(bp); 279 else 280 bawrite(bp); 281 } 282 uvm_vnp_setsize(ovp, length); 283 284 /* 285 * Calculate index into inode's block list of 286 * last direct and indirect blocks (if any) 287 * which we want to keep. Lastblock is -1 when 288 * the file is truncated to 0. 289 */ 290 lastblock = lblkno(fs, length + fs->e2fs_bsize - 1) - 1; 291 lastiblock[SINGLE] = lastblock - NDADDR; 292 lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 293 lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 294 nblocks = btodb(fs->e2fs_bsize); 295 /* 296 * Update file and block pointers on disk before we start freeing 297 * blocks. If we crash before free'ing blocks below, the blocks 298 * will be returned to the free list. lastiblock values are also 299 * normalized to -1 for calls to ext2fs_indirtrunc below. 300 */ 301 memcpy((caddr_t)oldblks, (caddr_t)&oip->i_e2fs_blocks[0], sizeof oldblks); 302 for (level = TRIPLE; level >= SINGLE; level--) 303 if (lastiblock[level] < 0) { 304 oip->i_e2fs_blocks[NDADDR + level] = 0; 305 lastiblock[level] = -1; 306 } 307 for (i = NDADDR - 1; i > lastblock; i--) 308 oip->i_e2fs_blocks[i] = 0; 309 oip->i_flag |= IN_CHANGE | IN_UPDATE; 310 error = VOP_UPDATE(ovp, NULL, NULL, UPDATE_WAIT); 311 if (error && !allerror) 312 allerror = error; 313 314 /* 315 * Having written the new inode to disk, save its new configuration 316 * and put back the old block pointers long enough to process them. 317 * Note that we save the new block configuration so we can check it 318 * when we are done. 319 */ 320 memcpy((caddr_t)newblks, (caddr_t)&oip->i_e2fs_blocks[0], sizeof newblks); 321 memcpy((caddr_t)&oip->i_e2fs_blocks[0], (caddr_t)oldblks, sizeof oldblks); 322 oip->i_e2fs_size = osize; 323 error = vtruncbuf(ovp, lastblock + 1, 0, 0); 324 if (error && !allerror) 325 allerror = error; 326 327 /* 328 * Indirect blocks first. 329 */ 330 indir_lbn[SINGLE] = -NDADDR; 331 indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) -1; 332 indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1; 333 for (level = TRIPLE; level >= SINGLE; level--) { 334 bn = fs2h32(oip->i_e2fs_blocks[NDADDR + level]); 335 if (bn != 0) { 336 error = ext2fs_indirtrunc(oip, indir_lbn[level], 337 fsbtodb(fs, bn), lastiblock[level], level, &count); 338 if (error) 339 allerror = error; 340 blocksreleased += count; 341 if (lastiblock[level] < 0) { 342 oip->i_e2fs_blocks[NDADDR + level] = 0; 343 ext2fs_blkfree(oip, bn); 344 blocksreleased += nblocks; 345 } 346 } 347 if (lastiblock[level] >= 0) 348 goto done; 349 } 350 351 /* 352 * All whole direct blocks or frags. 353 */ 354 for (i = NDADDR - 1; i > lastblock; i--) { 355 bn = fs2h32(oip->i_e2fs_blocks[i]); 356 if (bn == 0) 357 continue; 358 oip->i_e2fs_blocks[i] = 0; 359 ext2fs_blkfree(oip, bn); 360 blocksreleased += btodb(fs->e2fs_bsize); 361 } 362 if (lastblock < 0) 363 goto done; 364 365 done: 366 #ifdef DIAGNOSTIC 367 for (level = SINGLE; level <= TRIPLE; level++) 368 if (newblks[NDADDR + level] != oip->i_e2fs_blocks[NDADDR + level]) 369 panic("itrunc1"); 370 for (i = 0; i < NDADDR; i++) 371 if (newblks[i] != oip->i_e2fs_blocks[i]) 372 panic("itrunc2"); 373 if (length == 0 && 374 (!LIST_EMPTY(&ovp->v_cleanblkhd) || !LIST_EMPTY(&ovp->v_dirtyblkhd))) 375 panic("itrunc3"); 376 #endif /* DIAGNOSTIC */ 377 /* 378 * Put back the real size. 379 */ 380 oip->i_e2fs_size = length; 381 oip->i_e2fs_nblock -= blocksreleased; 382 if (oip->i_e2fs_nblock < 0) /* sanity */ 383 oip->i_e2fs_nblock = 0; 384 oip->i_flag |= IN_CHANGE; 385 return (allerror); 386 } 387 388 /* 389 * Release blocks associated with the inode ip and stored in the indirect 390 * block bn. Blocks are free'd in LIFO order up to (but not including) 391 * lastbn. If level is greater than SINGLE, the block is an indirect block 392 * and recursive calls to indirtrunc must be used to cleanse other indirect 393 * blocks. 394 * 395 * NB: triple indirect blocks are untested. 396 */ 397 static int 398 ext2fs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) 399 struct inode *ip; 400 ufs_daddr_t lbn, lastbn; 401 ufs_daddr_t dbn; 402 int level; 403 long *countp; 404 { 405 int i; 406 struct buf *bp; 407 struct m_ext2fs *fs = ip->i_e2fs; 408 ufs_daddr_t *bap; 409 struct vnode *vp; 410 ufs_daddr_t *copy = NULL, nb, nlbn, last; 411 long blkcount, factor; 412 int nblocks, blocksreleased = 0; 413 int error = 0, allerror = 0; 414 415 /* 416 * Calculate index in current block of last 417 * block to be kept. -1 indicates the entire 418 * block so we need not calculate the index. 419 */ 420 factor = 1; 421 for (i = SINGLE; i < level; i++) 422 factor *= NINDIR(fs); 423 last = lastbn; 424 if (lastbn > 0) 425 last /= factor; 426 nblocks = btodb(fs->e2fs_bsize); 427 /* 428 * Get buffer of block pointers, zero those entries corresponding 429 * to blocks to be free'd, and update on disk copy first. Since 430 * double(triple) indirect before single(double) indirect, calls 431 * to bmap on these blocks will fail. However, we already have 432 * the on disk address, so we have to set the b_blkno field 433 * explicitly instead of letting bread do everything for us. 434 */ 435 vp = ITOV(ip); 436 bp = getblk(vp, lbn, (int)fs->e2fs_bsize, 0, 0); 437 if (bp->b_flags & (B_DONE | B_DELWRI)) { 438 /* Braces must be here in case trace evaluates to nothing. */ 439 trace(TR_BREADHIT, pack(vp, fs->e2fs_bsize), lbn); 440 } else { 441 trace(TR_BREADMISS, pack(vp, fs->e2fs_bsize), lbn); 442 curproc->p_stats->p_ru.ru_inblock++; /* pay for read */ 443 bp->b_flags |= B_READ; 444 if (bp->b_bcount > bp->b_bufsize) 445 panic("ext2fs_indirtrunc: bad buffer size"); 446 bp->b_blkno = dbn; 447 VOP_STRATEGY(bp); 448 error = biowait(bp); 449 } 450 if (error) { 451 brelse(bp); 452 *countp = 0; 453 return (error); 454 } 455 456 bap = (ufs_daddr_t *)bp->b_data; 457 if (lastbn >= 0) { 458 MALLOC(copy, ufs_daddr_t *, fs->e2fs_bsize, M_TEMP, M_WAITOK); 459 memcpy((caddr_t)copy, (caddr_t)bap, (u_int)fs->e2fs_bsize); 460 memset((caddr_t)&bap[last + 1], 0, 461 (u_int)(NINDIR(fs) - (last + 1)) * sizeof (u_int32_t)); 462 error = bwrite(bp); 463 if (error) 464 allerror = error; 465 bap = copy; 466 } 467 468 /* 469 * Recursively free totally unused blocks. 470 */ 471 for (i = NINDIR(fs) - 1, 472 nlbn = lbn + 1 - i * factor; i > last; 473 i--, nlbn += factor) { 474 nb = fs2h32(bap[i]); 475 if (nb == 0) 476 continue; 477 if (level > SINGLE) { 478 error = ext2fs_indirtrunc(ip, nlbn, fsbtodb(fs, nb), 479 (ufs_daddr_t)-1, level - 1, 480 &blkcount); 481 if (error) 482 allerror = error; 483 blocksreleased += blkcount; 484 } 485 ext2fs_blkfree(ip, nb); 486 blocksreleased += nblocks; 487 } 488 489 /* 490 * Recursively free last partial block. 491 */ 492 if (level > SINGLE && lastbn >= 0) { 493 last = lastbn % factor; 494 nb = fs2h32(bap[i]); 495 if (nb != 0) { 496 error = ext2fs_indirtrunc(ip, nlbn, fsbtodb(fs, nb), 497 last, level - 1, &blkcount); 498 if (error) 499 allerror = error; 500 blocksreleased += blkcount; 501 } 502 } 503 504 if (copy != NULL) { 505 FREE(copy, M_TEMP); 506 } else { 507 bp->b_flags |= B_INVAL; 508 brelse(bp); 509 } 510 511 *countp = blocksreleased; 512 return (allerror); 513 } 514