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*38582Smckusick * @(#)lfs_inode.c 7.11 (Berkeley) 08/10/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 4437736Smckusick #define INSFREE(ip) {\ 4537736Smckusick if (ifreeh) { \ 4637736Smckusick *ifreet = (ip); \ 4737736Smckusick (ip)->i_freeb = ifreet; \ 4837736Smckusick } else { \ 4937736Smckusick ifreeh = (ip); \ 5037736Smckusick (ip)->i_freeb = &ifreeh; \ 5137736Smckusick } \ 5237736Smckusick (ip)->i_freef = NULL; \ 5337736Smckusick ifreet = &(ip)->i_freef; \ 5437736Smckusick } 5537736Smckusick 567334Skre union ihead { /* inode LRU cache, Chris Maltby */ 577334Skre union ihead *ih_head[2]; 587334Skre struct inode *ih_chain[2]; 597334Skre } ihead[INOHSZ]; 607334Skre 6137736Smckusick 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; 8237736Smckusick 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; 8737736Smckusick 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 /* 9637736Smckusick * 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. 10137736Smckusick * Callers must check for mount points!! 10224Sbill * In all cases, a pointer to a locked 10324Sbill * inode structure is returned. 10424Sbill */ 10537736Smckusick iget(xp, ino, ipp) 10637736Smckusick struct inode *xp; 1074818Swnj ino_t ino; 10837736Smckusick struct inode **ipp; 10924Sbill { 11037736Smckusick dev_t dev = xp->i_dev; 11137736Smckusick struct mount *mntp = ITOV(xp)->v_mount; 11237736Smckusick register struct fs *fs = VFSTOUFS(mntp)->um_fs; 11337736Smckusick register struct inode *ip, *iq; 11437736Smckusick register struct vnode *vp; 11537736Smckusick struct inode *nip; 11637736Smckusick struct buf *bp; 11737736Smckusick struct dinode tdip, *dp; 11837736Smckusick union ihead *ih; 11937736Smckusick 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 } 13737736Smckusick vp = ITOV(ip); 13837736Smckusick 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 } 14738226Smckusick ILOCK(ip); 14838345Smckusick VREF(vp); 14937736Smckusick *ipp = ip; 15037736Smckusick return(0); 15124Sbill } 15237736Smckusick if (error = getnewino(dev, ino, &nip)) { 15337736Smckusick *ipp = 0; 15437736Smckusick return (error); 15537736Smckusick } 15637736Smckusick ip = nip; 15737736Smckusick /* 15837736Smckusick * Read in the disk contents for the inode. 15937736Smckusick */ 16037736Smckusick if (error = bread(VFSTOUFS(mntp)->um_devvp, fsbtodb(fs, itod(fs, ino)), 16137736Smckusick (int)fs->fs_bsize, &bp)) { 16237736Smckusick /* 16337736Smckusick * The inode doesn't contain anything useful, so it would 16437736Smckusick * be misleading to leave it on its hash chain. Iput() will 16537736Smckusick * take care of putting it back on the free list. We also 16637736Smckusick * lose its inumber, just in case. 16737736Smckusick */ 16837736Smckusick remque(ip); 16937736Smckusick ip->i_forw = ip; 17037736Smckusick ip->i_back = ip; 17137736Smckusick ip->i_number = 0; 172*38582Smckusick ITOV(ip)->v_type = VNON; 17337736Smckusick INSFREE(ip); 17438226Smckusick iunlock(ip); 17537736Smckusick ip->i_flag = 0; 17637736Smckusick brelse(bp); 17737736Smckusick *ipp = 0; 17837736Smckusick return(error); 17937736Smckusick } 18037736Smckusick /* 18137736Smckusick * Check to see if the new inode represents a block device 18237736Smckusick * for which we already have an inode (either because of 18337736Smckusick * bdevvp() or because of a different inode representing 18437736Smckusick * the same block device). If such an alias exists, put the 18537736Smckusick * just allocated inode back on the free list, and replace 18637736Smckusick * the contents of the existing inode with the contents of 18737736Smckusick * the new inode. 18837736Smckusick */ 18937736Smckusick dp = bp->b_un.b_dino; 19037736Smckusick dp += itoo(fs, ino); 19137736Smckusick if ((dp->di_mode & IFMT) != IFBLK) { 19237736Smckusick ip->i_ic = dp->di_ic; 19337736Smckusick brelse(bp); 19437736Smckusick } else { 19537736Smckusick again: 19637736Smckusick for (iq = bdevlisth; iq; iq = iq->i_devlst) { 197*38582Smckusick vp = ITOV(iq); 198*38582Smckusick if (dp->di_rdev != vp->v_rdev) 19937736Smckusick continue; 20037736Smckusick igrab(iq); 201*38582Smckusick if (dp->di_rdev != vp->v_rdev) { 20237736Smckusick iput(iq); 20337736Smckusick goto again; 20437736Smckusick } 20537736Smckusick /* 20637736Smckusick * Discard unneeded inode. 20737736Smckusick */ 20837736Smckusick remque(ip); 20937736Smckusick ip->i_forw = ip; 21037736Smckusick ip->i_back = ip; 21137736Smckusick ip->i_number = 0; 212*38582Smckusick ITOV(ip)->v_type = VNON; 21337736Smckusick INSFREE(ip); 21438226Smckusick iunlock(ip); 21537736Smckusick ip->i_flag = 0; 21637736Smckusick /* 21737736Smckusick * Reinitialize aliased inode. 21837736Smckusick * We must release the buffer that we just read 21937736Smckusick * before doing the iupdat() to avoid a possible 22037736Smckusick * deadlock with updating an inode in the same 22137736Smckusick * disk block. 22237736Smckusick */ 22337736Smckusick ip = iq; 22437736Smckusick tdip.di_ic = dp->di_ic; 22537736Smckusick brelse(bp); 22637736Smckusick error = iupdat(ip, &time, &time, 1); 22737736Smckusick ip->i_ic = tdip.di_ic; 22837736Smckusick remque(ip); 22937736Smckusick insque(ip, ih); 23037736Smckusick ip->i_dev = dev; 23137736Smckusick ip->i_number = ino; 23237736Smckusick if (ip->i_devvp) { 23337736Smckusick vrele(ip->i_devvp); 23437736Smckusick ip->i_devvp = 0; 23537736Smckusick } 23637736Smckusick cache_purge(vp); 23737736Smckusick break; 23837736Smckusick } 23937736Smckusick if (iq == 0) { 24037736Smckusick ip->i_ic = dp->di_ic; 24137736Smckusick brelse(bp); 24237736Smckusick ip->i_devlst = bdevlisth; 24337736Smckusick bdevlisth = ip; 24437736Smckusick } 24537736Smckusick } 24637736Smckusick /* 24737736Smckusick * Finish inode initialization. 24837736Smckusick */ 24937736Smckusick ip->i_fs = fs; 25037736Smckusick ip->i_devvp = VFSTOUFS(mntp)->um_devvp; 25138345Smckusick VREF(ip->i_devvp); 25237736Smckusick /* 25337736Smckusick * Initialize the associated vnode 25437736Smckusick */ 25537736Smckusick vp = ITOV(ip); 25637736Smckusick vinit(vp, mntp, IFTOVT(ip->i_mode), &ufs_vnodeops); 25737736Smckusick if (vp->v_type == VCHR || vp->v_type == VBLK) { 25837736Smckusick vp->v_rdev = ip->i_rdev; 25937736Smckusick vp->v_op = &blk_vnodeops; 26037736Smckusick } 26137736Smckusick if (ino == ROOTINO) 26237736Smckusick vp->v_flag |= VROOT; 26337736Smckusick #ifdef QUOTA 26437736Smckusick if (ip->i_mode != 0) 26537736Smckusick ip->i_dquot = inoquota(ip); 26637736Smckusick #endif 26738256Smckusick /* 26838256Smckusick * Set up a generation number for this inode if it does not 26938256Smckusick * already have one. This should only happen on old filesystems. 27038256Smckusick */ 27138256Smckusick if (ip->i_gen == 0) { 27238256Smckusick if (++nextgennumber < (u_long)time.tv_sec) 27338256Smckusick nextgennumber = time.tv_sec; 27438256Smckusick ip->i_gen = nextgennumber; 27538256Smckusick if ((vp->v_mount->m_flag & M_RDONLY) == 0) 27638256Smckusick ip->i_flag |= IMOD; 27738256Smckusick } 27837736Smckusick *ipp = ip; 27937736Smckusick return (0); 28037736Smckusick } 2817334Skre 28237736Smckusick /* 28337736Smckusick * Allocate a new inode. 28437736Smckusick * 28537736Smckusick * Put it onto its hash chain and lock it so that other requests for 28637736Smckusick * this inode will block if they arrive while we are sleeping waiting 28737736Smckusick * for old data structures to be purged or for the contents of the disk 28837736Smckusick * portion of this inode to be read. 28937736Smckusick */ 29037736Smckusick getnewino(dev, ino, ipp) 29137736Smckusick dev_t dev; 29237736Smckusick ino_t ino; 29337736Smckusick struct inode **ipp; 29437736Smckusick { 29537736Smckusick union ihead *ih; 29637736Smckusick register struct inode *ip, *iq; 29737736Smckusick register struct vnode *vp; 29837736Smckusick 29937736Smckusick /* 30037736Smckusick * Remove the next inode from the free list. 30137736Smckusick */ 3027334Skre if ((ip = ifreeh) == NULL) { 3032933Swnj tablefull("inode"); 30437736Smckusick *ipp = 0; 30537736Smckusick return(ENFILE); 30624Sbill } 30737736Smckusick vp = ITOV(ip); 30837736Smckusick if (vp->v_count) 30916720Skarels panic("free inode isn't"); 3107334Skre if (iq = ip->i_freef) 3117334Skre iq->i_freeb = &ifreeh; 3127334Skre ifreeh = iq; 3137334Skre ip->i_freef = NULL; 3147334Skre ip->i_freeb = NULL; 3157334Skre /* 3167334Skre * Now to take inode off the hash chain it was on 3177334Skre * (initially, or after an iflush, it is on a "hash chain" 31837736Smckusick * consisting entirely of itself, and pointed to by no-one) 31937736Smckusick * and put it on the chain for its new (ino, dev) pair. 3207334Skre */ 3217335Skre remque(ip); 32224Sbill ip->i_dev = dev; 32324Sbill ip->i_number = ino; 32437736Smckusick if (dev != NODEV) { 32537736Smckusick ih = &ihead[INOHASH(dev, ino)]; 32637736Smckusick insque(ip, ih); 32737736Smckusick } 32838226Smckusick ip->i_flag = 0; 32938226Smckusick ILOCK(ip); 3306569Smckusic ip->i_lastr = 0; 33124Sbill /* 33237736Smckusick * Purge old data structures associated with the inode. 33324Sbill */ 33437736Smckusick cache_purge(vp); 33537736Smckusick if (ip->i_devvp) { 33637736Smckusick vrele(ip->i_devvp); 33737736Smckusick ip->i_devvp = 0; 33837736Smckusick } 3397651Ssam #ifdef QUOTA 34037736Smckusick dqrele(ip->i_dquot); 34137736Smckusick ip->i_dquot = NODQUOT; 3427492Skre #endif 34337736Smckusick if (vp->v_type == VBLK) { 34437736Smckusick if (bdevlisth == ip) { 34537736Smckusick bdevlisth = ip->i_devlst; 34637736Smckusick } else { 34737736Smckusick for (iq = bdevlisth; iq; iq = iq->i_devlst) { 34837736Smckusick if (iq->i_devlst != ip) 34937736Smckusick continue; 35037736Smckusick iq->i_devlst = ip->i_devlst; 35137736Smckusick break; 35237736Smckusick } 35337736Smckusick if (iq == NULL) 35437736Smckusick panic("missing bdev"); 35537736Smckusick } 35624Sbill } 35737736Smckusick *ipp = ip; 35837736Smckusick return (0); 35924Sbill } 36024Sbill 36124Sbill /* 36216642Ssam * Convert a pointer to an inode into a reference to an inode. 36316642Ssam * 36416642Ssam * This is basically the internal piece of iget (after the 36516642Ssam * inode pointer is located) but without the test for mounted 36616642Ssam * filesystems. It is caller's responsibility to check that 36716642Ssam * the inode pointer is valid. 36816642Ssam */ 36916642Ssam igrab(ip) 37016642Ssam register struct inode *ip; 37116642Ssam { 37237736Smckusick register struct vnode *vp = ITOV(ip); 37337736Smckusick 37416642Ssam while ((ip->i_flag&ILOCKED) != 0) { 37516642Ssam ip->i_flag |= IWANT; 37616642Ssam sleep((caddr_t)ip, PINOD); 37716642Ssam } 37837736Smckusick if (vp->v_count == 0) { /* ino on free list */ 37916642Ssam register struct inode *iq; 38016642Ssam 38116642Ssam if (iq = ip->i_freef) 38216642Ssam iq->i_freeb = ip->i_freeb; 38316642Ssam else 38416642Ssam ifreet = ip->i_freeb; 38516642Ssam *ip->i_freeb = iq; 38616642Ssam ip->i_freef = NULL; 38716642Ssam ip->i_freeb = NULL; 38816642Ssam } 38938345Smckusick VREF(vp); 39038226Smckusick ILOCK(ip); 39116642Ssam } 39216642Ssam 39316642Ssam /* 39437736Smckusick * Create a vnode for a block device. 39537736Smckusick * Used for root filesystem, argdev, and swap areas. 39637736Smckusick */ 39737736Smckusick bdevvp(dev, vpp) 39837736Smckusick dev_t dev; 39937736Smckusick struct vnode **vpp; 40037736Smckusick { 40137736Smckusick register struct inode *ip; 40237736Smckusick register struct vnode *vp; 40337736Smckusick struct inode *nip; 40437736Smckusick int error; 40537736Smckusick 40637736Smckusick /* 40737736Smckusick * Check for the existence of an existing vnode. 40837736Smckusick */ 40937736Smckusick again: 41037736Smckusick for (ip = bdevlisth; ip; ip = ip->i_devlst) { 41137736Smckusick vp = ITOV(ip); 41237736Smckusick if (dev != vp->v_rdev) 41337736Smckusick continue; 41437736Smckusick igrab(ip); 41537736Smckusick if (dev != vp->v_rdev) { 41637736Smckusick iput(ip); 41737736Smckusick goto again; 41837736Smckusick } 41937736Smckusick IUNLOCK(ip); 42037736Smckusick *vpp = vp; 42137736Smckusick return (0); 42237736Smckusick } 42337736Smckusick if (error = getnewino(NODEV, (ino_t)0, &nip)) { 42437736Smckusick *vpp = 0; 42537736Smckusick return (error); 42637736Smckusick } 42737736Smckusick ip = nip; 42837736Smckusick ip->i_fs = 0; 42937736Smckusick ip->i_devlst = bdevlisth; 43037736Smckusick bdevlisth = ip; 43137736Smckusick vp = ITOV(ip); 43237736Smckusick vinit(vp, 0, VBLK, &blk_vnodeops); 43337736Smckusick vp->v_rdev = dev; 43437736Smckusick IUNLOCK(ip); 43537736Smckusick *vpp = vp; 43637736Smckusick return (0); 43737736Smckusick } 43837736Smckusick 43937736Smckusick /* 44024Sbill * Decrement reference count of 44124Sbill * an inode structure. 44224Sbill * On the last reference, 44324Sbill * write the inode out and if necessary, 44424Sbill * truncate and deallocate the file. 44524Sbill */ 44624Sbill iput(ip) 4474818Swnj register struct inode *ip; 44824Sbill { 4497118Smckusick 4508452Sroot if ((ip->i_flag & ILOCKED) == 0) 4517118Smckusick panic("iput"); 45216665Smckusick IUNLOCK(ip); 45337736Smckusick vrele(ITOV(ip)); 4547118Smckusick } 4557118Smckusick 45637736Smckusick 45737736Smckusick ufs_inactive(vp) 45837736Smckusick struct vnode *vp; 4597118Smckusick { 46037736Smckusick register struct inode *ip = VTOI(vp); 46137736Smckusick int mode, error; 46224Sbill 46337736Smckusick if (ITOV(ip)->v_count != 0) 46437736Smckusick panic("ufs_inactive: not inactive"); 46538452Smckusick /* 46638452Smckusick * Get rid of inodes related to stale file handles. 46738452Smckusick */ 46838452Smckusick if (ip->i_mode == 0) 46938452Smckusick goto freeit; 47038226Smckusick ILOCK(ip); 47137736Smckusick if (ip->i_nlink <= 0 && (ITOV(ip)->v_mount->m_flag&M_RDONLY) == 0) { 47237736Smckusick error = itrunc(ip, (u_long)0); 47337736Smckusick mode = ip->i_mode; 47437736Smckusick ip->i_mode = 0; 47537736Smckusick ip->i_rdev = 0; 47637736Smckusick ip->i_flag |= IUPD|ICHG; 47737736Smckusick ifree(ip, ip->i_number, mode); 4787651Ssam #ifdef QUOTA 47937736Smckusick (void) chkiq(ip->i_dev, ip, ip->i_uid, 0); 48037736Smckusick dqrele(ip->i_dquot); 48137736Smckusick ip->i_dquot = NODQUOT; 4827492Skre #endif 48337736Smckusick } 48437736Smckusick IUPDAT(ip, &time, &time, 0); 48537736Smckusick IUNLOCK(ip); 48638452Smckusick freeit: 48737736Smckusick ip->i_flag = 0; 48837736Smckusick /* 48937736Smckusick * Put the inode on the end of the free list. 49037736Smckusick * Possibly in some cases it would be better to 49137736Smckusick * put the inode at the head of the free list, 49237736Smckusick * (eg: where i_mode == 0 || i_number == 0). 49337736Smckusick */ 49437736Smckusick INSFREE(ip); 49537736Smckusick return (error); 49624Sbill } 49724Sbill 49824Sbill /* 49924Sbill * Check accessed and update flags on 50024Sbill * an inode structure. 50124Sbill * If any is on, update the inode 50224Sbill * with the current time. 5031203Sbill * If waitfor is given, then must insure 5041203Sbill * i/o order so wait for write to complete. 50524Sbill */ 5061203Sbill iupdat(ip, ta, tm, waitfor) 5074818Swnj register struct inode *ip; 5088630Sroot struct timeval *ta, *tm; 5094818Swnj int waitfor; 51024Sbill { 51137736Smckusick struct buf *bp; 51237736Smckusick struct vnode *vp = ITOV(ip); 51324Sbill struct dinode *dp; 51430749Skarels register struct fs *fs; 51537736Smckusick int error; 51624Sbill 51730749Skarels fs = ip->i_fs; 51837736Smckusick if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) 51937736Smckusick return (0); 52037736Smckusick if (vp->v_mount->m_flag & M_RDONLY) 52137736Smckusick return (0); 52237736Smckusick error = bread(ip->i_devvp, fsbtodb(fs, itod(fs, ip->i_number)), 52337736Smckusick (int)fs->fs_bsize, &bp); 52437736Smckusick if (error) { 52537736Smckusick brelse(bp); 52637736Smckusick return (error); 52724Sbill } 52837736Smckusick if (ip->i_flag&IACC) 52937736Smckusick ip->i_atime = ta->tv_sec; 53037736Smckusick if (ip->i_flag&IUPD) 53137736Smckusick ip->i_mtime = tm->tv_sec; 53237736Smckusick if (ip->i_flag&ICHG) 53337736Smckusick ip->i_ctime = time.tv_sec; 53437736Smckusick ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 53537736Smckusick dp = bp->b_un.b_dino + itoo(fs, ip->i_number); 53637736Smckusick dp->di_ic = ip->i_ic; 53737736Smckusick if (waitfor) { 53837736Smckusick return (bwrite(bp)); 53937736Smckusick } else { 54037736Smckusick bdwrite(bp); 54137736Smckusick return (0); 54237736Smckusick } 54324Sbill } 54424Sbill 54510736Ssam #define SINGLE 0 /* index of single indirect block */ 54610736Ssam #define DOUBLE 1 /* index of double indirect block */ 54710736Ssam #define TRIPLE 2 /* index of triple indirect block */ 54824Sbill /* 5497702Ssam * Truncate the inode ip to at most 5507702Ssam * length size. Free affected disk 5517702Ssam * blocks -- the blocks of the file 5527702Ssam * are removed in reverse order. 55310736Ssam * 55410736Ssam * NB: triple indirect blocks are untested. 55524Sbill */ 55610736Ssam itrunc(oip, length) 55717942Smckusick register struct inode *oip; 5589165Ssam u_long length; 55924Sbill { 5609165Ssam register daddr_t lastblock; 56126272Skarels daddr_t bn, lbn, lastiblock[NIADDR]; 5626569Smckusic register struct fs *fs; 56310736Ssam register struct inode *ip; 56417942Smckusick struct buf *bp; 56537736Smckusick int offset, osize, size, level; 56637736Smckusick long count, nblocks, blocksreleased = 0; 56717942Smckusick register int i; 56837736Smckusick int error, allerror = 0; 56910736Ssam struct inode tip; 5709165Ssam 57113000Ssam if (oip->i_size <= length) { 57213000Ssam oip->i_flag |= ICHG|IUPD; 57337736Smckusick error = iupdat(oip, &time, &time, 1); 57437736Smckusick return (error); 57513000Ssam } 5761203Sbill /* 57710736Ssam * Calculate index into inode's block list of 57810736Ssam * last direct and indirect blocks (if any) 57910736Ssam * which we want to keep. Lastblock is -1 when 58010736Ssam * the file is truncated to 0. 5811203Sbill */ 58210736Ssam fs = oip->i_fs; 5839165Ssam lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1; 58410736Ssam lastiblock[SINGLE] = lastblock - NDADDR; 58510736Ssam lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs); 58610736Ssam lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs); 58712645Ssam nblocks = btodb(fs->fs_bsize); 5886569Smckusic /* 58917942Smckusick * Update the size of the file. If the file is not being 59017942Smckusick * truncated to a block boundry, the contents of the 59117942Smckusick * partial block following the end of the file must be 59217942Smckusick * zero'ed in case it ever become accessable again because 59317942Smckusick * of subsequent file growth. 59417942Smckusick */ 59517942Smckusick osize = oip->i_size; 59617942Smckusick offset = blkoff(fs, length); 59717942Smckusick if (offset == 0) { 59817942Smckusick oip->i_size = length; 59917942Smckusick } else { 60017942Smckusick lbn = lblkno(fs, length); 60137736Smckusick error = balloc(oip, lbn, offset, &bn, B_CLRBUF); 60237736Smckusick if (error) 60337736Smckusick return (error); 60437736Smckusick if ((long)bn < 0) 60537736Smckusick panic("itrunc: hole"); 60617942Smckusick oip->i_size = length; 60717942Smckusick size = blksize(fs, oip, lbn); 60830749Skarels count = howmany(size, CLBYTES); 60930749Skarels for (i = 0; i < count; i++) 61037736Smckusick munhash(oip->i_devvp, bn + i * CLBYTES / DEV_BSIZE); 61137736Smckusick error = bread(oip->i_devvp, bn, size, &bp); 61237736Smckusick if (error) { 61317942Smckusick oip->i_size = osize; 61417942Smckusick brelse(bp); 61537736Smckusick return (error); 61617942Smckusick } 61726272Skarels bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 61817942Smckusick bdwrite(bp); 61917942Smckusick } 62017942Smckusick /* 62117942Smckusick * Update file and block pointers 62210736Ssam * on disk before we start freeing blocks. 62310736Ssam * If we crash before free'ing blocks below, 62410736Ssam * the blocks will be returned to the free list. 62510736Ssam * lastiblock values are also normalized to -1 62610736Ssam * for calls to indirtrunc below. 6276569Smckusic */ 62810736Ssam tip = *oip; 62917942Smckusick tip.i_size = osize; 63010736Ssam for (level = TRIPLE; level >= SINGLE; level--) 63110736Ssam if (lastiblock[level] < 0) { 63210736Ssam oip->i_ib[level] = 0; 63310736Ssam lastiblock[level] = -1; 6349165Ssam } 63510736Ssam for (i = NDADDR - 1; i > lastblock; i--) 63610736Ssam oip->i_db[i] = 0; 63710736Ssam oip->i_flag |= ICHG|IUPD; 63837736Smckusick allerror = syncip(oip); 63910736Ssam 6406569Smckusic /* 64110736Ssam * Indirect blocks first. 6426569Smckusic */ 64317942Smckusick ip = &tip; 64410736Ssam for (level = TRIPLE; level >= SINGLE; level--) { 64510736Ssam bn = ip->i_ib[level]; 6469165Ssam if (bn != 0) { 64737736Smckusick error = indirtrunc(ip, bn, lastiblock[level], level, 64837736Smckusick &count); 64937736Smckusick if (error) 65037736Smckusick allerror = error; 65137736Smckusick blocksreleased += count; 65210736Ssam if (lastiblock[level] < 0) { 65310736Ssam ip->i_ib[level] = 0; 65431402Smckusick blkfree(ip, bn, (off_t)fs->fs_bsize); 65510736Ssam blocksreleased += nblocks; 65610736Ssam } 65710736Ssam } 65810736Ssam if (lastiblock[level] >= 0) 65910736Ssam goto done; 6609165Ssam } 66110736Ssam 6626569Smckusic /* 66310736Ssam * All whole direct blocks or frags. 6646569Smckusic */ 6659165Ssam for (i = NDADDR - 1; i > lastblock; i--) { 66626359Skarels register off_t bsize; 6679165Ssam 6686569Smckusic bn = ip->i_db[i]; 6699165Ssam if (bn == 0) 67024Sbill continue; 6719165Ssam ip->i_db[i] = 0; 67224525Sbloom bsize = (off_t)blksize(fs, ip, i); 67331402Smckusick blkfree(ip, bn, bsize); 67424525Sbloom blocksreleased += btodb(bsize); 67524Sbill } 67610736Ssam if (lastblock < 0) 67710736Ssam goto done; 67810736Ssam 6791203Sbill /* 6809165Ssam * Finally, look for a change in size of the 6819165Ssam * last direct block; release any frags. 6821203Sbill */ 68310736Ssam bn = ip->i_db[lastblock]; 68410736Ssam if (bn != 0) { 68526359Skarels off_t oldspace, newspace; 68610736Ssam 6879165Ssam /* 6889165Ssam * Calculate amount of space we're giving 6899165Ssam * back as old block size minus new block size. 6909165Ssam */ 69110736Ssam oldspace = blksize(fs, ip, lastblock); 6929165Ssam ip->i_size = length; 69310736Ssam newspace = blksize(fs, ip, lastblock); 69410736Ssam if (newspace == 0) 69510736Ssam panic("itrunc: newspace"); 69610736Ssam if (oldspace - newspace > 0) { 6979165Ssam /* 6989165Ssam * Block number of space to be free'd is 6999165Ssam * the old block # plus the number of frags 7009165Ssam * required for the storage we're keeping. 7019165Ssam */ 70210736Ssam bn += numfrags(fs, newspace); 70331402Smckusick blkfree(ip, bn, oldspace - newspace); 70412645Ssam blocksreleased += btodb(oldspace - newspace); 7059165Ssam } 7069165Ssam } 7079165Ssam done: 70810736Ssam /* BEGIN PARANOIA */ 70910736Ssam for (level = SINGLE; level <= TRIPLE; level++) 71010736Ssam if (ip->i_ib[level] != oip->i_ib[level]) 71110736Ssam panic("itrunc1"); 71210736Ssam for (i = 0; i < NDADDR; i++) 71310736Ssam if (ip->i_db[i] != oip->i_db[i]) 71410736Ssam panic("itrunc2"); 71510736Ssam /* END PARANOIA */ 71612645Ssam oip->i_blocks -= blocksreleased; 71712645Ssam if (oip->i_blocks < 0) /* sanity */ 71812645Ssam oip->i_blocks = 0; 71912645Ssam oip->i_flag |= ICHG; 7209165Ssam #ifdef QUOTA 72112645Ssam (void) chkdq(oip, -blocksreleased, 0); 7229165Ssam #endif 72337736Smckusick return (allerror); 72424Sbill } 72524Sbill 7269165Ssam /* 7279165Ssam * Release blocks associated with the inode ip and 7289165Ssam * stored in the indirect block bn. Blocks are free'd 7299165Ssam * in LIFO order up to (but not including) lastbn. If 73010736Ssam * level is greater than SINGLE, the block is an indirect 73110736Ssam * block and recursive calls to indirtrunc must be used to 73210736Ssam * cleanse other indirect blocks. 73310736Ssam * 73410736Ssam * NB: triple indirect blocks are untested. 7359165Ssam */ 73637736Smckusick indirtrunc(ip, bn, lastbn, level, countp) 7376569Smckusic register struct inode *ip; 7389165Ssam daddr_t bn, lastbn; 73910736Ssam int level; 74037736Smckusick long *countp; 74124Sbill { 7429165Ssam register int i; 74331661Smckusick struct buf *bp; 74431661Smckusick register struct fs *fs = ip->i_fs; 74524Sbill register daddr_t *bap; 74631661Smckusick daddr_t *copy, nb, last; 74737736Smckusick long blkcount, factor; 74837736Smckusick int nblocks, blocksreleased = 0; 74937736Smckusick int error, allerror = 0; 75024Sbill 75110736Ssam /* 75210736Ssam * Calculate index in current block of last 75310736Ssam * block to be kept. -1 indicates the entire 75410736Ssam * block so we need not calculate the index. 75510736Ssam */ 75610736Ssam factor = 1; 75710736Ssam for (i = SINGLE; i < level; i++) 75810736Ssam factor *= NINDIR(fs); 7599165Ssam last = lastbn; 76010736Ssam if (lastbn > 0) 76110736Ssam last /= factor; 76212645Ssam nblocks = btodb(fs->fs_bsize); 76310736Ssam /* 76410736Ssam * Get buffer of block pointers, zero those 76510736Ssam * entries corresponding to blocks to be free'd, 76610736Ssam * and update on disk copy first. 76710736Ssam */ 76837736Smckusick error = bread(ip->i_devvp, fsbtodb(fs, bn), (int)fs->fs_bsize, &bp); 76937736Smckusick if (error) { 77010736Ssam brelse(bp); 77137736Smckusick *countp = 0; 77237736Smckusick return (error); 77310736Ssam } 77410736Ssam bap = bp->b_un.b_daddr; 77531661Smckusick MALLOC(copy, daddr_t *, fs->fs_bsize, M_TEMP, M_WAITOK); 77631661Smckusick bcopy((caddr_t)bap, (caddr_t)copy, (u_int)fs->fs_bsize); 77710736Ssam bzero((caddr_t)&bap[last + 1], 77810736Ssam (u_int)(NINDIR(fs) - (last + 1)) * sizeof (daddr_t)); 77937736Smckusick error = bwrite(bp); 78037736Smckusick if (error) 78137736Smckusick allerror = error; 78231661Smckusick bap = copy; 78310736Ssam 78410736Ssam /* 78510736Ssam * Recursively free totally unused blocks. 78610736Ssam */ 7879165Ssam for (i = NINDIR(fs) - 1; i > last; i--) { 78824Sbill nb = bap[i]; 7899165Ssam if (nb == 0) 79024Sbill continue; 79137736Smckusick if (level > SINGLE) { 79237736Smckusick error = indirtrunc(ip, nb, (daddr_t)-1, level - 1, 79337736Smckusick &blkcount); 79437736Smckusick if (error) 79537736Smckusick allerror = error; 79637736Smckusick blocksreleased += blkcount; 79737736Smckusick } 79831402Smckusick blkfree(ip, nb, (off_t)fs->fs_bsize); 7999165Ssam blocksreleased += nblocks; 80024Sbill } 80110736Ssam 80210736Ssam /* 80310736Ssam * Recursively free last partial block. 80410736Ssam */ 80510736Ssam if (level > SINGLE && lastbn >= 0) { 80610736Ssam last = lastbn % factor; 8079165Ssam nb = bap[i]; 80837736Smckusick if (nb != 0) { 80937736Smckusick error = indirtrunc(ip, nb, last, level - 1, &blkcount); 81037736Smckusick if (error) 81137736Smckusick allerror = error; 81237736Smckusick blocksreleased += blkcount; 81337736Smckusick } 8149165Ssam } 81531661Smckusick FREE(copy, M_TEMP); 81637736Smckusick *countp = blocksreleased; 81737736Smckusick return (allerror); 81824Sbill } 81924Sbill 82024Sbill /* 82130749Skarels * Remove any inodes in the inode cache belonging to dev. 8227334Skre * 8237334Skre * There should not be any active ones, return error if any are found 82430749Skarels * (nb: this is a user error, not a system err). 8257334Skre */ 8267651Ssam #ifdef QUOTA 8277504Sroot iflush(dev, iq) 8287492Skre dev_t dev; 8297504Sroot struct inode *iq; 8307492Skre #else 8317334Skre iflush(dev) 8327334Skre dev_t dev; 8337492Skre #endif 8347334Skre { 8357335Skre register struct inode *ip; 8367334Skre 8377334Skre for (ip = inode; ip < inodeNINODE; ip++) { 8387651Ssam #ifdef QUOTA 8397492Skre if (ip != iq && ip->i_dev == dev) 8407492Skre #else 8417334Skre if (ip->i_dev == dev) 8427492Skre #endif 84337736Smckusick if (ITOV(ip)->v_count) 84430749Skarels return (EBUSY); 8457334Skre else { 8467335Skre remque(ip); 8477334Skre ip->i_forw = ip; 8487334Skre ip->i_back = ip; 8497334Skre /* 85037736Smckusick * as v_count == 0, the inode was on the free 8517334Skre * list already, just leave it there, it will 8527334Skre * fall off the bottom eventually. We could 8537334Skre * perhaps move it to the head of the free 8547334Skre * list, but as umounts are done so 8557334Skre * infrequently, we would gain very little, 8567334Skre * while making the code bigger. 8577334Skre */ 8587651Ssam #ifdef QUOTA 8597492Skre dqrele(ip->i_dquot); 8607492Skre ip->i_dquot = NODQUOT; 8617492Skre #endif 86237736Smckusick if (ip->i_devvp) { 86337736Smckusick vrele(ip->i_devvp); 86437736Smckusick ip->i_devvp = 0; 86537736Smckusick } 8667334Skre } 8677334Skre } 86830749Skarels return (0); 8697334Skre } 8707334Skre 8713617Sroot /* 8724818Swnj * Lock an inode. If its already locked, set the WANT bit and sleep. 8733617Sroot */ 8744818Swnj ilock(ip) 8754818Swnj register struct inode *ip; 8763617Sroot { 8773617Sroot 87837736Smckusick while (ip->i_flag & ILOCKED) { 87937736Smckusick ip->i_flag |= IWANT; 88037736Smckusick (void) sleep((caddr_t)ip, PINOD); 88137736Smckusick } 88237736Smckusick ip->i_flag |= ILOCKED; 8833617Sroot } 8843617Sroot 8853617Sroot /* 8864818Swnj * Unlock an inode. If WANT bit is on, wakeup. 8873617Sroot */ 8887118Smckusick iunlock(ip) 8894818Swnj register struct inode *ip; 8903617Sroot { 8913617Sroot 89237736Smckusick if ((ip->i_flag & ILOCKED) == 0) 89337736Smckusick printf("unlocking unlocked inode %d on dev 0x%x\n", 89437736Smckusick ip->i_number, ip->i_dev); 89537736Smckusick ip->i_flag &= ~ILOCKED; 89637736Smckusick if (ip->i_flag&IWANT) { 89737736Smckusick ip->i_flag &= ~IWANT; 89837736Smckusick wakeup((caddr_t)ip); 89937736Smckusick } 9003617Sroot } 90137736Smckusick 90237736Smckusick /* 90337736Smckusick * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 90437736Smckusick * The mode is shifted to select the owner/group/other fields. The 90537736Smckusick * super user is granted all permissions. 90637736Smckusick * 90737736Smckusick * NB: Called from vnode op table. It seems this could all be done 90837736Smckusick * using vattr's but... 90937736Smckusick */ 91037736Smckusick iaccess(ip, mode, cred) 91137736Smckusick register struct inode *ip; 91237736Smckusick register int mode; 91337736Smckusick struct ucred *cred; 91437736Smckusick { 91537736Smckusick register gid_t *gp; 91637736Smckusick register struct vnode *vp = ITOV(ip); 91737736Smckusick int i; 91837736Smckusick 91937736Smckusick /* 92037736Smckusick * If you're the super-user, 92137736Smckusick * you always get access. 92237736Smckusick */ 92337736Smckusick if (cred->cr_uid == 0) 92437736Smckusick return (0); 92537736Smckusick /* 92637736Smckusick * Access check is based on only one of owner, group, public. 92737736Smckusick * If not owner, then check group. If not a member of the 92837736Smckusick * group, then check public access. 92937736Smckusick */ 93037736Smckusick if (cred->cr_uid != ip->i_uid) { 93137736Smckusick mode >>= 3; 93237736Smckusick gp = cred->cr_groups; 93337736Smckusick for (i = 0; i < cred->cr_ngroups; i++, gp++) 93437736Smckusick if (ip->i_gid == *gp) 93537736Smckusick goto found; 93637736Smckusick mode >>= 3; 93737736Smckusick found: 93837736Smckusick ; 93937736Smckusick } 94037736Smckusick if ((ip->i_mode & mode) != 0) 94137736Smckusick return (0); 94237736Smckusick return (EACCES); 94337736Smckusick } 944