123399Smckusick /* 2*37736Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3*37736Smckusick * All rights reserved. 423399Smckusick * 5*37736Smckusick * Redistribution and use in source and binary forms are permitted 6*37736Smckusick * provided that the above copyright notice and this paragraph are 7*37736Smckusick * duplicated in all such forms and that any documentation, 8*37736Smckusick * advertising materials, and other materials related to such 9*37736Smckusick * distribution and use acknowledge that the software was developed 10*37736Smckusick * by the University of California, Berkeley. The name of the 11*37736Smckusick * University may not be used to endorse or promote products derived 12*37736Smckusick * from this software without specific prior written permission. 13*37736Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*37736Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*37736Smckusick * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16*37736Smckusick * 17*37736Smckusick * @(#)lfs_inode.c 7.6 (Berkeley) 05/09/89 1823399Smckusick */ 1924Sbill 2017099Sbloom #include "param.h" 2117099Sbloom #include "systm.h" 2217099Sbloom #include "mount.h" 2317099Sbloom #include "user.h" 24*37736Smckusick #include "file.h" 2517099Sbloom #include "buf.h" 2624525Sbloom #include "cmap.h" 27*37736Smckusick #include "vnode.h" 28*37736Smckusick #include "../ufs/inode.h" 29*37736Smckusick #include "../ufs/fs.h" 30*37736Smckusick #include "../ufs/ufsmount.h" 317651Ssam #ifdef QUOTA 32*37736Smckusick #include "../ufs/quota.h" 337504Sroot #endif 3417099Sbloom #include "kernel.h" 3531661Smckusick #include "malloc.h" 3624Sbill 3716840Smckusick #define INOHSZ 512 387334Skre #if ((INOHSZ&(INOHSZ-1)) == 0) 397334Skre #define INOHASH(dev,ino) (((dev)+(ino))&(INOHSZ-1)) 407334Skre #else 4110852Ssam #define INOHASH(dev,ino) (((unsigned)((dev)+(ino)))%INOHSZ) 427334Skre #endif 4324Sbill 44*37736Smckusick #define INSFREE(ip) {\ 45*37736Smckusick if (ifreeh) { \ 46*37736Smckusick *ifreet = (ip); \ 47*37736Smckusick (ip)->i_freeb = ifreet; \ 48*37736Smckusick } else { \ 49*37736Smckusick ifreeh = (ip); \ 50*37736Smckusick (ip)->i_freeb = &ifreeh; \ 51*37736Smckusick } \ 52*37736Smckusick (ip)->i_freef = NULL; \ 53*37736Smckusick ifreet = &(ip)->i_freef; \ 54*37736Smckusick } 55*37736Smckusick 567334Skre union ihead { /* inode LRU cache, Chris Maltby */ 577334Skre union ihead *ih_head[2]; 587334Skre struct inode *ih_chain[2]; 597334Skre } ihead[INOHSZ]; 607334Skre 61*37736Smckusick struct inode *ifreeh, **ifreet, *bdevlisth; 627334Skre 6324Sbill /* 6424Sbill * Initialize hash links for inodes 6524Sbill * and build inode free list. 6624Sbill */ 6724Sbill ihinit() 6824Sbill { 6924Sbill register int i; 702737Swnj register struct inode *ip = inode; 717334Skre register union ihead *ih = ihead; 7224Sbill 737334Skre for (i = INOHSZ; --i >= 0; ih++) { 747334Skre ih->ih_head[0] = ih; 757334Skre ih->ih_head[1] = ih; 767334Skre } 777334Skre ifreeh = ip; 787334Skre ifreet = &ip->i_freef; 797334Skre ip->i_freeb = &ifreeh; 807334Skre ip->i_forw = ip; 817334Skre ip->i_back = ip; 82*37736Smckusick ITOV(ip)->v_data = (qaddr_t)ip; 837334Skre for (i = ninode; --i > 0; ) { 847334Skre ++ip; 857334Skre ip->i_forw = ip; 867334Skre ip->i_back = ip; 87*37736Smckusick ITOV(ip)->v_data = (qaddr_t)ip; 887334Skre *ifreet = ip; 897334Skre ip->i_freeb = ifreet; 907334Skre ifreet = &ip->i_freef; 917334Skre } 927334Skre ip->i_freef = NULL; 9324Sbill } 9424Sbill 9524Sbill /* 96*37736Smckusick * Look up an vnode/inode by device,inumber. 9724Sbill * If it is in core (in the inode structure), 9824Sbill * honor the locking protocol. 9924Sbill * If it is not in core, read it in from the 10024Sbill * specified device. 101*37736Smckusick * Callers must check for mount points!! 10224Sbill * In all cases, a pointer to a locked 10324Sbill * inode structure is returned. 10424Sbill */ 105*37736Smckusick iget(xp, ino, ipp) 106*37736Smckusick struct inode *xp; 1074818Swnj ino_t ino; 108*37736Smckusick struct inode **ipp; 10924Sbill { 110*37736Smckusick dev_t dev = xp->i_dev; 111*37736Smckusick struct mount *mntp = ITOV(xp)->v_mount; 112*37736Smckusick register struct fs *fs = VFSTOUFS(mntp)->um_fs; 113*37736Smckusick register struct inode *ip, *iq; 114*37736Smckusick register struct vnode *vp; 115*37736Smckusick struct inode *nip; 116*37736Smckusick struct buf *bp; 117*37736Smckusick struct dinode tdip, *dp; 118*37736Smckusick union ihead *ih; 119*37736Smckusick int error; 12024Sbill 12124Sbill loop: 1227334Skre ih = &ihead[INOHASH(dev, ino)]; 1237334Skre for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) 1244818Swnj if (ino == ip->i_number && dev == ip->i_dev) { 12516642Ssam /* 12616642Ssam * Following is essentially an inline expanded 12716642Ssam * copy of igrab(), expanded inline for speed, 12816642Ssam * and so that the test for a mounted on inode 12916642Ssam * can be deferred until after we are sure that 13016642Ssam * the inode isn't busy. 13116642Ssam */ 1328452Sroot if ((ip->i_flag&ILOCKED) != 0) { 13324Sbill ip->i_flag |= IWANT; 13424Sbill sleep((caddr_t)ip, PINOD); 13524Sbill goto loop; 13624Sbill } 137*37736Smckusick vp = ITOV(ip); 138*37736Smckusick if (vp->v_count == 0) { /* ino on free list */ 1397334Skre if (iq = ip->i_freef) 1407334Skre iq->i_freeb = ip->i_freeb; 1417334Skre else 1427334Skre ifreet = ip->i_freeb; 1437334Skre *ip->i_freeb = iq; 1447334Skre ip->i_freef = NULL; 1457334Skre ip->i_freeb = NULL; 1467334Skre } 1478452Sroot ip->i_flag |= ILOCKED; 148*37736Smckusick vp->v_count++; 149*37736Smckusick *ipp = ip; 150*37736Smckusick return(0); 15124Sbill } 152*37736Smckusick if (error = getnewino(dev, ino, &nip)) { 153*37736Smckusick *ipp = 0; 154*37736Smckusick return (error); 155*37736Smckusick } 156*37736Smckusick ip = nip; 157*37736Smckusick /* 158*37736Smckusick * Read in the disk contents for the inode. 159*37736Smckusick */ 160*37736Smckusick if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)), 161*37736Smckusick (int)fs->fs_bsize, &bp)) { 162*37736Smckusick /* 163*37736Smckusick * The inode doesn't contain anything useful, so it would 164*37736Smckusick * be misleading to leave it on its hash chain. Iput() will 165*37736Smckusick * take care of putting it back on the free list. We also 166*37736Smckusick * lose its inumber, just in case. 167*37736Smckusick */ 168*37736Smckusick remque(ip); 169*37736Smckusick ip->i_forw = ip; 170*37736Smckusick ip->i_back = ip; 171*37736Smckusick ip->i_number = 0; 172*37736Smckusick INSFREE(ip); 173*37736Smckusick ip->i_flag = 0; 174*37736Smckusick brelse(bp); 175*37736Smckusick *ipp = 0; 176*37736Smckusick return(error); 177*37736Smckusick } 178*37736Smckusick /* 179*37736Smckusick * Check to see if the new inode represents a block device 180*37736Smckusick * for which we already have an inode (either because of 181*37736Smckusick * bdevvp() or because of a different inode representing 182*37736Smckusick * the same block device). If such an alias exists, put the 183*37736Smckusick * just allocated inode back on the free list, and replace 184*37736Smckusick * the contents of the existing inode with the contents of 185*37736Smckusick * the new inode. 186*37736Smckusick */ 187*37736Smckusick dp = bp->b_un.b_dino; 188*37736Smckusick dp += itoo(fs, ino); 189*37736Smckusick if ((dp->di_mode & IFMT) != IFBLK) { 190*37736Smckusick ip->i_ic = dp->di_ic; 191*37736Smckusick brelse(bp); 192*37736Smckusick } else { 193*37736Smckusick again: 194*37736Smckusick for (iq = bdevlisth; iq; iq = iq->i_devlst) { 195*37736Smckusick if (dp->di_rdev != ITOV(iq)->v_rdev) 196*37736Smckusick continue; 197*37736Smckusick igrab(iq); 198*37736Smckusick if (dp->di_rdev != ITOV(iq)->v_rdev) { 199*37736Smckusick iput(iq); 200*37736Smckusick goto again; 201*37736Smckusick } 202*37736Smckusick /* 203*37736Smckusick * Discard unneeded inode. 204*37736Smckusick */ 205*37736Smckusick remque(ip); 206*37736Smckusick ip->i_forw = ip; 207*37736Smckusick ip->i_back = ip; 208*37736Smckusick ip->i_number = 0; 209*37736Smckusick INSFREE(ip); 210*37736Smckusick ip->i_flag = 0; 211*37736Smckusick /* 212*37736Smckusick * Reinitialize aliased inode. 213*37736Smckusick * We must release the buffer that we just read 214*37736Smckusick * before doing the iupdat() to avoid a possible 215*37736Smckusick * deadlock with updating an inode in the same 216*37736Smckusick * disk block. 217*37736Smckusick */ 218*37736Smckusick ip = iq; 219*37736Smckusick vp = ITOV(iq); 220*37736Smckusick tdip.di_ic = dp->di_ic; 221*37736Smckusick brelse(bp); 222*37736Smckusick error = iupdat(ip, &time, &time, 1); 223*37736Smckusick ip->i_ic = tdip.di_ic; 224*37736Smckusick remque(ip); 225*37736Smckusick insque(ip, ih); 226*37736Smckusick ip->i_dev = dev; 227*37736Smckusick ip->i_number = ino; 228*37736Smckusick if (ip->i_devvp) { 229*37736Smckusick vrele(ip->i_devvp); 230*37736Smckusick ip->i_devvp = 0; 231*37736Smckusick } 232*37736Smckusick cache_purge(vp); 233*37736Smckusick break; 234*37736Smckusick } 235*37736Smckusick if (iq == 0) { 236*37736Smckusick ip->i_ic = dp->di_ic; 237*37736Smckusick brelse(bp); 238*37736Smckusick ip->i_devlst = bdevlisth; 239*37736Smckusick bdevlisth = ip; 240*37736Smckusick } 241*37736Smckusick } 242*37736Smckusick /* 243*37736Smckusick * Finish inode initialization. 244*37736Smckusick */ 245*37736Smckusick ip->i_fs = fs; 246*37736Smckusick ip->i_devvp = VFSTOUFS(mntp)->um_devvp; 247*37736Smckusick ip->i_devvp->v_count++; 248*37736Smckusick /* 249*37736Smckusick * Initialize the associated vnode 250*37736Smckusick */ 251*37736Smckusick vp = ITOV(ip); 252*37736Smckusick vinit(vp, mntp, IFTOVT(ip->i_mode), &ufs_vnodeops); 253*37736Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 254*37736Smckusick vp->v_rdev = ip->i_rdev; 255*37736Smckusick vp->v_op = &blk_vnodeops; 256*37736Smckusick } 257*37736Smckusick if (ino == ROOTINO) 258*37736Smckusick vp->v_flag |= VROOT; 259*37736Smckusick #ifdef QUOTA 260*37736Smckusick if (ip->i_mode != 0) 261*37736Smckusick ip->i_dquot = inoquota(ip); 262*37736Smckusick #endif 263*37736Smckusick *ipp = ip; 264*37736Smckusick return (0); 265*37736Smckusick } 2667334Skre 267*37736Smckusick /* 268*37736Smckusick * Allocate a new inode. 269*37736Smckusick * 270*37736Smckusick * Put it onto its hash chain and lock it so that other requests for 271*37736Smckusick * this inode will block if they arrive while we are sleeping waiting 272*37736Smckusick * for old data structures to be purged or for the contents of the disk 273*37736Smckusick * portion of this inode to be read. 274*37736Smckusick */ 275*37736Smckusick getnewino(dev, ino, ipp) 276*37736Smckusick dev_t dev; 277*37736Smckusick ino_t ino; 278*37736Smckusick struct inode **ipp; 279*37736Smckusick { 280*37736Smckusick union ihead *ih; 281*37736Smckusick register struct inode *ip, *iq; 282*37736Smckusick register struct vnode *vp; 283*37736Smckusick 284*37736Smckusick /* 285*37736Smckusick * Remove the next inode from the free list. 286*37736Smckusick */ 2877334Skre if ((ip = ifreeh) == NULL) { 2882933Swnj tablefull("inode"); 289*37736Smckusick *ipp = 0; 290*37736Smckusick return(ENFILE); 29124Sbill } 292*37736Smckusick vp = ITOV(ip); 293*37736Smckusick if (vp->v_count) 29416720Skarels panic("free inode isn't"); 2957334Skre if (iq = ip->i_freef) 2967334Skre iq->i_freeb = &ifreeh; 2977334Skre ifreeh = iq; 2987334Skre ip->i_freef = NULL; 2997334Skre ip->i_freeb = NULL; 3007334Skre /* 3017334Skre * Now to take inode off the hash chain it was on 3027334Skre * (initially, or after an iflush, it is on a "hash chain" 303*37736Smckusick * consisting entirely of itself, and pointed to by no-one) 304*37736Smckusick * and put it on the chain for its new (ino, dev) pair. 3057334Skre */ 3067335Skre remque(ip); 30724Sbill ip->i_dev = dev; 30824Sbill ip->i_number = ino; 309*37736Smckusick if (dev != NODEV) { 310*37736Smckusick ih = &ihead[INOHASH(dev, ino)]; 311*37736Smckusick insque(ip, ih); 312*37736Smckusick } 3138452Sroot ip->i_flag = ILOCKED; 3146569Smckusic ip->i_lastr = 0; 31524Sbill /* 316*37736Smckusick * Purge old data structures associated with the inode. 31724Sbill */ 318*37736Smckusick cache_purge(vp); 319*37736Smckusick if (ip->i_devvp) { 320*37736Smckusick vrele(ip->i_devvp); 321*37736Smckusick ip->i_devvp = 0; 322*37736Smckusick } 3237651Ssam #ifdef QUOTA 324*37736Smckusick dqrele(ip->i_dquot); 325*37736Smckusick ip->i_dquot = NODQUOT; 3267492Skre #endif 327*37736Smckusick if (vp->v_type == VBLK) { 328*37736Smckusick if (bdevlisth == ip) { 329*37736Smckusick bdevlisth = ip->i_devlst; 330*37736Smckusick } else { 331*37736Smckusick for (iq = bdevlisth; iq; iq = iq->i_devlst) { 332*37736Smckusick if (iq->i_devlst != ip) 333*37736Smckusick continue; 334*37736Smckusick iq->i_devlst = ip->i_devlst; 335*37736Smckusick break; 336*37736Smckusick } 337*37736Smckusick if (iq == NULL) 338*37736Smckusick panic("missing bdev"); 339*37736Smckusick } 34024Sbill } 341*37736Smckusick *ipp = ip; 342*37736Smckusick return (0); 34324Sbill } 34424Sbill 34524Sbill /* 34616642Ssam * Convert a pointer to an inode into a reference to an inode. 34716642Ssam * 34816642Ssam * This is basically the internal piece of iget (after the 34916642Ssam * inode pointer is located) but without the test for mounted 35016642Ssam * filesystems. It is caller's responsibility to check that 35116642Ssam * the inode pointer is valid. 35216642Ssam */ 35316642Ssam igrab(ip) 35416642Ssam register struct inode *ip; 35516642Ssam { 356*37736Smckusick register struct vnode *vp = ITOV(ip); 357*37736Smckusick 35816642Ssam while ((ip->i_flag&ILOCKED) != 0) { 35916642Ssam ip->i_flag |= IWANT; 36016642Ssam sleep((caddr_t)ip, PINOD); 36116642Ssam } 362*37736Smckusick if (vp->v_count == 0) { /* ino on free list */ 36316642Ssam register struct inode *iq; 36416642Ssam 36516642Ssam if (iq = ip->i_freef) 36616642Ssam iq->i_freeb = ip->i_freeb; 36716642Ssam else 36816642Ssam ifreet = ip->i_freeb; 36916642Ssam *ip->i_freeb = iq; 37016642Ssam ip->i_freef = NULL; 37116642Ssam ip->i_freeb = NULL; 37216642Ssam } 373*37736Smckusick vp->v_count++; 37416642Ssam ip->i_flag |= ILOCKED; 37516642Ssam } 37616642Ssam 37716642Ssam /* 378*37736Smckusick * Create a vnode for a block device. 379*37736Smckusick * Used for root filesystem, argdev, and swap areas. 380*37736Smckusick */ 381*37736Smckusick bdevvp(dev, vpp) 382*37736Smckusick dev_t dev; 383*37736Smckusick struct vnode **vpp; 384*37736Smckusick { 385*37736Smckusick register struct inode *ip; 386*37736Smckusick register struct vnode *vp; 387*37736Smckusick struct inode *nip; 388*37736Smckusick int error; 389*37736Smckusick 390*37736Smckusick /* 391*37736Smckusick * Check for the existence of an existing vnode. 392*37736Smckusick */ 393*37736Smckusick again: 394*37736Smckusick for (ip = bdevlisth; ip; ip = ip->i_devlst) { 395*37736Smckusick vp = ITOV(ip); 396*37736Smckusick if (dev != vp->v_rdev) 397*37736Smckusick continue; 398*37736Smckusick igrab(ip); 399*37736Smckusick if (dev != vp->v_rdev) { 400*37736Smckusick iput(ip); 401*37736Smckusick goto again; 402*37736Smckusick } 403*37736Smckusick IUNLOCK(ip); 404*37736Smckusick *vpp = vp; 405*37736Smckusick return (0); 406*37736Smckusick } 407*37736Smckusick if (error = getnewino(NODEV, (ino_t)0, &nip)) { 408*37736Smckusick *vpp = 0; 409*37736Smckusick return (error); 410*37736Smckusick } 411*37736Smckusick ip = nip; 412*37736Smckusick ip->i_fs = 0; 413*37736Smckusick ip->i_devlst = bdevlisth; 414*37736Smckusick bdevlisth = ip; 415*37736Smckusick vp = ITOV(ip); 416*37736Smckusick vinit(vp, 0, VBLK, &blk_vnodeops); 417*37736Smckusick vp->v_rdev = dev; 418*37736Smckusick IUNLOCK(ip); 419*37736Smckusick *vpp = vp; 420*37736Smckusick return (0); 421*37736Smckusick } 422*37736Smckusick 423*37736Smckusick /* 42424Sbill * Decrement reference count of 42524Sbill * an inode structure. 42624Sbill * On the last reference, 42724Sbill * write the inode out and if necessary, 42824Sbill * truncate and deallocate the file. 42924Sbill */ 43024Sbill iput(ip) 4314818Swnj register struct inode *ip; 43224Sbill { 4337118Smckusick 4348452Sroot if ((ip->i_flag & ILOCKED) == 0) 4357118Smckusick panic("iput"); 43616665Smckusick IUNLOCK(ip); 437*37736Smckusick vrele(ITOV(ip)); 4387118Smckusick } 4397118Smckusick 440*37736Smckusick 441*37736Smckusick ufs_inactive(vp) 442*37736Smckusick struct vnode *vp; 4437118Smckusick { 444*37736Smckusick register struct inode *ip = VTOI(vp); 445*37736Smckusick int mode, error; 44624Sbill 447*37736Smckusick if (ITOV(ip)->v_count != 0) 448*37736Smckusick panic("ufs_inactive: not inactive"); 449*37736Smckusick ip->i_flag |= ILOCKED; 450*37736Smckusick if (ip->i_nlink <= 0 && (ITOV(ip)->v_mount->m_flag&M_RDONLY) == 0) { 451*37736Smckusick error = itrunc(ip, (u_long)0); 452*37736Smckusick mode = ip->i_mode; 453*37736Smckusick ip->i_mode = 0; 454*37736Smckusick ip->i_rdev = 0; 455*37736Smckusick ip->i_flag |= IUPD|ICHG; 456*37736Smckusick ifree(ip, ip->i_number, mode); 4577651Ssam #ifdef QUOTA 458*37736Smckusick (void) chkiq(ip->i_dev, ip, ip->i_uid, 0); 459*37736Smckusick dqrele(ip->i_dquot); 460*37736Smckusick ip->i_dquot = NODQUOT; 4617492Skre #endif 462*37736Smckusick } 463*37736Smckusick IUPDAT(ip, &time, &time, 0); 464*37736Smckusick IUNLOCK(ip); 465*37736Smckusick ip->i_flag = 0; 466*37736Smckusick /* 467*37736Smckusick * Put the inode on the end of the free list. 468*37736Smckusick * Possibly in some cases it would be better to 469*37736Smckusick * put the inode at the head of the free list, 470*37736Smckusick * (eg: where i_mode == 0 || i_number == 0). 471*37736Smckusick */ 472*37736Smckusick INSFREE(ip); 473*37736Smckusick return (error); 47424Sbill } 47524Sbill 47624Sbill /* 47724Sbill * Check accessed and update flags on 47824Sbill * an inode structure. 47924Sbill * If any is on, update the inode 48024Sbill * with the current time. 4811203Sbill * If waitfor is given, then must insure 4821203Sbill * i/o order so wait for write to complete. 48324Sbill */ 4841203Sbill iupdat(ip, ta, tm, waitfor) 4854818Swnj register struct inode *ip; 4868630Sroot struct timeval *ta, *tm; 4874818Swnj int waitfor; 48824Sbill { 489*37736Smckusick struct buf *bp; 490*37736Smckusick struct vnode *vp = ITOV(ip); 49124Sbill struct dinode *dp; 49230749Skarels register struct fs *fs; 493*37736Smckusick int error; 49424Sbill 49530749Skarels fs = ip->i_fs; 496*37736Smckusick if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) 497*37736Smckusick return (0); 498*37736Smckusick if (vp->v_mount->m_flag & M_RDONLY) 499*37736Smckusick return (0); 500*37736Smckusick error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)), 501*37736Smckusick (int)fs->fs_bsize, &bp); 502*37736Smckusick if (error) { 503*37736Smckusick brelse(bp); 504*37736Smckusick return (error); 50524Sbill } 506*37736Smckusick if (ip->i_flag&IACC) 507*37736Smckusick ip->i_atime = ta->tv_sec; 508*37736Smckusick if (ip->i_flag&IUPD) 509*37736Smckusick ip->i_mtime = tm->tv_sec; 510*37736Smckusick if (ip->i_flag&ICHG) 511*37736Smckusick ip->i_ctime = time.tv_sec; 512*37736Smckusick ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 513*37736Smckusick dp = bp->b_un.b_dino + itoo(fs, ip->i_number); 514*37736Smckusick dp->di_ic = ip->i_ic; 515*37736Smckusick if (waitfor) { 516*37736Smckusick return (bwrite(bp)); 517*37736Smckusick } else { 518*37736Smckusick bdwrite(bp); 519*37736Smckusick return (0); 520*37736Smckusick } 52124Sbill } 52224Sbill 52310736Ssam #define SINGLE 0 /* index of single indirect block */ 52410736Ssam #define DOUBLE 1 /* index of double indirect block */ 52510736Ssam #define TRIPLE 2 /* index of triple indirect block */ 52624Sbill /* 5277702Ssam * Truncate the inode ip to at most 5287702Ssam * length size. Free affected disk 5297702Ssam * blocks -- the blocks of the file 5307702Ssam * are removed in reverse order. 53110736Ssam * 53210736Ssam * NB: triple indirect blocks are untested. 53324Sbill */ 53410736Ssam itrunc(oip, length) 53517942Smckusick register struct inode *oip; 5369165Ssam u_long length; 53724Sbill { 5389165Ssam register daddr_t lastblock; 53926272Skarels daddr_t bn, lbn, lastiblock[NIADDR]; 5406569Smckusic register struct fs *fs; 54110736Ssam register struct inode *ip; 54217942Smckusick struct buf *bp; 543*37736Smckusick int offset, osize, size, level; 544*37736Smckusick long count, nblocks, blocksreleased = 0; 54517942Smckusick register int i; 546*37736Smckusick int error, allerror = 0; 54710736Ssam struct inode tip; 5489165Ssam 54913000Ssam if (oip->i_size <= length) { 55013000Ssam oip->i_flag |= ICHG|IUPD; 551*37736Smckusick error = iupdat(oip, &time, &time, 1); 552*37736Smckusick return (error); 55313000Ssam } 5541203Sbill /* 55510736Ssam * Calculate index into inode's block list of 55610736Ssam * last direct and indirect blocks (if any) 55710736Ssam * which we want to keep. Lastblock is -1 when 55810736Ssam * the file is truncated to 0. 5591203Sbill */ 56010736Ssam fs = oip->i_fs; 5619165Ssam lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 56210736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 56310736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 56410736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 56512645Ssam nblocks = btodb(fs->fs_bsize); 5666569Smckusic /* 56717942Smckusick * Update the size of the file. If the file is not being 56817942Smckusick * truncated to a block boundry, the contents of the 56917942Smckusick * partial block following the end of the file must be 57017942Smckusick * zero'ed in case it ever become accessable again because 57117942Smckusick * of subsequent file growth. 57217942Smckusick */ 57317942Smckusick osize = oip->i_size; 57417942Smckusick offset = blkoff(fs, length); 57517942Smckusick if (offset == 0) { 57617942Smckusick oip->i_size = length; 57717942Smckusick } else { 57817942Smckusick lbn = lblkno(fs, length); 579*37736Smckusick error = balloc(oip, lbn, offset, &bn, B_CLRBUF); 580*37736Smckusick if (error) 581*37736Smckusick return (error); 582*37736Smckusick if ((long)bn < 0) 583*37736Smckusick panic("itrunc: hole"); 58417942Smckusick oip->i_size = length; 58517942Smckusick size = blksize(fs, oip, lbn); 58630749Skarels count = howmany(size, CLBYTES); 58730749Skarels for (i = 0; i < count; i++) 588*37736Smckusick munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE); 589*37736Smckusick error = bread(oip->i_devvp, bn, size, &bp); 590*37736Smckusick if (error) { 59117942Smckusick oip->i_size = osize; 59217942Smckusick brelse(bp); 593*37736Smckusick return (error); 59417942Smckusick } 59526272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 59617942Smckusick bdwrite(bp); 59717942Smckusick } 59817942Smckusick /* 59917942Smckusick * Update file and block pointers 60010736Ssam * on disk before we start freeing blocks. 60110736Ssam * If we crash before free'ing blocks below, 60210736Ssam * the blocks will be returned to the free list. 60310736Ssam * lastiblock values are also normalized to -1 60410736Ssam * for calls to indirtrunc below. 6056569Smckusic */ 60610736Ssam tip = *oip; 60717942Smckusick tip.i_size = osize; 60810736Ssam for (level = TRIPLE; level >= SINGLE; level--) 60910736Ssam if (lastiblock[level] < 0) { 61010736Ssam oip->i_ib[level] = 0; 61110736Ssam lastiblock[level] = -1; 6129165Ssam } 61310736Ssam for (i = NDADDR - 1; i > lastblock; i--) 61410736Ssam oip->i_db[i] = 0; 61510736Ssam oip->i_flag |= ICHG|IUPD; 616*37736Smckusick allerror = syncip(oip); 61710736Ssam 6186569Smckusic /* 61910736Ssam * Indirect blocks first. 6206569Smckusic */ 62117942Smckusick ip = &tip; 62210736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 62310736Ssam bn = ip->i_ib[level]; 6249165Ssam if (bn != 0) { 625*37736Smckusick error = indirtrunc(ip, bn, lastiblock[level], level, 626*37736Smckusick &count); 627*37736Smckusick if (error) 628*37736Smckusick allerror = error; 629*37736Smckusick blocksreleased += count; 63010736Ssam if (lastiblock[level] < 0) { 63110736Ssam ip->i_ib[level] = 0; 63231402Smckusick blkfree(ip, bn, (off_t)fs->fs_bsize); 63310736Ssam blocksreleased += nblocks; 63410736Ssam } 63510736Ssam } 63610736Ssam if (lastiblock[level] >= 0) 63710736Ssam goto done; 6389165Ssam } 63910736Ssam 6406569Smckusic /* 64110736Ssam * All whole direct blocks or frags. 6426569Smckusic */ 6439165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 64426359Skarels register off_t bsize; 6459165Ssam 6466569Smckusic bn = ip->i_db[i]; 6479165Ssam if (bn == 0) 64824Sbill continue; 6499165Ssam ip->i_db[i] = 0; 65024525Sbloom bsize = (off_t)blksize(fs, ip, i); 65131402Smckusick blkfree(ip, bn, bsize); 65224525Sbloom blocksreleased += btodb(bsize); 65324Sbill } 65410736Ssam if (lastblock < 0) 65510736Ssam goto done; 65610736Ssam 6571203Sbill /* 6589165Ssam * Finally, look for a change in size of the 6599165Ssam * last direct block; release any frags. 6601203Sbill */ 66110736Ssam bn = ip->i_db[lastblock]; 66210736Ssam if (bn != 0) { 66326359Skarels off_t oldspace, newspace; 66410736Ssam 6659165Ssam /* 6669165Ssam * Calculate amount of space we're giving 6679165Ssam * back as old block size minus new block size. 6689165Ssam */ 66910736Ssam oldspace = blksize(fs, ip, lastblock); 6709165Ssam ip->i_size = length; 67110736Ssam newspace = blksize(fs, ip, lastblock); 67210736Ssam if (newspace == 0) 67310736Ssam panic("itrunc: newspace"); 67410736Ssam if (oldspace - newspace > 0) { 6759165Ssam /* 6769165Ssam * Block number of space to be free'd is 6779165Ssam * the old block # plus the number of frags 6789165Ssam * required for the storage we're keeping. 6799165Ssam */ 68010736Ssam bn += numfrags(fs, newspace); 68131402Smckusick blkfree(ip, bn, oldspace - newspace); 68212645Ssam blocksreleased += btodb(oldspace - newspace); 6839165Ssam } 6849165Ssam } 6859165Ssam done: 68610736Ssam /* BEGIN PARANOIA */ 68710736Ssam for (level = SINGLE; level <= TRIPLE; level++) 68810736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 68910736Ssam panic("itrunc1"); 69010736Ssam for (i = 0; i < NDADDR; i++) 69110736Ssam if (ip->i_db[i] != oip->i_db[i]) 69210736Ssam panic("itrunc2"); 69310736Ssam /* END PARANOIA */ 69412645Ssam oip->i_blocks -= blocksreleased; 69512645Ssam if (oip->i_blocks < 0) /* sanity */ 69612645Ssam oip->i_blocks = 0; 69712645Ssam oip->i_flag |= ICHG; 6989165Ssam #ifdef QUOTA 69912645Ssam (void) chkdq(oip, -blocksreleased, 0); 7009165Ssam #endif 701*37736Smckusick return (allerror); 70224Sbill } 70324Sbill 7049165Ssam /* 7059165Ssam * Release blocks associated with the inode ip and 7069165Ssam * stored in the indirect block bn. Blocks are free'd 7079165Ssam * in LIFO order up to (but not including) lastbn. If 70810736Ssam * level is greater than SINGLE, the block is an indirect 70910736Ssam * block and recursive calls to indirtrunc must be used to 71010736Ssam * cleanse other indirect blocks. 71110736Ssam * 71210736Ssam * NB: triple indirect blocks are untested. 7139165Ssam */ 714*37736Smckusick indirtrunc(ip, bn, lastbn, level, countp) 7156569Smckusic register struct inode *ip; 7169165Ssam daddr_t bn, lastbn; 71710736Ssam int level; 718*37736Smckusick long *countp; 71924Sbill { 7209165Ssam register int i; 72131661Smckusick struct buf *bp; 72231661Smckusick register struct fs *fs = ip->i_fs; 72324Sbill register daddr_t *bap; 72431661Smckusick daddr_t *copy, nb, last; 725*37736Smckusick long blkcount, factor; 726*37736Smckusick int nblocks, blocksreleased = 0; 727*37736Smckusick int error, allerror = 0; 72824Sbill 72910736Ssam /* 73010736Ssam * Calculate index in current block of last 73110736Ssam * block to be kept. -1 indicates the entire 73210736Ssam * block so we need not calculate the index. 73310736Ssam */ 73410736Ssam factor = 1; 73510736Ssam for (i = SINGLE; i < level; i++) 73610736Ssam factor *= NINDIR(fs); 7379165Ssam last = lastbn; 73810736Ssam if (lastbn > 0) 73910736Ssam last /= factor; 74012645Ssam nblocks = btodb(fs->fs_bsize); 74110736Ssam /* 74210736Ssam * Get buffer of block pointers, zero those 74310736Ssam * entries corresponding to blocks to be free'd, 74410736Ssam * and update on disk copy first. 74510736Ssam */ 746*37736Smckusick error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, &bp); 747*37736Smckusick if (error) { 74810736Ssam brelse(bp); 749*37736Smckusick *countp = 0; 750*37736Smckusick return (error); 75110736Ssam } 75210736Ssam bap = bp->b_un.b_daddr; 75331661Smckusick MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); 75431661Smckusick bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); 75510736Ssam bzero((caddr_t)&bap[last + 1], 75610736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 757*37736Smckusick error = bwrite(bp); 758*37736Smckusick if (error) 759*37736Smckusick allerror = error; 76031661Smckusick bap = copy; 76110736Ssam 76210736Ssam /* 76310736Ssam * Recursively free totally unused blocks. 76410736Ssam */ 7659165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 76624Sbill nb = bap[i]; 7679165Ssam if (nb == 0) 76824Sbill continue; 769*37736Smckusick if (level > SINGLE) { 770*37736Smckusick error = indirtrunc(ip, nb, (daddr_t)-1, level - 1, 771*37736Smckusick &blkcount); 772*37736Smckusick if (error) 773*37736Smckusick allerror = error; 774*37736Smckusick blocksreleased += blkcount; 775*37736Smckusick } 77631402Smckusick blkfree(ip, nb, (off_t)fs->fs_bsize); 7779165Ssam blocksreleased += nblocks; 77824Sbill } 77910736Ssam 78010736Ssam /* 78110736Ssam * Recursively free last partial block. 78210736Ssam */ 78310736Ssam if (level > SINGLE && lastbn >= 0) { 78410736Ssam last = lastbn % factor; 7859165Ssam nb = bap[i]; 786*37736Smckusick if (nb != 0) { 787*37736Smckusick error = indirtrunc(ip, nb, last, level - 1, &blkcount); 788*37736Smckusick if (error) 789*37736Smckusick allerror = error; 790*37736Smckusick blocksreleased += blkcount; 791*37736Smckusick } 7929165Ssam } 79331661Smckusick FREE(copy, M_TEMP); 794*37736Smckusick *countp = blocksreleased; 795*37736Smckusick return (allerror); 79624Sbill } 79724Sbill 79824Sbill /* 79930749Skarels * Remove any inodes in the inode cache belonging to dev. 8007334Skre * 8017334Skre * There should not be any active ones, return error if any are found 80230749Skarels * (nb: this is a user error, not a system err). 8037334Skre */ 8047651Ssam #ifdef QUOTA 8057504Sroot iflush(dev, iq) 8067492Skre dev_t dev; 8077504Sroot struct inode *iq; 8087492Skre #else 8097334Skre iflush(dev) 8107334Skre dev_t dev; 8117492Skre #endif 8127334Skre { 8137335Skre register struct inode *ip; 8147334Skre 8157334Skre for (ip = inode; ip < inodeNINODE; ip++) { 8167651Ssam #ifdef QUOTA 8177492Skre if (ip != iq && ip->i_dev == dev) 8187492Skre #else 8197334Skre if (ip->i_dev == dev) 8207492Skre #endif 821*37736Smckusick if (ITOV(ip)->v_count) 82230749Skarels return (EBUSY); 8237334Skre else { 8247335Skre remque(ip); 8257334Skre ip->i_forw = ip; 8267334Skre ip->i_back = ip; 8277334Skre /* 828*37736Smckusick * as v_count == 0, the inode was on the free 8297334Skre * list already, just leave it there, it will 8307334Skre * fall off the bottom eventually. We could 8317334Skre * perhaps move it to the head of the free 8327334Skre * list, but as umounts are done so 8337334Skre * infrequently, we would gain very little, 8347334Skre * while making the code bigger. 8357334Skre */ 8367651Ssam #ifdef QUOTA 8377492Skre dqrele(ip->i_dquot); 8387492Skre ip->i_dquot = NODQUOT; 8397492Skre #endif 840*37736Smckusick if (ip->i_devvp) { 841*37736Smckusick vrele(ip->i_devvp); 842*37736Smckusick ip->i_devvp = 0; 843*37736Smckusick } 8447334Skre } 8457334Skre } 84630749Skarels return (0); 8477334Skre } 8487334Skre 8493617Sroot /* 8504818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 8513617Sroot */ 8524818Swnj ilock(ip) 8534818Swnj register struct inode *ip; 8543617Sroot { 8553617Sroot 856*37736Smckusick while (ip->i_flag & ILOCKED) { 857*37736Smckusick ip->i_flag |= IWANT; 858*37736Smckusick (void) sleep((caddr_t)ip, PINOD); 859*37736Smckusick } 860*37736Smckusick ip->i_flag |= ILOCKED; 8613617Sroot } 8623617Sroot 8633617Sroot /* 8644818Swnj * Unlock an inode. If WANT bit is on, wakeup. 8653617Sroot */ 8667118Smckusick iunlock(ip) 8674818Swnj register struct inode *ip; 8683617Sroot { 8693617Sroot 870*37736Smckusick if ((ip->i_flag & ILOCKED) == 0) 871*37736Smckusick printf("unlocking unlocked inode %d on dev 0x%x\n", 872*37736Smckusick ip->i_number, ip->i_dev); 873*37736Smckusick ip->i_flag &= ~ILOCKED; 874*37736Smckusick if (ip->i_flag&IWANT) { 875*37736Smckusick ip->i_flag &= ~IWANT; 876*37736Smckusick wakeup((caddr_t)ip); 877*37736Smckusick } 8783617Sroot } 879*37736Smckusick 880*37736Smckusick /* 881*37736Smckusick * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 882*37736Smckusick * The mode is shifted to select the owner/group/other fields. The 883*37736Smckusick * super user is granted all permissions. 884*37736Smckusick * 885*37736Smckusick * NB: Called from vnode op table. It seems this could all be done 886*37736Smckusick * using vattr's but... 887*37736Smckusick */ 888*37736Smckusick iaccess(ip, mode, cred) 889*37736Smckusick register struct inode *ip; 890*37736Smckusick register int mode; 891*37736Smckusick struct ucred *cred; 892*37736Smckusick { 893*37736Smckusick register gid_t *gp; 894*37736Smckusick register struct vnode *vp = ITOV(ip); 895*37736Smckusick int i; 896*37736Smckusick 897*37736Smckusick /* 898*37736Smckusick * If you're the super-user, 899*37736Smckusick * you always get access. 900*37736Smckusick */ 901*37736Smckusick if (cred->cr_uid == 0) 902*37736Smckusick return (0); 903*37736Smckusick /* 904*37736Smckusick * Access check is based on only one of owner, group, public. 905*37736Smckusick * If not owner, then check group. If not a member of the 906*37736Smckusick * group, then check public access. 907*37736Smckusick */ 908*37736Smckusick if (cred->cr_uid != ip->i_uid) { 909*37736Smckusick mode >>= 3; 910*37736Smckusick gp = cred->cr_groups; 911*37736Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 912*37736Smckusick if (ip->i_gid == *gp) 913*37736Smckusick goto found; 914*37736Smckusick mode >>= 3; 915*37736Smckusick found: 916*37736Smckusick ; 917*37736Smckusick } 918*37736Smckusick if ((ip->i_mode & mode) != 0) 919*37736Smckusick return (0); 920*37736Smckusick return (EACCES); 921*37736Smckusick } 922