1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)ffs_inode.c 7.61 (Berkeley) 10/07/92 8 */ 9 10 #include <sys/param.h> 11 #include <sys/systm.h> 12 #include <sys/mount.h> 13 #include <sys/proc.h> 14 #include <sys/file.h> 15 #include <sys/buf.h> 16 #include <sys/vnode.h> 17 #include <sys/kernel.h> 18 #include <sys/malloc.h> 19 20 #include <vm/vm.h> 21 22 #include <ufs/ufs/quota.h> 23 #include <ufs/ufs/inode.h> 24 #include <ufs/ufs/ufsmount.h> 25 #include <ufs/ufs/ufs_extern.h> 26 27 #include <ufs/ffs/fs.h> 28 #include <ufs/ffs/ffs_extern.h> 29 30 static int ffs_indirtrunc __P((struct inode *, daddr_t, daddr_t, int, long *)); 31 32 int 33 ffs_init() 34 { 35 return (ufs_init()); 36 } 37 38 /* 39 * Update the access, modified, and inode change times as specified 40 * by the IACC, IUPD, and ICHG flags respectively. The IMOD flag 41 * is used to specify that the inode needs to be updated but that 42 * the times have already been set. The access and modified times 43 * are taken from the second and third parameters; the inode change 44 * time is always taken from the current time. If waitfor is set, 45 * then wait for the disk write of the inode to complete. 46 */ 47 int 48 ffs_update(ap) 49 struct vop_update_args /* { 50 struct vnode *a_vp; 51 struct timeval *a_ta; 52 struct timeval *a_tm; 53 int a_waitfor; 54 } */ *ap; 55 { 56 struct buf *bp; 57 struct inode *ip; 58 struct dinode *dp; 59 register struct fs *fs; 60 int error; 61 62 if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) 63 return (0); 64 ip = VTOI(ap->a_vp); 65 if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) 66 return (0); 67 if (ip->i_flag&IACC) 68 ip->i_atime.ts_sec = ap->a_ta->tv_sec; 69 if (ip->i_flag&IUPD) { 70 ip->i_mtime.ts_sec = ap->a_tm->tv_sec; 71 ip->i_modrev++; 72 } 73 if (ip->i_flag&ICHG) 74 ip->i_ctime.ts_sec = time.tv_sec; 75 ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 76 fs = ip->i_fs; 77 /* 78 * Ensure that uid and gid are correct. This is a temporary 79 * fix until fsck has been changed to do the update. 80 */ 81 if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 82 ip->i_din.di_ouid = ip->i_uid; /* XXX */ 83 ip->i_din.di_ogid = ip->i_gid; /* XXX */ 84 } /* XXX */ 85 if (error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)), 86 (int)fs->fs_bsize, NOCRED, &bp)) { 87 brelse(bp); 88 return (error); 89 } 90 dp = bp->b_un.b_dino + itoo(fs, ip->i_number); 91 *dp = ip->i_din; 92 if (ap->a_waitfor) 93 return (bwrite(bp)); 94 else { 95 bdwrite(bp); 96 return (0); 97 } 98 } 99 100 #define SINGLE 0 /* index of single indirect block */ 101 #define DOUBLE 1 /* index of double indirect block */ 102 #define TRIPLE 2 /* index of triple indirect block */ 103 /* 104 * Truncate the inode ip to at most length size. Free affected disk 105 * blocks -- the blocks of the file are removed in reverse order. 106 */ 107 ffs_truncate(ap) 108 struct vop_truncate_args /* { 109 struct vnode *a_vp; 110 off_t a_length; 111 int a_flags; 112 struct ucred *a_cred; 113 struct proc *a_p; 114 } */ *ap; 115 { 116 register struct vnode *ovp = ap->a_vp; 117 register daddr_t lastblock; 118 register struct inode *oip; 119 daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR]; 120 off_t length = ap->a_length; 121 register struct fs *fs; 122 register struct inode *ip; 123 struct buf *bp; 124 int offset, size, level; 125 long count, nblocks, vflags, blocksreleased = 0; 126 struct timeval tv; 127 register int i; 128 int aflags, error, allerror; 129 struct inode tip; 130 off_t osize; 131 132 oip = VTOI(ovp); 133 tv = time; 134 if (ovp->v_type == VLNK && ovp->v_mount->mnt_maxsymlinklen > 0) { 135 #ifdef DIAGNOSTIC 136 if (length != 0) 137 panic("ffs_truncate: partial truncate of symlink"); 138 #endif 139 bzero((char *)&oip->i_shortlink, (u_int)oip->i_size); 140 oip->i_size = 0; 141 oip->i_flag |= ICHG|IUPD; 142 return (VOP_UPDATE(ovp, &tv, &tv, 1)); 143 } 144 if (oip->i_size <= length) { 145 oip->i_flag |= ICHG|IUPD; 146 return (VOP_UPDATE(ovp, &tv, &tv, 1)); 147 } 148 vnode_pager_setsize(ovp, (u_long)length); 149 /* 150 * Calculate index into inode's block list of 151 * last direct and indirect blocks (if any) 152 * which we want to keep. Lastblock is -1 when 153 * the file is truncated to 0. 154 */ 155 fs = oip->i_fs; 156 lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 157 lastiblock[SINGLE] = lastblock - NDADDR; 158 lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 159 lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 160 nblocks = btodb(fs->fs_bsize); 161 /* 162 * Update the size of the file. If the file is not being 163 * truncated to a block boundry, the contents of the 164 * partial block following the end of the file must be 165 * zero'ed in case it ever become accessable again because 166 * of subsequent file growth. 167 */ 168 osize = oip->i_size; 169 offset = blkoff(fs, length); 170 if (offset == 0) { 171 oip->i_size = length; 172 } else { 173 lbn = lblkno(fs, length); 174 aflags = B_CLRBUF; 175 if (ap->a_flags & IO_SYNC) 176 aflags |= B_SYNC; 177 #ifdef QUOTA 178 if (error = getinoquota(oip)) 179 return (error); 180 #endif 181 if (error = ffs_balloc(oip, lbn, offset, ap->a_cred, &bp, aflags)) 182 return (error); 183 oip->i_size = length; 184 size = blksize(fs, oip, lbn); 185 (void) vnode_pager_uncache(ovp); 186 bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 187 allocbuf(bp, size); 188 if (ap->a_flags & IO_SYNC) 189 bwrite(bp); 190 else 191 bdwrite(bp); 192 } 193 /* 194 * Update file and block pointers on disk before we start freeing 195 * blocks. If we crash before free'ing blocks below, the blocks 196 * will be returned to the free list. lastiblock values are also 197 * normalized to -1 for calls to ffs_indirtrunc below. 198 */ 199 tip = *oip; 200 tip.i_size = osize; 201 for (level = TRIPLE; level >= SINGLE; level--) 202 if (lastiblock[level] < 0) { 203 oip->i_ib[level] = 0; 204 lastiblock[level] = -1; 205 } 206 for (i = NDADDR - 1; i > lastblock; i--) 207 oip->i_db[i] = 0; 208 oip->i_flag |= ICHG|IUPD; 209 vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA; 210 allerror = vinvalbuf(ovp, vflags, ap->a_cred, ap->a_p); 211 if (error = VOP_UPDATE(ovp, &tv, &tv, MNT_WAIT)) 212 allerror = error; 213 214 /* 215 * Indirect blocks first. 216 */ 217 indir_lbn[SINGLE] = -NDADDR; 218 indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1; 219 indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1; 220 ip = &tip; 221 ITOV(ip)->v_data = ip; 222 for (level = TRIPLE; level >= SINGLE; level--) { 223 bn = ip->i_ib[level]; 224 if (bn != 0) { 225 error = ffs_indirtrunc(ip, 226 indir_lbn[level], lastiblock[level], level, &count); 227 if (error) 228 allerror = error; 229 blocksreleased += count; 230 if (lastiblock[level] < 0) { 231 ip->i_ib[level] = 0; 232 ffs_blkfree(ip, bn, fs->fs_bsize); 233 blocksreleased += nblocks; 234 } 235 } 236 if (lastiblock[level] >= 0) 237 goto done; 238 } 239 240 /* 241 * All whole direct blocks or frags. 242 */ 243 for (i = NDADDR - 1; i > lastblock; i--) { 244 register long bsize; 245 246 bn = ip->i_db[i]; 247 if (bn == 0) 248 continue; 249 ip->i_db[i] = 0; 250 bsize = blksize(fs, ip, i); 251 ffs_blkfree(ip, bn, bsize); 252 blocksreleased += btodb(bsize); 253 } 254 if (lastblock < 0) 255 goto done; 256 257 /* 258 * Finally, look for a change in size of the 259 * last direct block; release any frags. 260 */ 261 bn = ip->i_db[lastblock]; 262 if (bn != 0) { 263 long oldspace, newspace; 264 265 /* 266 * Calculate amount of space we're giving 267 * back as old block size minus new block size. 268 */ 269 oldspace = blksize(fs, ip, lastblock); 270 ip->i_size = length; 271 newspace = blksize(fs, ip, lastblock); 272 if (newspace == 0) 273 panic("itrunc: newspace"); 274 if (oldspace - newspace > 0) { 275 /* 276 * Block number of space to be free'd is 277 * the old block # plus the number of frags 278 * required for the storage we're keeping. 279 */ 280 bn += numfrags(fs, newspace); 281 ffs_blkfree(ip, bn, oldspace - newspace); 282 blocksreleased += btodb(oldspace - newspace); 283 } 284 } 285 done: 286 ITOV(ip)->v_data = oip; 287 /* BEGIN PARANOIA */ 288 for (level = SINGLE; level <= TRIPLE; level++) 289 if (ip->i_ib[level] != oip->i_ib[level]) 290 panic("itrunc1"); 291 for (i = 0; i < NDADDR; i++) 292 if (ip->i_db[i] != oip->i_db[i]) 293 panic("itrunc2"); 294 /* END PARANOIA */ 295 oip->i_blocks -= blocksreleased; 296 if (oip->i_blocks < 0) /* sanity */ 297 oip->i_blocks = 0; 298 oip->i_flag |= ICHG; 299 #ifdef QUOTA 300 if (!getinoquota(oip)) 301 (void) chkdq(oip, -blocksreleased, NOCRED, 0); 302 #endif 303 return (allerror); 304 } 305 306 /* 307 * Release blocks associated with the inode ip and stored in the indirect 308 * block bn. Blocks are free'd in LIFO order up to (but not including) 309 * lastbn. If level is greater than SINGLE, the block is an indirect block 310 * and recursive calls to indirtrunc must be used to cleanse other indirect 311 * blocks. 312 * 313 * NB: triple indirect blocks are untested. 314 */ 315 static int 316 ffs_indirtrunc(ip, lbn, lastbn, level, countp) 317 register struct inode *ip; 318 daddr_t lbn, lastbn; 319 int level; 320 long *countp; 321 { 322 register int i; 323 struct buf *bp; 324 register struct fs *fs = ip->i_fs; 325 register daddr_t *bap; 326 daddr_t *copy, nb, nlbn, last; 327 long blkcount, factor; 328 int nblocks, blocksreleased = 0; 329 int error, allerror = 0; 330 331 /* 332 * Calculate index in current block of last 333 * block to be kept. -1 indicates the entire 334 * block so we need not calculate the index. 335 */ 336 factor = 1; 337 for (i = SINGLE; i < level; i++) 338 factor *= NINDIR(fs); 339 last = lastbn; 340 if (lastbn > 0) 341 last /= factor; 342 nblocks = btodb(fs->fs_bsize); 343 /* 344 * Get buffer of block pointers, zero those 345 * entries corresponding to blocks to be free'd, 346 * and update on disk copy first. 347 */ 348 error = bread(ITOV(ip), lbn, (int)fs->fs_bsize, NOCRED, &bp); 349 if (error) { 350 brelse(bp); 351 *countp = 0; 352 return (error); 353 } 354 bap = bp->b_un.b_daddr; 355 MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); 356 bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); 357 bzero((caddr_t)&bap[last + 1], 358 (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 359 if (last == -1) 360 bp->b_flags |= B_INVAL; 361 error = bwrite(bp); 362 if (error) 363 allerror = error; 364 bap = copy; 365 366 /* 367 * Recursively free totally unused blocks. 368 */ 369 for (i = NINDIR(fs) - 1, nlbn = lbn + 1 - i * factor; i > last; 370 i--, nlbn -= factor) { 371 nb = bap[i]; 372 if (nb == 0) 373 continue; 374 if (level > SINGLE) { 375 if (error = ffs_indirtrunc(ip, 376 nlbn, (daddr_t)-1, level - 1, &blkcount)) 377 allerror = error; 378 blocksreleased += blkcount; 379 } 380 ffs_blkfree(ip, nb, fs->fs_bsize); 381 blocksreleased += nblocks; 382 } 383 384 /* 385 * Recursively free last partial block. 386 */ 387 if (level > SINGLE && lastbn >= 0) { 388 last = lastbn % factor; 389 nb = bap[i]; 390 if (nb != 0) { 391 if (error = 392 ffs_indirtrunc(ip, nlbn, last, level - 1, 393 &blkcount)) 394 allerror = error; 395 blocksreleased += blkcount; 396 } 397 } 398 FREE(copy, M_TEMP); 399 *countp = blocksreleased; 400 return (allerror); 401 } 402