1 /* 2 * Copyright (c) 1986, 1989, 1991 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)lfs_inode.c 7.64 (Berkeley) 05/14/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/lfs/lfs.h> 28 #include <ufs/lfs/lfs_extern.h> 29 30 static struct dinode *lfs_ifind __P((struct lfs *, ino_t, struct dinode *)); 31 32 int 33 lfs_init() 34 { 35 #ifdef VERBOSE 36 printf("lfs_init\n"); 37 #endif 38 return (ufs_init()); 39 } 40 41 /* 42 * Look up an LFS dinode number to find its incore vnode. If not already 43 * in core, read it in from the specified device. Return the inode locked. 44 * Detection and handling of mount points must be done by the calling routine. 45 */ 46 int 47 lfs_vget (ap) 48 struct vop_vget_args *ap; 49 #define mntp (ap->a_mp) 50 #define ino (ap->a_ino) 51 #define vpp (ap->a_vpp) 52 { 53 register struct lfs *fs; 54 register struct inode *ip; 55 struct buf *bp; 56 struct ifile *ifp; 57 struct vnode *vp; 58 struct ufsmount *ump; 59 daddr_t daddr; 60 dev_t dev; 61 int error; 62 63 #ifdef VERBOSE 64 printf("lfs_vget\n"); 65 #endif 66 ump = VFSTOUFS(mntp); 67 dev = ump->um_dev; 68 if ((*vpp = ufs_ihashget(dev, ino)) != NULL) 69 return (0); 70 71 /* Translate the inode number to a disk address. */ 72 fs = ump->um_lfs; 73 if (ino == LFS_IFILE_INUM) 74 daddr = fs->lfs_idaddr; 75 else { 76 LFS_IENTRY(ifp, fs, ino, bp); 77 daddr = ifp->if_daddr; 78 brelse(bp); 79 if (daddr == LFS_UNUSED_DADDR) 80 return (ENOENT); 81 } 82 83 /* Allocate new vnode/inode. */ 84 if (error = lfs_vcreate(mntp, ino, &vp)) { 85 *vpp = NULL; 86 return (error); 87 } 88 89 /* 90 * Put it onto its hash chain and lock it so that other requests for 91 * this inode will block if they arrive while we are sleeping waiting 92 * for old data structures to be purged or for the contents of the 93 * disk portion of this inode to be read. 94 */ 95 ip = VTOI(vp); 96 ufs_ihashins(ip); 97 98 /* 99 * XXX 100 * This may not need to be here, logically it should go down with 101 * the i_devvp initialization. 102 * Ask Kirk. 103 */ 104 ip->i_lfs = ump->um_lfs; 105 106 /* Read in the disk contents for the inode, copy into the inode. */ 107 if (error = 108 bread(ump->um_devvp, daddr, (int)fs->lfs_bsize, NOCRED, &bp)) { 109 /* 110 * The inode does not contain anything useful, so it 111 * would be misleading to leave it on its hash chain. 112 * Iput() will return it to the free list. 113 */ 114 remque(ip); 115 ip->i_forw = ip; 116 ip->i_back = ip; 117 118 /* Unlock and discard unneeded inode. */ 119 ufs_iput(ip); 120 brelse(bp); 121 *vpp = NULL; 122 return (error); 123 } 124 ip->i_din = *lfs_ifind(fs, ino, bp->b_un.b_dino); 125 brelse(bp); 126 127 /* 128 * Initialize the vnode from the inode, check for aliases. In all 129 * cases re-init ip, the underlying vnode/inode may have changed. 130 */ 131 if (error = ufs_vinit(mntp, lfs_specop_p, LFS_FIFOOPS, &vp)) { 132 ufs_iput(ip); 133 *vpp = NULL; 134 return (error); 135 } 136 /* 137 * Finish inode initialization now that aliasing has been resolved. 138 */ 139 ip->i_devvp = ump->um_devvp; 140 VREF(ip->i_devvp); 141 *vpp = vp; 142 return (0); 143 } 144 #undef mntp 145 #undef ino 146 #undef vpp 147 148 /* Search a block for a specific dinode. */ 149 static struct dinode * 150 lfs_ifind(fs, ino, dip) 151 struct lfs *fs; 152 ino_t ino; 153 register struct dinode *dip; 154 { 155 register int cnt; 156 157 #ifdef VERBOSE 158 printf("lfs_ifind: inode %d\n", ino); 159 #endif 160 for (cnt = INOPB(fs); cnt--; ++dip) 161 if (dip->di_inum == ino) 162 return (dip); 163 164 panic("lfs_ifind: dinode %u not found", ino); 165 /* NOTREACHED */ 166 } 167 168 int 169 lfs_update (ap) 170 struct vop_update_args *ap; 171 #define vp (ap->a_vp) 172 #define ta (ap->a_ta) 173 #define tm (ap->a_tm) 174 #define waitfor (ap->a_waitfor) 175 { 176 struct inode *ip; 177 178 #ifdef VERBOSE 179 printf("lfs_update\n"); 180 #endif 181 if (vp->v_mount->mnt_flag & MNT_RDONLY) 182 return (0); 183 ip = VTOI(vp); 184 if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) 185 return (0); 186 if (ip->i_flag&IACC) 187 ip->i_atime.tv_sec = ta->tv_sec; 188 if (ip->i_flag&IUPD) { 189 ip->i_mtime.tv_sec = tm->tv_sec; 190 INCRQUAD((ip)->i_modrev); 191 } 192 if (ip->i_flag&ICHG) 193 ip->i_ctime.tv_sec = time.tv_sec; 194 ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 195 196 /* Push back the vnode and any dirty blocks it may have. */ 197 return (waitfor ? lfs_vflush(vp) : 0); 198 } 199 #undef vp 200 #undef ta 201 #undef tm 202 #undef waitfor 203 204 /* Update segment usage information when removing a block. */ 205 #define UPDATE_SEGUSE \ 206 if (lastseg != -1) { \ 207 LFS_SEGENTRY(sup, fs, lastseg, sup_bp); \ 208 sup->su_nbytes -= num << fs->lfs_bshift; \ 209 LFS_UBWRITE(sup_bp); \ 210 blocksreleased += num; \ 211 } 212 213 #define SEGDEC { \ 214 if (daddr != UNASSIGNED) { \ 215 if (lastseg != (seg = datosn(fs, daddr))) { \ 216 UPDATE_SEGUSE; \ 217 num = 1; \ 218 lastseg = seg; \ 219 } else \ 220 ++num; \ 221 } \ 222 } 223 224 /* 225 * Truncate the inode ip to at most length size. Update segment usage 226 * table information. 227 */ 228 /* ARGSUSED */ 229 int 230 lfs_truncate (ap) 231 struct vop_truncate_args *ap; 232 #define vp (ap->a_vp) 233 #define length (ap->a_length) 234 #define flags (ap->a_flags) 235 #define cred (ap->a_cred) 236 { 237 USES_VOP_UPDATE; 238 register INDIR *inp; 239 register int i; 240 register daddr_t *daddrp; 241 struct buf *bp, *sup_bp; 242 struct ifile *ifp; 243 struct inode *ip; 244 struct lfs *fs; 245 INDIR a[NIADDR + 2], a_end[NIADDR + 2]; 246 SEGUSE *sup; 247 daddr_t daddr, lastblock, lbn, olastblock; 248 long off, blocksreleased; 249 int error, depth, lastseg, num, offset, seg, size; 250 251 #ifdef VERBOSE 252 printf("lfs_truncate\n"); 253 #endif 254 vnode_pager_setsize(vp, (u_long)length); 255 256 ip = VTOI(vp); 257 fs = ip->i_lfs; 258 259 /* If truncating the file to 0, update the version number. */ 260 if (length == 0) { 261 LFS_IENTRY(ifp, fs, ip->i_number, bp); 262 ++ifp->if_version; 263 LFS_UBWRITE(bp); 264 } 265 266 /* If length is larger than the file, just update the times. */ 267 if (ip->i_size <= length) { 268 ip->i_flag |= ICHG|IUPD; 269 return (VOP_UPDATE(vp, &time, &time, 1)); 270 } 271 272 /* 273 * Calculate index into inode's block list of last direct and indirect 274 * blocks (if any) which we want to keep. Lastblock is 0 when the 275 * file is truncated to 0. 276 */ 277 lastblock = lblkno(fs, length + fs->lfs_bsize - 1); 278 olastblock = lblkno(fs, ip->i_size + fs->lfs_bsize - 1) - 1; 279 280 /* 281 * Update the size of the file. If the file is not being truncated to 282 * a block boundry, the contents of the partial block following the end 283 * of the file must be zero'ed in case it ever become accessable again 284 * because of subsequent file growth. 285 */ 286 offset = blkoff(fs, length); 287 if (offset == 0) 288 ip->i_size = length; 289 else { 290 lbn = lblkno(fs, length); 291 #ifdef QUOTA 292 if (error = getinoquota(ip)) 293 return (error); 294 #endif 295 if (error = bread(vp, lbn, fs->lfs_bsize, NOCRED, &bp)) 296 return (error); 297 ip->i_size = length; 298 size = blksize(fs); 299 (void)vnode_pager_uncache(vp); 300 bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 301 allocbuf(bp, size); 302 LFS_UBWRITE(bp); 303 } 304 /* 305 * Modify sup->su_nbyte counters for each deleted block; keep track 306 * of number of blocks removed for ip->i_blocks. 307 */ 308 blocksreleased = 0; 309 num = 0; 310 lastseg = -1; 311 312 for (lbn = olastblock; lbn >= lastblock;) { 313 lfs_bmaparray(vp, lbn, &daddr, a, &depth); 314 if (lbn == olastblock) 315 for (i = NIADDR + 2; i--;) 316 a_end[i] = a[i]; 317 switch (depth) { 318 case 0: /* Direct block. */ 319 daddr = ip->i_db[lbn]; 320 SEGDEC; 321 ip->i_db[lbn] = 0; 322 --lbn; 323 break; 324 #ifdef DIAGNOSTIC 325 case 1: /* An indirect block. */ 326 panic("lfs_truncate: lfs_bmaparray returned depth 1"); 327 /* NOTREACHED */ 328 #endif 329 default: /* Chain of indirect blocks. */ 330 inp = a + --depth; 331 if (inp->in_off > 0 && lbn != lastblock) { 332 lbn -= inp->in_off < lbn - lastblock ? 333 inp->in_off : lbn - lastblock; 334 break; 335 } 336 for (; depth && (inp->in_off == 0 || lbn == lastblock); 337 --inp, --depth) { 338 /* 339 * XXX 340 * The indirect block may not yet exist, so 341 * bread will create one just so we can free 342 * it. 343 */ 344 if (bread(vp, 345 inp->in_lbn, fs->lfs_bsize, NOCRED, &bp)) 346 panic("lfs_truncate: bread bno %d", 347 inp->in_lbn); 348 daddrp = bp->b_un.b_daddr + inp->in_off; 349 for (i = inp->in_off; 350 i++ <= a_end[depth].in_off;) { 351 daddr = *daddrp++; 352 SEGDEC; 353 } 354 a_end[depth].in_off = NINDIR(fs) - 1; 355 if (inp->in_off == 0) 356 brelse (bp); 357 else { 358 bzero(bp->b_un.b_daddr + inp->in_off, 359 fs->lfs_bsize - 360 inp->in_off * sizeof(daddr_t)); 361 LFS_UBWRITE(bp); 362 } 363 } 364 if (depth == 0 && a[1].in_off == 0) { 365 off = a[0].in_off; 366 daddr = ip->i_ib[off]; 367 SEGDEC; 368 ip->i_ib[off] = 0; 369 } 370 if (lbn == lastblock || lbn <= NDADDR) 371 --lbn; 372 else { 373 lbn -= NINDIR(fs); 374 if (lbn < lastblock) 375 lbn = lastblock; 376 } 377 } 378 } 379 UPDATE_SEGUSE; 380 ip->i_blocks -= blocksreleased; 381 /* 382 * XXX 383 * Currently, we don't know when we allocate an indirect block, so 384 * ip->i_blocks isn't getting incremented appropriately. As a result, 385 * when we delete any indirect blocks, we get a bad number here. 386 */ 387 if (ip->i_blocks < 0) 388 ip->i_blocks = 0; 389 ip->i_flag |= ICHG|IUPD; 390 (void)vinvalbuf(vp, length > 0); 391 error = VOP_UPDATE(vp, &time, &time, MNT_WAIT); 392 return (0); 393 } 394 #undef vp 395 #undef length 396 #undef flags 397 #undef cred 398