1 /* 2 * Copyright (c) 1986, 1989, 1991 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)lfs_inode.c 7.50 (Berkeley) 12/19/91 8 */ 9 10 #include <sys/param.h> 11 #include <sys/systm.h> 12 #include <sys/mount.h> 13 #include <sys/proc.h> 14 #include <sys/file.h> 15 #include <sys/buf.h> 16 #include <sys/vnode.h> 17 #include <sys/kernel.h> 18 #include <sys/malloc.h> 19 20 #include <ufs/ufs/quota.h> 21 #include <ufs/ufs/inode.h> 22 #include <ufs/ufs/ufsmount.h> 23 #include <ufs/ufs/ufs_extern.h> 24 25 #include <ufs/lfs/lfs.h> 26 #include <ufs/lfs/lfs_extern.h> 27 28 int 29 lfs_init() 30 { 31 #ifdef VERBOSE 32 printf("lfs_init\n"); 33 #endif 34 return (ufs_init()); 35 } 36 37 /* 38 * Look up an LFS dinode number to find its incore vnode. If not already 39 * in core, read it in from the specified device. Return the inode locked. 40 * Detection and handling of mount points must be done by the calling routine. 41 */ 42 int 43 lfs_vget(mntp, ino, vpp) 44 struct mount *mntp; 45 ino_t ino; 46 struct vnode **vpp; 47 { 48 register struct lfs *fs; 49 register struct inode *ip; 50 struct buf *bp; 51 struct vnode *vp; 52 struct ufsmount *ump; 53 dev_t dev; 54 int error; 55 56 #ifdef VERBOSE 57 printf("lfs_vget\n"); 58 #endif 59 ump = VFSTOUFS(mntp); 60 dev = ump->um_dev; 61 if ((*vpp = ufs_ihashget(dev, ino)) != NULL) 62 return (0); 63 64 /* Allocate new vnode/inode. */ 65 if (error = lfs_vcreate(mntp, ino, &vp)) { 66 *vpp = NULL; 67 return (error); 68 } 69 /* 70 * Put it onto its hash chain and lock it so that other requests for 71 * this inode will block if they arrive while we are sleeping waiting 72 * for old data structures to be purged or for the contents of the 73 * disk portion of this inode to be read. 74 */ 75 ip = VTOI(vp); 76 ufs_ihashins(ip); 77 78 /* Read in the disk contents for the inode, copy into the inode. */ 79 ip->i_lfs = fs = ump->um_lfs; 80 if (error = bread(ump->um_devvp, lfs_itod(fs, ino), 81 (int)fs->lfs_bsize, NOCRED, &bp)) { 82 /* 83 * The inode does not contain anything useful, so it 84 * would be misleading to leave it on its hash chain. 85 * Iput() will return it to the free list. 86 */ 87 remque(ip); 88 ip->i_forw = ip; 89 ip->i_back = ip; 90 91 /* Unlock and discard unneeded inode. */ 92 ufs_iput(ip); 93 brelse(bp); 94 *vpp = NULL; 95 return (error); 96 } 97 ip->i_din = *lfs_ifind(fs, ino, bp->b_un.b_dino); 98 brelse(bp); 99 100 /* 101 * Initialize the vnode from the inode, check for aliases. In all 102 * cases re-init ip, the underlying vnode/inode may have changed. 103 */ 104 if (error = ufs_vinit(mntp, &lfs_specops, LFS_FIFOOPS, &vp)) { 105 ufs_iput(ip); 106 *vpp = NULL; 107 return (error); 108 } 109 /* 110 * Finish inode initialization now that aliasing has been resolved. 111 */ 112 ip->i_devvp = ump->um_devvp; 113 VREF(ip->i_devvp); 114 *vpp = vp; 115 return (0); 116 } 117 118 int 119 lfs_update(vp, ta, tm, waitfor) 120 register struct vnode *vp; 121 struct timeval *ta, *tm; 122 int waitfor; 123 { 124 struct inode *ip; 125 126 #ifdef VERBOSE 127 printf("lfs_update\n"); 128 #endif 129 if (vp->v_mount->mnt_flag & MNT_RDONLY) 130 return (0); 131 ip = VTOI(vp); 132 if ((ip->i_flag & (IUPD|IACC|ICHG|IMOD)) == 0) 133 return (0); 134 if (ip->i_flag&IACC) 135 ip->i_atime = ta->tv_sec; 136 if (ip->i_flag&IUPD) { 137 ip->i_mtime = tm->tv_sec; 138 INCRQUAD((ip)->i_modrev); 139 } 140 if (ip->i_flag&ICHG) 141 ip->i_ctime = time.tv_sec; 142 ip->i_flag &= ~(IUPD|IACC|ICHG|IMOD); 143 144 /* 145 * XXX 146 * I'm not real sure what to do here; once we have fsync and partial 147 * segments working in the LFS context, this must be fixed to be 148 * correct. The contents of the inode have to be pushed back to 149 * stable storage; note that the ifile contains the access time of 150 * the inode and must be updated as well. 151 */ 152 return (0); 153 } 154 155 /* 156 * Truncate the inode ip to at most length size. 157 * 158 * NB: triple indirect blocks are untested. 159 */ 160 /* ARGSUSED */ 161 int 162 lfs_truncate(ovp, length, flags) 163 struct vnode *ovp; 164 u_long length; 165 int flags; 166 { 167 register struct lfs *fs; 168 register struct inode *oip; 169 struct buf *bp; 170 daddr_t lbn; 171 int error, offset, size; 172 173 #ifdef VERBOSE 174 printf("lfs_truncate\n"); 175 #endif 176 vnode_pager_setsize(ovp, length); 177 oip = VTOI(ovp); 178 179 /* If length is larger than the file, just update the times. */ 180 if (oip->i_size <= length) { 181 oip->i_flag |= ICHG|IUPD; 182 ITIMES(oip, &time, &time); 183 return (0); 184 } 185 186 /* 187 * Update the size of the file. If the file is not being truncated to 188 * a block boundry, the contents of the partial block following the end 189 * of the file must be zero'ed in case it ever become accessable again 190 * because of subsequent file growth. 191 */ 192 fs = oip->i_lfs; 193 offset = blkoff(fs, length); 194 if (offset == 0) 195 oip->i_size = length; 196 else { 197 lbn = lblkno(fs, length); 198 #ifdef QUOTA 199 if (error = getinoquota(oip)) 200 return (error); 201 #endif 202 if (error = bread(ovp, lbn, fs->lfs_bsize, NOCRED, &bp)) 203 return (error); 204 oip->i_size = length; 205 size = blksize(fs); 206 (void)vnode_pager_uncache(ovp); 207 bzero(bp->b_un.b_addr + offset, (unsigned)(size - offset)); 208 allocbuf(bp, size); 209 lfs_bwrite(bp); 210 } 211 /* XXX: BZERO INODE BLOCK POINTERS HERE, FOR CONSISTENCY. */ 212 (void)vinvalbuf(ovp, length > 0); 213 return (0); 214 } 215