1 /* $NetBSD: ext2fs_inode.c,v 1.21 2000/11/27 08:39:53 chs 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, NULL, 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, 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 int offset, size, level; 195 long count, nblocks, blocksreleased = 0; 196 int i; 197 int error, allerror = 0; 198 off_t osize; 199 200 if (length < 0) 201 return (EINVAL); 202 203 oip = VTOI(ovp); 204 if (ovp->v_type == VLNK && 205 (oip->i_e2fs_size < ovp->v_mount->mnt_maxsymlinklen || 206 (ovp->v_mount->mnt_maxsymlinklen == 0 && 207 oip->i_e2fs_nblock == 0))) { 208 #ifdef DIAGNOSTIC 209 if (length != 0) 210 panic("ext2fs_truncate: partial truncate of symlink"); 211 #endif 212 memset((char *)&oip->i_din.e2fs_din.e2di_shortlink, 0, 213 (u_int)oip->i_e2fs_size); 214 oip->i_e2fs_size = 0; 215 oip->i_flag |= IN_CHANGE | IN_UPDATE; 216 return (VOP_UPDATE(ovp, NULL, NULL, UPDATE_WAIT)); 217 } 218 if (oip->i_e2fs_size == length) { 219 oip->i_flag |= IN_CHANGE | IN_UPDATE; 220 return (VOP_UPDATE(ovp, NULL, NULL, 0)); 221 } 222 fs = oip->i_e2fs; 223 osize = oip->i_e2fs_size; 224 /* 225 * Lengthen the size of the file. We must ensure that the 226 * last byte of the file is allocated. Since the smallest 227 * value of osize is 0, length will be at least 1. 228 */ 229 if (osize < length) { 230 #if 0 /* XXX */ 231 if (length > fs->fs_maxfilesize) 232 return (EFBIG); 233 #endif 234 ext2fs_balloc_range(ovp, length - 1, 1, ap->a_cred, 235 ap->a_flags & IO_SYNC ? B_SYNC : 0); 236 oip->i_flag |= IN_CHANGE | IN_UPDATE; 237 return (VOP_UPDATE(ovp, NULL, NULL, 1)); 238 } 239 /* 240 * Shorten the size of the file. If the file is not being 241 * truncated to a block boundry, the contents of the 242 * partial block following the end of the file must be 243 * zero'ed in case it ever become accessable again because 244 * of subsequent file growth. 245 */ 246 offset = blkoff(fs, length); 247 if (offset != 0) { 248 size = fs->e2fs_bsize; 249 250 /* XXXUBC we should handle more than just VREG */ 251 uvm_vnp_zerorange(ovp, length, size - offset); 252 } 253 oip->i_e2fs_size = length; 254 uvm_vnp_setsize(ovp, length); 255 256 /* 257 * Calculate index into inode's block list of 258 * last direct and indirect blocks (if any) 259 * which we want to keep. Lastblock is -1 when 260 * the file is truncated to 0. 261 */ 262 lastblock = lblkno(fs, length + fs->e2fs_bsize - 1) - 1; 263 lastiblock[SINGLE] = lastblock - NDADDR; 264 lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 265 lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 266 nblocks = btodb(fs->e2fs_bsize); 267 /* 268 * Update file and block pointers on disk before we start freeing 269 * blocks. If we crash before free'ing blocks below, the blocks 270 * will be returned to the free list. lastiblock values are also 271 * normalized to -1 for calls to ext2fs_indirtrunc below. 272 */ 273 memcpy((caddr_t)oldblks, (caddr_t)&oip->i_e2fs_blocks[0], sizeof oldblks); 274 for (level = TRIPLE; level >= SINGLE; level--) 275 if (lastiblock[level] < 0) { 276 oip->i_e2fs_blocks[NDADDR + level] = 0; 277 lastiblock[level] = -1; 278 } 279 for (i = NDADDR - 1; i > lastblock; i--) 280 oip->i_e2fs_blocks[i] = 0; 281 oip->i_flag |= IN_CHANGE | IN_UPDATE; 282 error = VOP_UPDATE(ovp, NULL, NULL, UPDATE_WAIT); 283 if (error && !allerror) 284 allerror = error; 285 286 /* 287 * Having written the new inode to disk, save its new configuration 288 * and put back the old block pointers long enough to process them. 289 * Note that we save the new block configuration so we can check it 290 * when we are done. 291 */ 292 293 memcpy((caddr_t)newblks, (caddr_t)&oip->i_e2fs_blocks[0], sizeof newblks); 294 memcpy((caddr_t)&oip->i_e2fs_blocks[0], (caddr_t)oldblks, sizeof oldblks); 295 oip->i_e2fs_size = osize; 296 error = vtruncbuf(ovp, lastblock + 1, 0, 0); 297 if (error && !allerror) 298 allerror = error; 299 300 /* 301 * Indirect blocks first. 302 */ 303 indir_lbn[SINGLE] = -NDADDR; 304 indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) -1; 305 indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1; 306 for (level = TRIPLE; level >= SINGLE; level--) { 307 bn = fs2h32(oip->i_e2fs_blocks[NDADDR + level]); 308 if (bn != 0) { 309 error = ext2fs_indirtrunc(oip, indir_lbn[level], 310 fsbtodb(fs, bn), lastiblock[level], level, &count); 311 if (error) 312 allerror = error; 313 blocksreleased += count; 314 if (lastiblock[level] < 0) { 315 oip->i_e2fs_blocks[NDADDR + level] = 0; 316 ext2fs_blkfree(oip, bn); 317 blocksreleased += nblocks; 318 } 319 } 320 if (lastiblock[level] >= 0) 321 goto done; 322 } 323 324 /* 325 * All whole direct blocks or frags. 326 */ 327 for (i = NDADDR - 1; i > lastblock; i--) { 328 bn = fs2h32(oip->i_e2fs_blocks[i]); 329 if (bn == 0) 330 continue; 331 oip->i_e2fs_blocks[i] = 0; 332 ext2fs_blkfree(oip, bn); 333 blocksreleased += btodb(fs->e2fs_bsize); 334 } 335 336 done: 337 #ifdef DIAGNOSTIC 338 for (level = SINGLE; level <= TRIPLE; level++) 339 if (newblks[NDADDR + level] != 340 oip->i_e2fs_blocks[NDADDR + level]) 341 panic("ext2fs_truncate1"); 342 for (i = 0; i < NDADDR; i++) 343 if (newblks[i] != oip->i_e2fs_blocks[i]) 344 panic("ext2fs_truncate2"); 345 if (length == 0 && 346 (!LIST_EMPTY(&ovp->v_cleanblkhd) || 347 !LIST_EMPTY(&ovp->v_dirtyblkhd))) 348 panic("ext2fs_truncate3"); 349 #endif /* DIAGNOSTIC */ 350 /* 351 * Put back the real size. 352 */ 353 oip->i_e2fs_size = length; 354 oip->i_e2fs_nblock -= blocksreleased; 355 if (oip->i_e2fs_nblock < 0) /* sanity */ 356 oip->i_e2fs_nblock = 0; 357 oip->i_flag |= IN_CHANGE; 358 return (allerror); 359 } 360 361 /* 362 * Release blocks associated with the inode ip and stored in the indirect 363 * block bn. Blocks are free'd in LIFO order up to (but not including) 364 * lastbn. If level is greater than SINGLE, the block is an indirect block 365 * and recursive calls to indirtrunc must be used to cleanse other indirect 366 * blocks. 367 * 368 * NB: triple indirect blocks are untested. 369 */ 370 static int 371 ext2fs_indirtrunc(ip, lbn, dbn, lastbn, level, countp) 372 struct inode *ip; 373 ufs_daddr_t lbn, lastbn; 374 ufs_daddr_t dbn; 375 int level; 376 long *countp; 377 { 378 int i; 379 struct buf *bp; 380 struct m_ext2fs *fs = ip->i_e2fs; 381 ufs_daddr_t *bap; 382 struct vnode *vp; 383 ufs_daddr_t *copy = NULL, nb, nlbn, last; 384 long blkcount, factor; 385 int nblocks, blocksreleased = 0; 386 int error = 0, allerror = 0; 387 388 /* 389 * Calculate index in current block of last 390 * block to be kept. -1 indicates the entire 391 * block so we need not calculate the index. 392 */ 393 factor = 1; 394 for (i = SINGLE; i < level; i++) 395 factor *= NINDIR(fs); 396 last = lastbn; 397 if (lastbn > 0) 398 last /= factor; 399 nblocks = btodb(fs->e2fs_bsize); 400 /* 401 * Get buffer of block pointers, zero those entries corresponding 402 * to blocks to be free'd, and update on disk copy first. Since 403 * double(triple) indirect before single(double) indirect, calls 404 * to bmap on these blocks will fail. However, we already have 405 * the on disk address, so we have to set the b_blkno field 406 * explicitly instead of letting bread do everything for us. 407 */ 408 vp = ITOV(ip); 409 bp = getblk(vp, lbn, (int)fs->e2fs_bsize, 0, 0); 410 if (bp->b_flags & (B_DONE | B_DELWRI)) { 411 /* Braces must be here in case trace evaluates to nothing. */ 412 trace(TR_BREADHIT, pack(vp, fs->e2fs_bsize), lbn); 413 } else { 414 trace(TR_BREADMISS, pack(vp, fs->e2fs_bsize), lbn); 415 curproc->p_stats->p_ru.ru_inblock++; /* pay for read */ 416 bp->b_flags |= B_READ; 417 if (bp->b_bcount > bp->b_bufsize) 418 panic("ext2fs_indirtrunc: bad buffer size"); 419 bp->b_blkno = dbn; 420 VOP_STRATEGY(bp); 421 error = biowait(bp); 422 } 423 if (error) { 424 brelse(bp); 425 *countp = 0; 426 return (error); 427 } 428 429 bap = (ufs_daddr_t *)bp->b_data; 430 if (lastbn >= 0) { 431 MALLOC(copy, ufs_daddr_t *, fs->e2fs_bsize, M_TEMP, M_WAITOK); 432 memcpy((caddr_t)copy, (caddr_t)bap, (u_int)fs->e2fs_bsize); 433 memset((caddr_t)&bap[last + 1], 0, 434 (u_int)(NINDIR(fs) - (last + 1)) * sizeof (u_int32_t)); 435 error = bwrite(bp); 436 if (error) 437 allerror = error; 438 bap = copy; 439 } 440 441 /* 442 * Recursively free totally unused blocks. 443 */ 444 for (i = NINDIR(fs) - 1, 445 nlbn = lbn + 1 - i * factor; i > last; 446 i--, nlbn += factor) { 447 nb = fs2h32(bap[i]); 448 if (nb == 0) 449 continue; 450 if (level > SINGLE) { 451 error = ext2fs_indirtrunc(ip, nlbn, fsbtodb(fs, nb), 452 (ufs_daddr_t)-1, level - 1, 453 &blkcount); 454 if (error) 455 allerror = error; 456 blocksreleased += blkcount; 457 } 458 ext2fs_blkfree(ip, nb); 459 blocksreleased += nblocks; 460 } 461 462 /* 463 * Recursively free last partial block. 464 */ 465 if (level > SINGLE && lastbn >= 0) { 466 last = lastbn % factor; 467 nb = fs2h32(bap[i]); 468 if (nb != 0) { 469 error = ext2fs_indirtrunc(ip, nlbn, fsbtodb(fs, nb), 470 last, level - 1, &blkcount); 471 if (error) 472 allerror = error; 473 blocksreleased += blkcount; 474 } 475 } 476 477 if (copy != NULL) { 478 FREE(copy, M_TEMP); 479 } else { 480 bp->b_flags |= B_INVAL; 481 brelse(bp); 482 } 483 484 *countp = blocksreleased; 485 return (allerror); 486 } 487