1 /* $OpenBSD: ext2fs_inode.c,v 1.54 2014/07/13 16:59:35 pelikan 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 <ufs/ufs/quota.h> 49 #include <ufs/ufs/inode.h> 50 #include <ufs/ufs/ufsmount.h> 51 #include <ufs/ufs/ufs_extern.h> 52 53 #include <ufs/ext2fs/ext2fs.h> 54 #include <ufs/ext2fs/ext2fs_extern.h> 55 56 static int ext2fs_indirtrunc(struct inode *, int32_t, int32_t, 57 int32_t, int, long *); 58 59 /* 60 * Get the size of an inode. 61 */ 62 u_int64_t 63 ext2fs_size(struct inode *ip) 64 { 65 u_int64_t size = ip->i_e2fs_size; 66 67 if ((ip->i_e2fs_mode & IFMT) == IFREG) 68 size |= (u_int64_t)ip->i_e2fs_size_hi << 32; 69 70 return (size); 71 } 72 73 int 74 ext2fs_setsize(struct inode *ip, u_int64_t size) 75 { 76 struct m_ext2fs *fs = ip->i_e2fs; 77 78 if (size <= fs->e2fs_maxfilesize) { 79 /* If HUGE_FILEs are off, e2fs_maxfilesize will protect us. */ 80 if ((ip->i_e2fs_mode & IFMT) == IFREG || ip->i_e2fs_mode == 0) 81 ip->i_e2fs_size_hi = size >> 32; 82 83 ip->i_e2fs_size = size; 84 return (0); 85 } 86 87 /* Linux automagically upgrades to REV1 here! */ 88 if (fs->e2fs.e2fs_rev <= E2FS_REV0) 89 return (EFBIG); 90 91 if ((fs->e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE) == 0) { 92 fs->e2fs.e2fs_features_rocompat |= EXT2F_ROCOMPAT_LARGEFILE; 93 fs->e2fs_fmod = 1; 94 } 95 return (EFBIG); 96 } 97 98 99 /* 100 * Last reference to an inode. If necessary, write or delete it. 101 */ 102 int 103 ext2fs_inactive(void *v) 104 { 105 struct vop_inactive_args *ap = v; 106 struct vnode *vp = ap->a_vp; 107 struct inode *ip = VTOI(vp); 108 struct proc *p = ap->a_p; 109 struct timespec ts; 110 int error = 0; 111 #ifdef DIAGNOSTIC 112 extern int prtactive; 113 114 if (prtactive && vp->v_usecount != 0) 115 vprint("ext2fs_inactive: pushing active", vp); 116 #endif 117 118 /* Get rid of inodes related to stale file handles. */ 119 if (ip->i_e2din == NULL || ip->i_e2fs_mode == 0 || ip->i_e2fs_dtime) 120 goto out; 121 122 error = 0; 123 if (ip->i_e2fs_nlink == 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 124 if (ext2fs_size(ip) != 0) { 125 error = ext2fs_truncate(ip, (off_t)0, 0, NOCRED); 126 } 127 getnanotime(&ts); 128 ip->i_e2fs_dtime = ts.tv_sec; 129 ip->i_flag |= IN_CHANGE | IN_UPDATE; 130 ext2fs_inode_free(ip, ip->i_number, ip->i_e2fs_mode); 131 } 132 if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) { 133 ext2fs_update(ip, 0); 134 } 135 out: 136 VOP_UNLOCK(vp, 0, p); 137 /* 138 * If we are done with the inode, reclaim it 139 * so that it can be reused immediately. 140 */ 141 if (ip->i_e2din == NULL || ip->i_e2fs_dtime != 0) 142 vrecycle(vp, p); 143 return (error); 144 } 145 146 147 /* 148 * Update the access, modified, and inode change times as specified by the 149 * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is 150 * used to specify that the inode needs to be updated but that the times have 151 * already been set. The access and modified times are taken from the second 152 * and third parameters; the inode change time is always taken from the current 153 * time. If waitfor is set, then wait for the disk write of the inode to 154 * complete. 155 */ 156 int 157 ext2fs_update(struct inode *ip, int waitfor) 158 { 159 struct m_ext2fs *fs; 160 struct buf *bp; 161 int error; 162 caddr_t cp; 163 164 if (ITOV(ip)->v_mount->mnt_flag & MNT_RDONLY) 165 return (0); 166 EXT2FS_ITIMES(ip); 167 if ((ip->i_flag & IN_MODIFIED) == 0) 168 return (0); 169 ip->i_flag &= ~IN_MODIFIED; 170 fs = ip->i_e2fs; 171 error = bread(ip->i_devvp, 172 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 173 (int)fs->e2fs_bsize, &bp); 174 if (error) { 175 brelse(bp); 176 return (error); 177 } 178 ip->i_flag &= ~(IN_MODIFIED); 179 cp = (caddr_t)bp->b_data + 180 (ino_to_fsbo(fs, ip->i_number) * EXT2_DINODE_SIZE(fs)); 181 182 /* 183 * See note about 16-bit UID/GID limitation in ext2fs_vget(). Now 184 * that we are about to write the inode, construct the split UID and 185 * GID fields out of the two 32-bit fields we kept in memory. 186 */ 187 ip->i_e2fs_uid_low = (u_int16_t)ip->i_e2fs_uid; 188 ip->i_e2fs_gid_low = (u_int16_t)ip->i_e2fs_gid; 189 ip->i_e2fs_uid_high = ip->i_e2fs_uid >> 16; 190 ip->i_e2fs_gid_high = ip->i_e2fs_gid >> 16; 191 192 e2fs_isave(ip->i_e2din, (struct ext2fs_dinode *)cp); 193 if (waitfor) 194 return (bwrite(bp)); 195 else { 196 bdwrite(bp); 197 return (0); 198 } 199 } 200 201 #define SINGLE 0 /* index of single indirect block */ 202 #define DOUBLE 1 /* index of double indirect block */ 203 #define TRIPLE 2 /* index of triple indirect block */ 204 /* 205 * Truncate the inode oip to at most length size, freeing the 206 * disk blocks. 207 */ 208 int 209 ext2fs_truncate(struct inode *oip, off_t length, int flags, struct ucred *cred) 210 { 211 struct vnode *ovp = ITOV(oip); 212 int32_t lastblock; 213 int32_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR]; 214 int32_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR]; 215 struct m_ext2fs *fs; 216 struct buf *bp; 217 int offset, size, level; 218 long count, nblocks, vflags, blocksreleased = 0; 219 int i; 220 int aflags, error, allerror; 221 off_t osize; 222 223 if (length < 0) 224 return (EINVAL); 225 226 if (ovp->v_type != VREG && 227 ovp->v_type != VDIR && 228 ovp->v_type != VLNK) 229 return (0); 230 231 if (ovp->v_type == VLNK && 232 (ext2fs_size(oip) < ovp->v_mount->mnt_maxsymlinklen || 233 (ovp->v_mount->mnt_maxsymlinklen == 0 && 234 oip->i_e2fs_nblock == 0))) { 235 #ifdef DIAGNOSTIC 236 if (length != 0) 237 panic("ext2fs_truncate: partial truncate of symlink"); 238 #endif 239 memset(&oip->i_e2din->e2di_shortlink, 0, ext2fs_size(oip)); 240 (void)ext2fs_setsize(oip, 0); 241 oip->i_flag |= IN_CHANGE | IN_UPDATE; 242 return (ext2fs_update(oip, 1)); 243 } 244 245 if (ext2fs_size(oip) == length) { 246 oip->i_flag |= IN_CHANGE | IN_UPDATE; 247 return (ext2fs_update(oip, 0)); 248 } 249 fs = oip->i_e2fs; 250 osize = ext2fs_size(oip); 251 /* 252 * Lengthen the size of the file. We must ensure that the 253 * last byte of the file is allocated. Since the smallest 254 * value of osize is 0, length will be at least 1. 255 */ 256 if (osize < length) { 257 #if 0 /* XXX */ 258 if (length > fs->fs_maxfilesize) 259 return (EFBIG); 260 #endif 261 offset = blkoff(fs, length - 1); 262 lbn = lblkno(fs, length - 1); 263 aflags = B_CLRBUF; 264 if (flags & IO_SYNC) 265 aflags |= B_SYNC; 266 error = ext2fs_buf_alloc(oip, lbn, offset + 1, cred, &bp, 267 aflags); 268 if (error) 269 return (error); 270 (void)ext2fs_setsize(oip, length); 271 uvm_vnp_setsize(ovp, length); 272 uvm_vnp_uncache(ovp); 273 if (aflags & B_SYNC) 274 bwrite(bp); 275 else 276 bawrite(bp); 277 oip->i_flag |= IN_CHANGE | IN_UPDATE; 278 return (ext2fs_update(oip, 1)); 279 } 280 /* 281 * Shorten the size of the file. If the file is not being 282 * truncated to a block boundry, the contents of the 283 * partial block following the end of the file must be 284 * zero'ed in case it ever become accessible again because 285 * of subsequent file growth. 286 */ 287 offset = blkoff(fs, length); 288 if (offset == 0) { 289 (void)ext2fs_setsize(oip, length); 290 } else { 291 lbn = lblkno(fs, length); 292 aflags = B_CLRBUF; 293 if (flags & IO_SYNC) 294 aflags |= B_SYNC; 295 error = ext2fs_buf_alloc(oip, lbn, offset, cred, &bp, 296 aflags); 297 if (error) 298 return (error); 299 (void)ext2fs_setsize(oip, length); 300 size = fs->e2fs_bsize; 301 uvm_vnp_setsize(ovp, length); 302 uvm_vnp_uncache(ovp); 303 memset(bp->b_data + offset, 0, size - offset); 304 bp->b_bcount = size; 305 if (aflags & B_SYNC) 306 bwrite(bp); 307 else 308 bawrite(bp); 309 } 310 /* 311 * Calculate index into inode's block list of 312 * last direct and indirect blocks (if any) 313 * which we want to keep. Lastblock is -1 when 314 * the file is truncated to 0. 315 */ 316 lastblock = lblkno(fs, length + fs->e2fs_bsize - 1) - 1; 317 lastiblock[SINGLE] = lastblock - NDADDR; 318 lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 319 lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 320 nblocks = btodb(fs->e2fs_bsize); 321 /* 322 * Update file and block pointers on disk before we start freeing 323 * blocks. If we crash before free'ing blocks below, the blocks 324 * will be returned to the free list. lastiblock values are also 325 * normalized to -1 for calls to ext2fs_indirtrunc below. 326 */ 327 memcpy(oldblks, &oip->i_e2fs_blocks[0], sizeof(oldblks)); 328 for (level = TRIPLE; level >= SINGLE; level--) 329 if (lastiblock[level] < 0) { 330 oip->i_e2fs_blocks[NDADDR + level] = 0; 331 lastiblock[level] = -1; 332 } 333 for (i = NDADDR - 1; i > lastblock; i--) 334 oip->i_e2fs_blocks[i] = 0; 335 oip->i_flag |= IN_CHANGE | IN_UPDATE; 336 if ((error = ext2fs_update(oip, 1)) != 0) 337 allerror = error; 338 /* 339 * Having written the new inode to disk, save its new configuration 340 * and put back the old block pointers long enough to process them. 341 * Note that we save the new block configuration so we can check it 342 * when we are done. 343 */ 344 memcpy(newblks, &oip->i_e2fs_blocks[0], sizeof(newblks)); 345 memcpy(&oip->i_e2fs_blocks[0], oldblks, sizeof(oldblks)); 346 (void)ext2fs_setsize(oip, osize); 347 vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA; 348 allerror = vinvalbuf(ovp, vflags, cred, curproc, 0, 0); 349 350 /* 351 * Indirect blocks first. 352 */ 353 indir_lbn[SINGLE] = -NDADDR; 354 indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) -1; 355 indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1; 356 for (level = TRIPLE; level >= SINGLE; level--) { 357 bn = letoh32(oip->i_e2fs_blocks[NDADDR + level]); 358 if (bn != 0) { 359 error = ext2fs_indirtrunc(oip, indir_lbn[level], 360 fsbtodb(fs, bn), lastiblock[level], level, &count); 361 if (error) 362 allerror = error; 363 blocksreleased += count; 364 if (lastiblock[level] < 0) { 365 oip->i_e2fs_blocks[NDADDR + level] = 0; 366 ext2fs_blkfree(oip, bn); 367 blocksreleased += nblocks; 368 } 369 } 370 if (lastiblock[level] >= 0) 371 goto done; 372 } 373 374 /* 375 * All whole direct blocks or frags. 376 */ 377 for (i = NDADDR - 1; i > lastblock; i--) { 378 bn = letoh32(oip->i_e2fs_blocks[i]); 379 if (bn == 0) 380 continue; 381 oip->i_e2fs_blocks[i] = 0; 382 ext2fs_blkfree(oip, bn); 383 blocksreleased += btodb(fs->e2fs_bsize); 384 } 385 386 done: 387 #ifdef DIAGNOSTIC 388 for (level = SINGLE; level <= TRIPLE; level++) 389 if (newblks[NDADDR + level] != 390 oip->i_e2fs_blocks[NDADDR + level]) 391 panic("ext2fs_truncate1"); 392 for (i = 0; i < NDADDR; i++) 393 if (newblks[i] != oip->i_e2fs_blocks[i]) 394 panic("ext2fs_truncate2"); 395 if (length == 0 && 396 (!LIST_EMPTY(&ovp->v_cleanblkhd) || 397 !LIST_EMPTY(&ovp->v_dirtyblkhd))) 398 panic("ext2fs_truncate3"); 399 #endif /* DIAGNOSTIC */ 400 /* 401 * Put back the real size. 402 */ 403 (void)ext2fs_setsize(oip, length); 404 if (blocksreleased >= oip->i_e2fs_nblock) 405 oip->i_e2fs_nblock = 0; 406 else 407 oip->i_e2fs_nblock -= blocksreleased; 408 oip->i_flag |= IN_CHANGE; 409 return (allerror); 410 } 411 412 /* 413 * Release blocks associated with the inode ip and stored in the indirect 414 * block bn. Blocks are free'd in LIFO order up to (but not including) 415 * lastbn. If level is greater than SINGLE, the block is an indirect block 416 * and recursive calls to indirtrunc must be used to cleanse other indirect 417 * blocks. 418 * 419 * NB: triple indirect blocks are untested. 420 */ 421 static int 422 ext2fs_indirtrunc(struct inode *ip, int32_t lbn, int32_t dbn, int32_t lastbn, int level, long *countp) 423 { 424 int i; 425 struct buf *bp; 426 struct m_ext2fs *fs = ip->i_e2fs; 427 int32_t *bap; 428 struct vnode *vp; 429 int32_t *copy = NULL, nb, nlbn, last; 430 long blkcount, factor; 431 int nblocks, blocksreleased = 0; 432 int error = 0, allerror = 0; 433 434 /* 435 * Calculate index in current block of last 436 * block to be kept. -1 indicates the entire 437 * block so we need not calculate the index. 438 */ 439 factor = 1; 440 for (i = SINGLE; i < level; i++) 441 factor *= NINDIR(fs); 442 last = lastbn; 443 if (lastbn > 0) 444 last /= factor; 445 nblocks = btodb(fs->e2fs_bsize); 446 /* 447 * Get buffer of block pointers, zero those entries corresponding 448 * to blocks to be free'd, and update on disk copy first. Since 449 * double(triple) indirect before single(double) indirect, calls 450 * to bmap on these blocks will fail. However, we already have 451 * the on disk address, so we have to set the b_blkno field 452 * explicitly instead of letting bread do everything for us. 453 */ 454 vp = ITOV(ip); 455 bp = getblk(vp, lbn, (int)fs->e2fs_bsize, 0, 0); 456 if (!(bp->b_flags & (B_DONE | B_DELWRI))) { 457 curproc->p_ru.ru_inblock++; /* pay for read */ 458 bcstats.pendingreads++; 459 bcstats.numreads++; 460 bp->b_flags |= B_READ; 461 if (bp->b_bcount > bp->b_bufsize) 462 panic("ext2fs_indirtrunc: bad buffer size"); 463 bp->b_blkno = dbn; 464 VOP_STRATEGY(bp); 465 error = biowait(bp); 466 } 467 if (error) { 468 brelse(bp); 469 *countp = 0; 470 return (error); 471 } 472 473 bap = (int32_t *)bp->b_data; 474 if (lastbn >= 0) { 475 copy = malloc(fs->e2fs_bsize, M_TEMP, M_WAITOK); 476 memcpy(copy, bap, fs->e2fs_bsize); 477 memset(&bap[last + 1], 0, 478 (NINDIR(fs) - (last + 1)) * sizeof(u_int32_t)); 479 error = bwrite(bp); 480 if (error) 481 allerror = error; 482 bap = copy; 483 } 484 485 /* 486 * Recursively free totally unused blocks. 487 */ 488 for (i = NINDIR(fs) - 1, 489 nlbn = lbn + 1 - i * factor; i > last; 490 i--, nlbn += factor) { 491 nb = letoh32(bap[i]); 492 if (nb == 0) 493 continue; 494 if (level > SINGLE) { 495 error = ext2fs_indirtrunc(ip, nlbn, fsbtodb(fs, nb), 496 (int32_t)-1, level - 1, 497 &blkcount); 498 if (error) 499 allerror = error; 500 blocksreleased += blkcount; 501 } 502 ext2fs_blkfree(ip, nb); 503 blocksreleased += nblocks; 504 } 505 506 /* 507 * Recursively free last partial block. 508 */ 509 if (level > SINGLE && lastbn >= 0) { 510 last = lastbn % factor; 511 nb = letoh32(bap[i]); 512 if (nb != 0) { 513 error = ext2fs_indirtrunc(ip, nlbn, fsbtodb(fs, nb), 514 last, level - 1, &blkcount); 515 if (error) 516 allerror = error; 517 blocksreleased += blkcount; 518 } 519 } 520 521 if (copy != NULL) { 522 free(copy, M_TEMP, fs->e2fs_bsize); 523 } else { 524 bp->b_flags |= B_INVAL; 525 brelse(bp); 526 } 527 528 *countp = blocksreleased; 529 return (allerror); 530 } 531