123399Smckusick /* 237736Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337736Smckusick * All rights reserved. 423399Smckusick * 537736Smckusick * Redistribution and use in source and binary forms are permitted 637736Smckusick * provided that the above copyright notice and this paragraph are 737736Smckusick * duplicated in all such forms and that any documentation, 837736Smckusick * advertising materials, and other materials related to such 937736Smckusick * distribution and use acknowledge that the software was developed 1037736Smckusick * by the University of California, Berkeley. The name of the 1137736Smckusick * University may not be used to endorse or promote products derived 1237736Smckusick * from this software without specific prior written permission. 1337736Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437736Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537736Smckusick * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637736Smckusick * 17*39392Smckusick * @(#)lfs_inode.c 7.15 (Berkeley) 10/24/89 1823399Smckusick */ 1924Sbill 2017099Sbloom #include "param.h" 2117099Sbloom #include "systm.h" 2217099Sbloom #include "mount.h" 2317099Sbloom #include "user.h" 2437736Smckusick #include "file.h" 2517099Sbloom #include "buf.h" 2624525Sbloom #include "cmap.h" 2737736Smckusick #include "vnode.h" 2837736Smckusick #include "../ufs/inode.h" 2937736Smckusick #include "../ufs/fs.h" 3037736Smckusick #include "../ufs/ufsmount.h" 317651Ssam #ifdef QUOTA 3237736Smckusick #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*39392Smckusick union ihead { 457334Skre union ihead *ih_head[2]; 467334Skre struct inode *ih_chain[2]; 477334Skre } ihead[INOHSZ]; 487334Skre 49*39392Smckusick struct inode *bdevlisth; 507334Skre 5124Sbill /* 52*39392Smckusick * Initialize hash links for inodes. 5324Sbill */ 5424Sbill ihinit() 5524Sbill { 5624Sbill register int i; 57*39392Smckusick register union ihead *ih = ihead; 5824Sbill 59*39392Smckusick if (VN_MAXPRIVATE < sizeof(struct inode)) 60*39392Smckusick panic("ihinit: too small"); 617334Skre for (i = INOHSZ; --i >= 0; ih++) { 627334Skre ih->ih_head[0] = ih; 637334Skre ih->ih_head[1] = ih; 647334Skre } 6524Sbill } 6624Sbill 6724Sbill /* 6837736Smckusick * Look up an vnode/inode by device,inumber. 6924Sbill * If it is in core (in the inode structure), 7024Sbill * honor the locking protocol. 7124Sbill * If it is not in core, read it in from the 7224Sbill * specified device. 7337736Smckusick * Callers must check for mount points!! 7424Sbill * In all cases, a pointer to a locked 7524Sbill * inode structure is returned. 7624Sbill */ 7737736Smckusick iget(xp, ino, ipp) 7837736Smckusick struct inode *xp; 794818Swnj ino_t ino; 8037736Smckusick struct inode **ipp; 8124Sbill { 8237736Smckusick dev_t dev = xp->i_dev; 8337736Smckusick struct mount *mntp = ITOV(xp)->v_mount; 8437736Smckusick register struct fs *fs = VFSTOUFS(mntp)->um_fs; 8537736Smckusick register struct inode *ip, *iq; 8637736Smckusick register struct vnode *vp; 8737736Smckusick struct inode *nip; 8837736Smckusick struct buf *bp; 8937736Smckusick struct dinode tdip, *dp; 9037736Smckusick union ihead *ih; 9137736Smckusick int error; 9224Sbill 9324Sbill loop: 947334Skre ih = &ihead[INOHASH(dev, ino)]; 95*39392Smckusick for (ip = ih->ih_chain[0]; ip != (struct inode *)ih; ip = ip->i_forw) { 96*39392Smckusick if (ino != ip->i_number || dev != ip->i_dev) 97*39392Smckusick continue; 98*39392Smckusick /* 99*39392Smckusick * Following is essentially an inline expanded 100*39392Smckusick * copy of igrab(), expanded inline for speed, 101*39392Smckusick * and so that the test for a mounted on inode 102*39392Smckusick * can be deferred until after we are sure that 103*39392Smckusick * the inode isn't busy. 104*39392Smckusick */ 105*39392Smckusick if ((ip->i_flag&ILOCKED) != 0) { 106*39392Smckusick ip->i_flag |= IWANT; 107*39392Smckusick sleep((caddr_t)ip, PINOD); 108*39392Smckusick goto loop; 109*39392Smckusick } 110*39392Smckusick vp = ITOV(ip); 111*39392Smckusick if (vp->v_count == 0) /* ino on free list */ 112*39392Smckusick vget(vp); 113*39392Smckusick else 11438345Smckusick VREF(vp); 115*39392Smckusick ILOCK(ip); 116*39392Smckusick *ipp = ip; 117*39392Smckusick return(0); 118*39392Smckusick } 119*39392Smckusick if (error = getnewino(dev, ino, mntp, &nip)) { 12037736Smckusick *ipp = 0; 12137736Smckusick return (error); 12237736Smckusick } 12337736Smckusick ip = nip; 12437736Smckusick /* 12537736Smckusick * Read in the disk contents for the inode. 12637736Smckusick */ 12737736Smckusick if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)), 12838776Smckusick (int)fs->fs_bsize, NOCRED, &bp)) { 12937736Smckusick /* 130*39392Smckusick * Unlock and discard unneeded inode. 13137736Smckusick */ 13238226Smckusick iunlock(ip); 133*39392Smckusick vrele(ITOV(ip)); 13437736Smckusick brelse(bp); 13537736Smckusick *ipp = 0; 13637736Smckusick return(error); 13737736Smckusick } 13837736Smckusick /* 13937736Smckusick * Check to see if the new inode represents a block device 14037736Smckusick * for which we already have an inode (either because of 14137736Smckusick * bdevvp() or because of a different inode representing 14237736Smckusick * the same block device). If such an alias exists, put the 14337736Smckusick * just allocated inode back on the free list, and replace 14437736Smckusick * the contents of the existing inode with the contents of 14537736Smckusick * the new inode. 14637736Smckusick */ 14737736Smckusick dp = bp->b_un.b_dino; 14837736Smckusick dp += itoo(fs, ino); 14937736Smckusick if ((dp->di_mode & IFMT) != IFBLK) { 150*39392Smckusick ip->i_din = *dp; 15137736Smckusick brelse(bp); 15237736Smckusick } else { 15337736Smckusick again: 15437736Smckusick for (iq = bdevlisth; iq; iq = iq->i_devlst) { 15538582Smckusick vp = ITOV(iq); 15638582Smckusick if (dp->di_rdev != vp->v_rdev) 15737736Smckusick continue; 15837736Smckusick igrab(iq); 15938582Smckusick if (dp->di_rdev != vp->v_rdev) { 16037736Smckusick iput(iq); 16137736Smckusick goto again; 16237736Smckusick } 16337736Smckusick /* 164*39392Smckusick * Unlock and discard unneeded inode. 16537736Smckusick */ 166*39392Smckusick vput(ITOV(ip)); 16737736Smckusick /* 16837736Smckusick * Reinitialize aliased inode. 16937736Smckusick * We must release the buffer that we just read 17037736Smckusick * before doing the iupdat() to avoid a possible 17137736Smckusick * deadlock with updating an inode in the same 17237736Smckusick * disk block. 17337736Smckusick */ 17437736Smckusick ip = iq; 175*39392Smckusick vp = ITOV(ip); 176*39392Smckusick tdip = *dp; 17737736Smckusick brelse(bp); 17837736Smckusick error = iupdat(ip, &time, &time, 1); 179*39392Smckusick ip->i_din = tdip; 18037736Smckusick remque(ip); 18137736Smckusick insque(ip, ih); 18237736Smckusick ip->i_dev = dev; 18337736Smckusick ip->i_number = ino; 184*39392Smckusick insmntque(vp, mntp); 18537736Smckusick if (ip->i_devvp) { 18637736Smckusick vrele(ip->i_devvp); 18737736Smckusick ip->i_devvp = 0; 18837736Smckusick } 18937736Smckusick cache_purge(vp); 19037736Smckusick break; 19137736Smckusick } 19237736Smckusick if (iq == 0) { 193*39392Smckusick ip->i_din = *dp; 19437736Smckusick brelse(bp); 19537736Smckusick ip->i_devlst = bdevlisth; 19637736Smckusick bdevlisth = ip; 19737736Smckusick } 19837736Smckusick } 19937736Smckusick /* 20037736Smckusick * Finish inode initialization. 20137736Smckusick */ 20237736Smckusick ip->i_fs = fs; 20337736Smckusick ip->i_devvp = VFSTOUFS(mntp)->um_devvp; 20438345Smckusick VREF(ip->i_devvp); 20537736Smckusick /* 20637736Smckusick * Initialize the associated vnode 20737736Smckusick */ 20837736Smckusick vp = ITOV(ip); 209*39392Smckusick vp->v_type = IFTOVT(ip->i_mode); 21037736Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 21137736Smckusick vp->v_rdev = ip->i_rdev; 21237736Smckusick vp->v_op = &blk_vnodeops; 21337736Smckusick } 21437736Smckusick if (ino == ROOTINO) 21537736Smckusick vp->v_flag |= VROOT; 21637736Smckusick #ifdef QUOTA 21737736Smckusick if (ip->i_mode != 0) 21837736Smckusick ip->i_dquot = inoquota(ip); 21937736Smckusick #endif 22038256Smckusick /* 22138256Smckusick * Set up a generation number for this inode if it does not 22238256Smckusick * already have one. This should only happen on old filesystems. 22338256Smckusick */ 22438256Smckusick if (ip->i_gen == 0) { 22538256Smckusick if (++nextgennumber < (u_long)time.tv_sec) 22638256Smckusick nextgennumber = time.tv_sec; 22738256Smckusick ip->i_gen = nextgennumber; 22838256Smckusick if ((vp->v_mount->m_flag & M_RDONLY) == 0) 22938256Smckusick ip->i_flag |= IMOD; 23038256Smckusick } 23137736Smckusick *ipp = ip; 23237736Smckusick return (0); 23337736Smckusick } 2347334Skre 23537736Smckusick /* 23637736Smckusick * Allocate a new inode. 23737736Smckusick * 23837736Smckusick * Put it onto its hash chain and lock it so that other requests for 23937736Smckusick * this inode will block if they arrive while we are sleeping waiting 24037736Smckusick * for old data structures to be purged or for the contents of the disk 24137736Smckusick * portion of this inode to be read. 24237736Smckusick */ 243*39392Smckusick getnewino(dev, ino, mp, ipp) 24437736Smckusick dev_t dev; 24537736Smckusick ino_t ino; 246*39392Smckusick struct mount *mp; 24737736Smckusick struct inode **ipp; 24837736Smckusick { 24937736Smckusick union ihead *ih; 250*39392Smckusick register struct inode *ip; 251*39392Smckusick struct vnode *vp; 252*39392Smckusick int error; 25337736Smckusick 254*39392Smckusick if (error = getnewvnode(VT_UFS, mp, &ufs_vnodeops, &vp)) 255*39392Smckusick return (error); 256*39392Smckusick ip = VTOI(vp); 257*39392Smckusick ip->i_vnode = vp; 258*39392Smckusick ip->i_flag = 0; 259*39392Smckusick ip->i_devvp = 0; 260*39392Smckusick ip->i_lastr = 0; 261*39392Smckusick ip->i_mode = 0; 262*39392Smckusick #ifdef QUOTA 263*39392Smckusick ip->i_dquot = NODQUOT; 264*39392Smckusick #endif 26537736Smckusick /* 266*39392Smckusick * Put the inode on the chain for its new (ino, dev) pair. 26737736Smckusick */ 26824Sbill ip->i_dev = dev; 26924Sbill ip->i_number = ino; 27037736Smckusick if (dev != NODEV) { 27137736Smckusick ih = &ihead[INOHASH(dev, ino)]; 27237736Smckusick insque(ip, ih); 273*39392Smckusick } else { 274*39392Smckusick ip->i_forw = ip; 275*39392Smckusick ip->i_back = ip; 27637736Smckusick } 27738226Smckusick ILOCK(ip); 27837736Smckusick *ipp = ip; 27937736Smckusick return (0); 28024Sbill } 28124Sbill 28224Sbill /* 28316642Ssam * Convert a pointer to an inode into a reference to an inode. 28416642Ssam * 28516642Ssam * This is basically the internal piece of iget (after the 28616642Ssam * inode pointer is located) but without the test for mounted 28716642Ssam * filesystems. It is caller's responsibility to check that 28816642Ssam * the inode pointer is valid. 28916642Ssam */ 29016642Ssam igrab(ip) 29116642Ssam register struct inode *ip; 29216642Ssam { 29337736Smckusick register struct vnode *vp = ITOV(ip); 29437736Smckusick 29516642Ssam while ((ip->i_flag&ILOCKED) != 0) { 29616642Ssam ip->i_flag |= IWANT; 29716642Ssam sleep((caddr_t)ip, PINOD); 29816642Ssam } 299*39392Smckusick if (vp->v_count == 0) /* ino on free list */ 300*39392Smckusick vget(vp); 301*39392Smckusick else 302*39392Smckusick VREF(vp); 30338226Smckusick ILOCK(ip); 30416642Ssam } 30516642Ssam 30616642Ssam /* 30737736Smckusick * Create a vnode for a block device. 30837736Smckusick * Used for root filesystem, argdev, and swap areas. 30937736Smckusick */ 31037736Smckusick bdevvp(dev, vpp) 31137736Smckusick dev_t dev; 31237736Smckusick struct vnode **vpp; 31337736Smckusick { 31437736Smckusick register struct inode *ip; 31537736Smckusick register struct vnode *vp; 31637736Smckusick struct inode *nip; 31737736Smckusick int error; 31837736Smckusick 31937736Smckusick /* 32037736Smckusick * Check for the existence of an existing vnode. 32137736Smckusick */ 32237736Smckusick again: 32337736Smckusick for (ip = bdevlisth; ip; ip = ip->i_devlst) { 32437736Smckusick vp = ITOV(ip); 32537736Smckusick if (dev != vp->v_rdev) 32637736Smckusick continue; 32737736Smckusick igrab(ip); 32837736Smckusick if (dev != vp->v_rdev) { 32937736Smckusick iput(ip); 33037736Smckusick goto again; 33137736Smckusick } 33237736Smckusick IUNLOCK(ip); 33337736Smckusick *vpp = vp; 33437736Smckusick return (0); 33537736Smckusick } 336*39392Smckusick if (error = getnewino(NODEV, (ino_t)0, (struct mount *)0, &nip)) { 33737736Smckusick *vpp = 0; 33837736Smckusick return (error); 33937736Smckusick } 34037736Smckusick ip = nip; 34137736Smckusick ip->i_fs = 0; 34237736Smckusick ip->i_devlst = bdevlisth; 34337736Smckusick bdevlisth = ip; 34437736Smckusick vp = ITOV(ip); 345*39392Smckusick vp->v_type = VBLK; 346*39392Smckusick vp->v_op = &blk_vnodeops; 34737736Smckusick vp->v_rdev = dev; 34837736Smckusick IUNLOCK(ip); 34937736Smckusick *vpp = vp; 35037736Smckusick return (0); 35137736Smckusick } 35237736Smckusick 35337736Smckusick /* 354*39392Smckusick * Unlock and decrement the reference count of an inode structure. 35524Sbill */ 35624Sbill iput(ip) 3574818Swnj register struct inode *ip; 35824Sbill { 3597118Smckusick 3608452Sroot if ((ip->i_flag & ILOCKED) == 0) 3617118Smckusick panic("iput"); 36216665Smckusick IUNLOCK(ip); 36337736Smckusick vrele(ITOV(ip)); 3647118Smckusick } 3657118Smckusick 366*39392Smckusick /* 367*39392Smckusick * Last reference to an inode, write the inode out and if necessary, 368*39392Smckusick * truncate and deallocate the file. 369*39392Smckusick */ 37037736Smckusick ufs_inactive(vp) 37137736Smckusick struct vnode *vp; 3727118Smckusick { 37337736Smckusick register struct inode *ip = VTOI(vp); 374*39392Smckusick int mode, error = 0; 37524Sbill 37639364Smckusick if (vp->v_count != 0) 37737736Smckusick panic("ufs_inactive: not inactive"); 37838452Smckusick /* 37938452Smckusick * Get rid of inodes related to stale file handles. 38038452Smckusick */ 38138452Smckusick if (ip->i_mode == 0) 382*39392Smckusick return (ufs_reclaim(vp)); 38338226Smckusick ILOCK(ip); 38439364Smckusick if (ip->i_nlink <= 0 && (vp->v_mount->m_flag & M_RDONLY) == 0) { 38537736Smckusick error = itrunc(ip, (u_long)0); 38637736Smckusick mode = ip->i_mode; 38737736Smckusick ip->i_mode = 0; 38837736Smckusick ip->i_rdev = 0; 38937736Smckusick ip->i_flag |= IUPD|ICHG; 39037736Smckusick ifree(ip, ip->i_number, mode); 3917651Ssam #ifdef QUOTA 39237736Smckusick (void) chkiq(ip->i_dev, ip, ip->i_uid, 0); 39337736Smckusick dqrele(ip->i_dquot); 39437736Smckusick ip->i_dquot = NODQUOT; 3957492Skre #endif 39637736Smckusick } 39737736Smckusick IUPDAT(ip, &time, &time, 0); 39837736Smckusick IUNLOCK(ip); 39937736Smckusick ip->i_flag = 0; 40037736Smckusick /* 401*39392Smckusick * If we are done with the inode, reclaim it 402*39392Smckusick * so that it can be reused immediately. 40337736Smckusick */ 404*39392Smckusick if (ip->i_mode == 0 && !error) 405*39392Smckusick return (ufs_reclaim(vp)); 40637736Smckusick return (error); 40724Sbill } 40824Sbill 40924Sbill /* 410*39392Smckusick * Reclaim an inode so that it can be used for other purposes. 41124Sbill */ 412*39392Smckusick ufs_reclaim(vp) 413*39392Smckusick register struct vnode *vp; 414*39392Smckusick { 415*39392Smckusick register struct inode *iq, *ip = VTOI(vp); 416*39392Smckusick 417*39392Smckusick if (vp->v_count != 0) 418*39392Smckusick panic("ufs_reclaim: active inode"); 419*39392Smckusick /* 420*39392Smckusick * Remove the inode from its hash chain. 421*39392Smckusick */ 422*39392Smckusick remque(ip); 423*39392Smckusick ip->i_forw = ip; 424*39392Smckusick ip->i_back = ip; 425*39392Smckusick /* 426*39392Smckusick * Purge old data structures associated with the inode. 427*39392Smckusick */ 428*39392Smckusick cache_purge(vp); 429*39392Smckusick if (ip->i_devvp) { 430*39392Smckusick vrele(ip->i_devvp); 431*39392Smckusick ip->i_devvp = 0; 432*39392Smckusick } 433*39392Smckusick #ifdef QUOTA 434*39392Smckusick dqrele(ip->i_dquot); 435*39392Smckusick ip->i_dquot = NODQUOT; 436*39392Smckusick #endif 437*39392Smckusick if (vp->v_type == VBLK) { 438*39392Smckusick if (bdevlisth == ip) { 439*39392Smckusick bdevlisth = ip->i_devlst; 440*39392Smckusick } else { 441*39392Smckusick for (iq = bdevlisth; iq; iq = iq->i_devlst) { 442*39392Smckusick if (iq->i_devlst != ip) 443*39392Smckusick continue; 444*39392Smckusick iq->i_devlst = ip->i_devlst; 445*39392Smckusick break; 446*39392Smckusick } 447*39392Smckusick if (iq == NULL) 448*39392Smckusick panic("missing bdev"); 449*39392Smckusick } 450*39392Smckusick } 451*39392Smckusick vp->v_type = VNON; 452*39392Smckusick ip->i_flag = 0; 453*39392Smckusick return (0); 454*39392Smckusick } 455*39392Smckusick 456*39392Smckusick /* 457*39392Smckusick * Check accessed and update flags on an inode structure. 458*39392Smckusick * If any is on, update the inode with the current time. 459*39392Smckusick * If waitfor is given, then must ensure I/O order, 460*39392Smckusick * so wait for write to complete. 461*39392Smckusick */ 4621203Sbill iupdat(ip, ta, tm, waitfor) 4634818Swnj register struct inode *ip; 4648630Sroot struct timeval *ta, *tm; 4654818Swnj int waitfor; 46624Sbill { 46737736Smckusick struct buf *bp; 46837736Smckusick struct vnode *vp = ITOV(ip); 46924Sbill struct dinode *dp; 47030749Skarels register struct fs *fs; 47137736Smckusick int error; 47224Sbill 47330749Skarels fs = ip->i_fs; 47437736Smckusick if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) 47537736Smckusick return (0); 47637736Smckusick if (vp->v_mount->m_flag & M_RDONLY) 47737736Smckusick return (0); 47837736Smckusick error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)), 47938776Smckusick (int)fs->fs_bsize, NOCRED, &bp); 48037736Smckusick if (error) { 48137736Smckusick brelse(bp); 48237736Smckusick return (error); 48324Sbill } 48437736Smckusick if (ip->i_flag&IACC) 48537736Smckusick ip->i_atime = ta->tv_sec; 48637736Smckusick if (ip->i_flag&IUPD) 48737736Smckusick ip->i_mtime = tm->tv_sec; 48837736Smckusick if (ip->i_flag&ICHG) 48937736Smckusick ip->i_ctime = time.tv_sec; 49037736Smckusick ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 49137736Smckusick dp = bp->b_un.b_dino + itoo(fs, ip->i_number); 492*39392Smckusick *dp = ip->i_din; 49337736Smckusick if (waitfor) { 49437736Smckusick return (bwrite(bp)); 49537736Smckusick } else { 49637736Smckusick bdwrite(bp); 49737736Smckusick return (0); 49837736Smckusick } 49924Sbill } 50024Sbill 50110736Ssam #define SINGLE 0 /* index of single indirect block */ 50210736Ssam #define DOUBLE 1 /* index of double indirect block */ 50310736Ssam #define TRIPLE 2 /* index of triple indirect block */ 50424Sbill /* 505*39392Smckusick * Truncate the inode ip to at most length size. Free affected disk 506*39392Smckusick * blocks -- the blocks of the file are removed in reverse order. 50710736Ssam * 50810736Ssam * NB: triple indirect blocks are untested. 50924Sbill */ 51010736Ssam itrunc(oip, length) 51117942Smckusick register struct inode *oip; 5129165Ssam u_long length; 51324Sbill { 5149165Ssam register daddr_t lastblock; 51526272Skarels daddr_t bn, lbn, lastiblock[NIADDR]; 5166569Smckusic register struct fs *fs; 51710736Ssam register struct inode *ip; 51817942Smckusick struct buf *bp; 51937736Smckusick int offset, osize, size, level; 52037736Smckusick long count, nblocks, blocksreleased = 0; 52117942Smckusick register int i; 52237736Smckusick int error, allerror = 0; 52310736Ssam struct inode tip; 5249165Ssam 52513000Ssam if (oip->i_size <= length) { 52613000Ssam oip->i_flag |= ICHG|IUPD; 52737736Smckusick error = iupdat(oip, &time, &time, 1); 52837736Smckusick return (error); 52913000Ssam } 5301203Sbill /* 53110736Ssam * Calculate index into inode's block list of 53210736Ssam * last direct and indirect blocks (if any) 53310736Ssam * which we want to keep. Lastblock is -1 when 53410736Ssam * the file is truncated to 0. 5351203Sbill */ 53610736Ssam fs = oip->i_fs; 5379165Ssam lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 53810736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 53910736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 54010736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 54112645Ssam nblocks = btodb(fs->fs_bsize); 5426569Smckusic /* 54317942Smckusick * Update the size of the file. If the file is not being 54417942Smckusick * truncated to a block boundry, the contents of the 54517942Smckusick * partial block following the end of the file must be 54617942Smckusick * zero'ed in case it ever become accessable again because 54717942Smckusick * of subsequent file growth. 54817942Smckusick */ 54917942Smckusick osize = oip->i_size; 55017942Smckusick offset = blkoff(fs, length); 55117942Smckusick if (offset == 0) { 55217942Smckusick oip->i_size = length; 55317942Smckusick } else { 55417942Smckusick lbn = lblkno(fs, length); 55537736Smckusick error = balloc(oip, lbn, offset, &bn, B_CLRBUF); 55637736Smckusick if (error) 55737736Smckusick return (error); 55837736Smckusick if ((long)bn < 0) 55937736Smckusick panic("itrunc: hole"); 56017942Smckusick oip->i_size = length; 56117942Smckusick size = blksize(fs, oip, lbn); 56230749Skarels count = howmany(size, CLBYTES); 56330749Skarels for (i = 0; i < count; i++) 56437736Smckusick munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE); 56538776Smckusick error = bread(oip->i_devvp, bn, size, NOCRED, &bp); 56637736Smckusick if (error) { 56717942Smckusick oip->i_size = osize; 56817942Smckusick brelse(bp); 56937736Smckusick return (error); 57017942Smckusick } 57126272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 57217942Smckusick bdwrite(bp); 57317942Smckusick } 57417942Smckusick /* 57517942Smckusick * Update file and block pointers 57610736Ssam * on disk before we start freeing blocks. 57710736Ssam * If we crash before free'ing blocks below, 57810736Ssam * the blocks will be returned to the free list. 57910736Ssam * lastiblock values are also normalized to -1 58010736Ssam * for calls to indirtrunc below. 5816569Smckusic */ 58210736Ssam tip = *oip; 58317942Smckusick tip.i_size = osize; 58410736Ssam for (level = TRIPLE; level >= SINGLE; level--) 58510736Ssam if (lastiblock[level] < 0) { 58610736Ssam oip->i_ib[level] = 0; 58710736Ssam lastiblock[level] = -1; 5889165Ssam } 58910736Ssam for (i = NDADDR - 1; i > lastblock; i--) 59010736Ssam oip->i_db[i] = 0; 59110736Ssam oip->i_flag |= ICHG|IUPD; 59237736Smckusick allerror = syncip(oip); 59310736Ssam 5946569Smckusic /* 59510736Ssam * Indirect blocks first. 5966569Smckusic */ 59717942Smckusick ip = &tip; 59810736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 59910736Ssam bn = ip->i_ib[level]; 6009165Ssam if (bn != 0) { 60137736Smckusick error = indirtrunc(ip, bn, lastiblock[level], level, 60237736Smckusick &count); 60337736Smckusick if (error) 60437736Smckusick allerror = error; 60537736Smckusick blocksreleased += count; 60610736Ssam if (lastiblock[level] < 0) { 60710736Ssam ip->i_ib[level] = 0; 60831402Smckusick blkfree(ip, bn, (off_t)fs->fs_bsize); 60910736Ssam blocksreleased += nblocks; 61010736Ssam } 61110736Ssam } 61210736Ssam if (lastiblock[level] >= 0) 61310736Ssam goto done; 6149165Ssam } 61510736Ssam 6166569Smckusic /* 61710736Ssam * All whole direct blocks or frags. 6186569Smckusic */ 6199165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 62026359Skarels register off_t bsize; 6219165Ssam 6226569Smckusic bn = ip->i_db[i]; 6239165Ssam if (bn == 0) 62424Sbill continue; 6259165Ssam ip->i_db[i] = 0; 62624525Sbloom bsize = (off_t)blksize(fs, ip, i); 62731402Smckusick blkfree(ip, bn, bsize); 62824525Sbloom blocksreleased += btodb(bsize); 62924Sbill } 63010736Ssam if (lastblock < 0) 63110736Ssam goto done; 63210736Ssam 6331203Sbill /* 6349165Ssam * Finally, look for a change in size of the 6359165Ssam * last direct block; release any frags. 6361203Sbill */ 63710736Ssam bn = ip->i_db[lastblock]; 63810736Ssam if (bn != 0) { 63926359Skarels off_t oldspace, newspace; 64010736Ssam 6419165Ssam /* 6429165Ssam * Calculate amount of space we're giving 6439165Ssam * back as old block size minus new block size. 6449165Ssam */ 64510736Ssam oldspace = blksize(fs, ip, lastblock); 6469165Ssam ip->i_size = length; 64710736Ssam newspace = blksize(fs, ip, lastblock); 64810736Ssam if (newspace == 0) 64910736Ssam panic("itrunc: newspace"); 65010736Ssam if (oldspace - newspace > 0) { 6519165Ssam /* 6529165Ssam * Block number of space to be free'd is 6539165Ssam * the old block # plus the number of frags 6549165Ssam * required for the storage we're keeping. 6559165Ssam */ 65610736Ssam bn += numfrags(fs, newspace); 65731402Smckusick blkfree(ip, bn, oldspace - newspace); 65812645Ssam blocksreleased += btodb(oldspace - newspace); 6599165Ssam } 6609165Ssam } 6619165Ssam done: 66210736Ssam /* BEGIN PARANOIA */ 66310736Ssam for (level = SINGLE; level <= TRIPLE; level++) 66410736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 66510736Ssam panic("itrunc1"); 66610736Ssam for (i = 0; i < NDADDR; i++) 66710736Ssam if (ip->i_db[i] != oip->i_db[i]) 66810736Ssam panic("itrunc2"); 66910736Ssam /* END PARANOIA */ 67012645Ssam oip->i_blocks -= blocksreleased; 67112645Ssam if (oip->i_blocks < 0) /* sanity */ 67212645Ssam oip->i_blocks = 0; 67312645Ssam oip->i_flag |= ICHG; 6749165Ssam #ifdef QUOTA 67512645Ssam (void) chkdq(oip, -blocksreleased, 0); 6769165Ssam #endif 67737736Smckusick return (allerror); 67824Sbill } 67924Sbill 6809165Ssam /* 6819165Ssam * Release blocks associated with the inode ip and 6829165Ssam * stored in the indirect block bn. Blocks are free'd 6839165Ssam * in LIFO order up to (but not including) lastbn. If 68410736Ssam * level is greater than SINGLE, the block is an indirect 68510736Ssam * block and recursive calls to indirtrunc must be used to 68610736Ssam * cleanse other indirect blocks. 68710736Ssam * 68810736Ssam * NB: triple indirect blocks are untested. 6899165Ssam */ 69037736Smckusick indirtrunc(ip, bn, lastbn, level, countp) 6916569Smckusic register struct inode *ip; 6929165Ssam daddr_t bn, lastbn; 69310736Ssam int level; 69437736Smckusick long *countp; 69524Sbill { 6969165Ssam register int i; 69731661Smckusick struct buf *bp; 69831661Smckusick register struct fs *fs = ip->i_fs; 69924Sbill register daddr_t *bap; 70031661Smckusick daddr_t *copy, nb, last; 70137736Smckusick long blkcount, factor; 70237736Smckusick int nblocks, blocksreleased = 0; 70337736Smckusick int error, allerror = 0; 70424Sbill 70510736Ssam /* 70610736Ssam * Calculate index in current block of last 70710736Ssam * block to be kept. -1 indicates the entire 70810736Ssam * block so we need not calculate the index. 70910736Ssam */ 71010736Ssam factor = 1; 71110736Ssam for (i = SINGLE; i < level; i++) 71210736Ssam factor *= NINDIR(fs); 7139165Ssam last = lastbn; 71410736Ssam if (lastbn > 0) 71510736Ssam last /= factor; 71612645Ssam nblocks = btodb(fs->fs_bsize); 71710736Ssam /* 71810736Ssam * Get buffer of block pointers, zero those 71910736Ssam * entries corresponding to blocks to be free'd, 72010736Ssam * and update on disk copy first. 72110736Ssam */ 72238776Smckusick error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, 72338776Smckusick NOCRED, &bp); 72437736Smckusick if (error) { 72510736Ssam brelse(bp); 72637736Smckusick *countp = 0; 72737736Smckusick return (error); 72810736Ssam } 72910736Ssam bap = bp->b_un.b_daddr; 73031661Smckusick MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); 73131661Smckusick bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); 73210736Ssam bzero((caddr_t)&bap[last + 1], 73310736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 73437736Smckusick error = bwrite(bp); 73537736Smckusick if (error) 73637736Smckusick allerror = error; 73731661Smckusick bap = copy; 73810736Ssam 73910736Ssam /* 74010736Ssam * Recursively free totally unused blocks. 74110736Ssam */ 7429165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 74324Sbill nb = bap[i]; 7449165Ssam if (nb == 0) 74524Sbill continue; 74637736Smckusick if (level > SINGLE) { 74737736Smckusick error = indirtrunc(ip, nb, (daddr_t)-1, level - 1, 74837736Smckusick &blkcount); 74937736Smckusick if (error) 75037736Smckusick allerror = error; 75137736Smckusick blocksreleased += blkcount; 75237736Smckusick } 75331402Smckusick blkfree(ip, nb, (off_t)fs->fs_bsize); 7549165Ssam blocksreleased += nblocks; 75524Sbill } 75610736Ssam 75710736Ssam /* 75810736Ssam * Recursively free last partial block. 75910736Ssam */ 76010736Ssam if (level > SINGLE && lastbn >= 0) { 76110736Ssam last = lastbn % factor; 7629165Ssam nb = bap[i]; 76337736Smckusick if (nb != 0) { 76437736Smckusick error = indirtrunc(ip, nb, last, level - 1, &blkcount); 76537736Smckusick if (error) 76637736Smckusick allerror = error; 76737736Smckusick blocksreleased += blkcount; 76837736Smckusick } 7699165Ssam } 77031661Smckusick FREE(copy, M_TEMP); 77137736Smckusick *countp = blocksreleased; 77237736Smckusick return (allerror); 77324Sbill } 77424Sbill 77524Sbill /* 77630749Skarels * Remove any inodes in the inode cache belonging to dev. 7777334Skre * 7787334Skre * There should not be any active ones, return error if any are found 77930749Skarels * (nb: this is a user error, not a system err). 7807334Skre */ 78139363Smckusick int busyprt = 0; /* patch to print out busy inodes */ 78239363Smckusick 7837651Ssam #ifdef QUOTA 784*39392Smckusick iflush(mp, iq) 785*39392Smckusick struct mount *mp; 7867504Sroot struct inode *iq; 7877492Skre #else 788*39392Smckusick iflush(mp) 789*39392Smckusick struct mount *mp; 7907492Skre #endif 7917334Skre { 792*39392Smckusick register struct vnode *vp; 7937335Skre register struct inode *ip; 79439363Smckusick int busy = 0; 7957334Skre 796*39392Smckusick for (vp = mp->m_mounth; vp; vp = vp->v_mountf) { 797*39392Smckusick ip = VTOI(vp); 7987651Ssam #ifdef QUOTA 799*39392Smckusick if (ip == iq) 80039363Smckusick continue; 8017492Skre #endif 802*39392Smckusick if (vp->v_count) { 80339363Smckusick busy++; 80439363Smckusick if (!busyprt) 80539363Smckusick continue; 80639363Smckusick printf("%s %d on dev 0x%x count %d type %d\n", 80739363Smckusick "iflush: busy inode ", ip->i_number, ip->i_dev, 808*39392Smckusick vp->v_count, vp->v_type); 80939363Smckusick continue; 81039363Smckusick } 81139363Smckusick /* 81239363Smckusick * As v_count == 0, the inode was on the free list already, 813*39392Smckusick * so it will fall off the bottom eventually. 81439363Smckusick * We could perhaps move it to the head of the free list, 81539363Smckusick * but as umounts are done so infrequently, we would gain 81639363Smckusick * very little, while making the code bigger. 81739363Smckusick */ 818*39392Smckusick ufs_reclaim(vp); 8197334Skre } 82039363Smckusick if (busy) 82139363Smckusick return (EBUSY); 82230749Skarels return (0); 8237334Skre } 8247334Skre 8253617Sroot /* 8264818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 8273617Sroot */ 8284818Swnj ilock(ip) 8294818Swnj register struct inode *ip; 8303617Sroot { 8313617Sroot 83237736Smckusick while (ip->i_flag & ILOCKED) { 83337736Smckusick ip->i_flag |= IWANT; 83437736Smckusick (void) sleep((caddr_t)ip, PINOD); 83537736Smckusick } 83637736Smckusick ip->i_flag |= ILOCKED; 8373617Sroot } 8383617Sroot 8393617Sroot /* 8404818Swnj * Unlock an inode. If WANT bit is on, wakeup. 8413617Sroot */ 8427118Smckusick iunlock(ip) 8434818Swnj register struct inode *ip; 8443617Sroot { 8453617Sroot 84637736Smckusick if ((ip->i_flag & ILOCKED) == 0) 84737736Smckusick printf("unlocking unlocked inode %d on dev 0x%x\n", 84837736Smckusick ip->i_number, ip->i_dev); 84937736Smckusick ip->i_flag &= ~ILOCKED; 85037736Smckusick if (ip->i_flag&IWANT) { 85137736Smckusick ip->i_flag &= ~IWANT; 85237736Smckusick wakeup((caddr_t)ip); 85337736Smckusick } 8543617Sroot } 85537736Smckusick 85637736Smckusick /* 85737736Smckusick * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 85837736Smckusick * The mode is shifted to select the owner/group/other fields. The 85937736Smckusick * super user is granted all permissions. 86037736Smckusick * 86137736Smckusick * NB: Called from vnode op table. It seems this could all be done 86237736Smckusick * using vattr's but... 86337736Smckusick */ 86437736Smckusick iaccess(ip, mode, cred) 86537736Smckusick register struct inode *ip; 86637736Smckusick register int mode; 86737736Smckusick struct ucred *cred; 86837736Smckusick { 86937736Smckusick register gid_t *gp; 87037736Smckusick int i; 87137736Smckusick 87237736Smckusick /* 873*39392Smckusick * If you're the super-user, you always get access. 87437736Smckusick */ 87537736Smckusick if (cred->cr_uid == 0) 87637736Smckusick return (0); 87737736Smckusick /* 87837736Smckusick * Access check is based on only one of owner, group, public. 87937736Smckusick * If not owner, then check group. If not a member of the 88037736Smckusick * group, then check public access. 88137736Smckusick */ 88237736Smckusick if (cred->cr_uid != ip->i_uid) { 88337736Smckusick mode >>= 3; 88437736Smckusick gp = cred->cr_groups; 88537736Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 88637736Smckusick if (ip->i_gid == *gp) 88737736Smckusick goto found; 88837736Smckusick mode >>= 3; 88937736Smckusick found: 89037736Smckusick ; 89137736Smckusick } 89237736Smckusick if ((ip->i_mode & mode) != 0) 89337736Smckusick return (0); 89437736Smckusick return (EACCES); 89537736Smckusick } 896