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