|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* $NetBSD: lfs_inode.c,v 1.2 1994/06/29 06:46:57 cgd Exp $ */ ! 23: ! 24: /* ! 25: * Copyright (c) 1986, 1989, 1991, 1993 ! 26: * The Regents of the University of California. All rights reserved. ! 27: * ! 28: * Redistribution and use in source and binary forms, with or without ! 29: * modification, are permitted provided that the following conditions ! 30: * are met: ! 31: * 1. Redistributions of source code must retain the above copyright ! 32: * notice, this list of conditions and the following disclaimer. ! 33: * 2. Redistributions in binary form must reproduce the above copyright ! 34: * notice, this list of conditions and the following disclaimer in the ! 35: * documentation and/or other materials provided with the distribution. ! 36: * 3. All advertising materials mentioning features or use of this software ! 37: * must display the following acknowledgement: ! 38: * This product includes software developed by the University of ! 39: * California, Berkeley and its contributors. ! 40: * 4. Neither the name of the University nor the names of its contributors ! 41: * may be used to endorse or promote products derived from this software ! 42: * without specific prior written permission. ! 43: * ! 44: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 45: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 46: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 47: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 48: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 49: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 50: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 51: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 52: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 53: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 54: * SUCH DAMAGE. ! 55: * ! 56: * @(#)lfs_inode.c 8.5 (Berkeley) 12/30/93 ! 57: */ ! 58: ! 59: #include <sys/param.h> ! 60: #include <sys/systm.h> ! 61: #include <sys/mount.h> ! 62: #include <sys/proc.h> ! 63: #include <sys/file.h> ! 64: #include <sys/buf.h> ! 65: #include <sys/vnode.h> ! 66: #include <sys/kernel.h> ! 67: #include <sys/malloc.h> ! 68: ! 69: #include <vm/vm.h> ! 70: ! 71: #include <ufs/ufs/quota.h> ! 72: #include <ufs/ufs/inode.h> ! 73: #include <ufs/ufs/ufsmount.h> ! 74: #include <ufs/ufs/ufs_extern.h> ! 75: ! 76: #include <ufs/lfs/lfs.h> ! 77: #include <ufs/lfs/lfs_extern.h> ! 78: ! 79: int ! 80: lfs_init() ! 81: { ! 82: return (ufs_init()); ! 83: } ! 84: ! 85: /* Search a block for a specific dinode. */ ! 86: struct dinode * ! 87: lfs_ifind(fs, ino, dip) ! 88: struct lfs *fs; ! 89: ino_t ino; ! 90: register struct dinode *dip; ! 91: { ! 92: register int cnt; ! 93: register struct dinode *ldip; ! 94: ! 95: for (cnt = INOPB(fs), ldip = dip + (cnt - 1); cnt--; --ldip) ! 96: if (ldip->di_inumber == ino) ! 97: return (ldip); ! 98: ! 99: panic("lfs_ifind: dinode %u not found", ino); ! 100: /* NOTREACHED */ ! 101: } ! 102: ! 103: int ! 104: lfs_update(ap) ! 105: struct vop_update_args /* { ! 106: struct vnode *a_vp; ! 107: struct timeval *a_access; ! 108: struct timeval *a_modify; ! 109: int a_waitfor; ! 110: } */ *ap; ! 111: { ! 112: struct vnode *vp = ap->a_vp; ! 113: struct inode *ip; ! 114: ! 115: if (vp->v_mount->mnt_flag & MNT_RDONLY) ! 116: return (0); ! 117: ip = VTOI(vp); ! 118: if ((ip->i_flag & ! 119: (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) ! 120: return (0); ! 121: if (ip->i_flag & IN_ACCESS) ! 122: ip->i_atime.tv_sec = ap->a_access->tv_sec; ! 123: if (ip->i_flag & IN_UPDATE) { ! 124: ip->i_mtime.tv_sec = ap->a_modify->tv_sec; ! 125: (ip)->i_modrev++; ! 126: } ! 127: if (ip->i_flag & IN_CHANGE) ! 128: ip->i_ctime.tv_sec = time.tv_sec; ! 129: ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); ! 130: ! 131: if (!(ip->i_flag & IN_MODIFIED)) ! 132: ++(VFSTOUFS(vp->v_mount)->um_lfs->lfs_uinodes); ! 133: ip->i_flag |= IN_MODIFIED; ! 134: ! 135: /* If sync, push back the vnode and any dirty blocks it may have. */ ! 136: return (ap->a_waitfor & LFS_SYNC ? lfs_vflush(vp) : 0); ! 137: } ! 138: ! 139: /* Update segment usage information when removing a block. */ ! 140: #define UPDATE_SEGUSE \ ! 141: if (lastseg != -1) { \ ! 142: LFS_SEGENTRY(sup, fs, lastseg, sup_bp); \ ! 143: if ((num << fs->lfs_bshift) > sup->su_nbytes) \ ! 144: panic("lfs_truncate: negative bytes in segment %d\n", \ ! 145: lastseg); \ ! 146: sup->su_nbytes -= num << fs->lfs_bshift; \ ! 147: e1 = VOP_BWRITE(sup_bp); \ ! 148: blocksreleased += num; \ ! 149: } ! 150: ! 151: #define SEGDEC { \ ! 152: if (daddr != 0) { \ ! 153: if (lastseg != (seg = datosn(fs, daddr))) { \ ! 154: UPDATE_SEGUSE; \ ! 155: num = 1; \ ! 156: lastseg = seg; \ ! 157: } else \ ! 158: ++num; \ ! 159: } \ ! 160: } ! 161: ! 162: /* ! 163: * Truncate the inode ip to at most length size. Update segment usage ! 164: * table information. ! 165: */ ! 166: /* ARGSUSED */ ! 167: int ! 168: lfs_truncate(ap) ! 169: struct vop_truncate_args /* { ! 170: struct vnode *a_vp; ! 171: off_t a_length; ! 172: int a_flags; ! 173: struct ucred *a_cred; ! 174: struct proc *a_p; ! 175: } */ *ap; ! 176: { ! 177: register struct indir *inp; ! 178: register int i; ! 179: register daddr_t *daddrp; ! 180: register struct vnode *vp = ap->a_vp; ! 181: off_t length = ap->a_length; ! 182: struct buf *bp, *sup_bp; ! 183: struct timeval tv; ! 184: struct ifile *ifp; ! 185: struct inode *ip; ! 186: struct lfs *fs; ! 187: struct indir a[NIADDR + 2], a_end[NIADDR + 2]; ! 188: SEGUSE *sup; ! 189: daddr_t daddr, lastblock, lbn, olastblock; ! 190: long off, a_released, blocksreleased, i_released; ! 191: int e1, e2, depth, lastseg, num, offset, seg, size; ! 192: ! 193: ip = VTOI(vp); ! 194: tv = time; ! 195: if (vp->v_type == VLNK && vp->v_mount->mnt_maxsymlinklen > 0) { ! 196: #if DIAGNOSTIC ! 197: if (length != 0) ! 198: panic("lfs_truncate: partial truncate of symlink"); ! 199: #endif ! 200: bzero((char *)&ip->i_shortlink, (u_int)ip->i_size); ! 201: ip->i_size = 0; ! 202: ip->i_flag |= IN_CHANGE | IN_UPDATE; ! 203: return (VOP_UPDATE(vp, &tv, &tv, 0)); ! 204: } ! 205: vnode_pager_setsize(vp, (u_long)length); ! 206: ! 207: fs = ip->i_lfs; ! 208: ! 209: /* If length is larger than the file, just update the times. */ ! 210: if (ip->i_size <= length) { ! 211: ip->i_flag |= IN_CHANGE | IN_UPDATE; ! 212: return (VOP_UPDATE(vp, &tv, &tv, 0)); ! 213: } ! 214: ! 215: /* ! 216: * Calculate index into inode's block list of last direct and indirect ! 217: * blocks (if any) which we want to keep. Lastblock is 0 when the ! 218: * file is truncated to 0. ! 219: */ ! 220: lastblock = lblkno(fs, length + fs->lfs_bsize - 1); ! 221: olastblock = lblkno(fs, ip->i_size + fs->lfs_bsize - 1) - 1; ! 222: ! 223: /* ! 224: * Update the size of the file. If the file is not being truncated to ! 225: * a block boundry, the contents of the partial block following the end ! 226: * of the file must be zero'ed in case it ever become accessable again ! 227: * because of subsequent file growth. ! 228: */ ! 229: offset = blkoff(fs, length); ! 230: if (offset == 0) ! 231: ip->i_size = length; ! 232: else { ! 233: lbn = lblkno(fs, length); ! 234: #if QUOTA ! 235: if (e1 = getinoquota(ip)) ! 236: return (e1); ! 237: #endif ! 238: if (e1 = bread(vp, lbn, fs->lfs_bsize, NOCRED, &bp)) ! 239: return (e1); ! 240: ip->i_size = length; ! 241: size = blksize(fs); ! 242: (void)vnode_pager_uncache(vp); ! 243: bzero((char *)bp->b_data + offset, (u_int)(size - offset)); ! 244: allocbuf(bp, size); ! 245: if (e1 = VOP_BWRITE(bp)) ! 246: return (e1); ! 247: } ! 248: /* ! 249: * Modify sup->su_nbyte counters for each deleted block; keep track ! 250: * of number of blocks removed for ip->i_blocks. ! 251: */ ! 252: blocksreleased = 0; ! 253: num = 0; ! 254: lastseg = -1; ! 255: ! 256: for (lbn = olastblock; lbn >= lastblock;) { ! 257: /* XXX use run length from bmap array to make this faster */ ! 258: ufs_bmaparray(vp, lbn, &daddr, a, &depth, NULL); ! 259: if (lbn == olastblock) ! 260: for (i = NIADDR + 2; i--;) ! 261: a_end[i] = a[i]; ! 262: switch (depth) { ! 263: case 0: /* Direct block. */ ! 264: daddr = ip->i_db[lbn]; ! 265: SEGDEC; ! 266: ip->i_db[lbn] = 0; ! 267: --lbn; ! 268: break; ! 269: #if DIAGNOSTIC ! 270: case 1: /* An indirect block. */ ! 271: panic("lfs_truncate: ufs_bmaparray returned depth 1"); ! 272: /* NOTREACHED */ ! 273: #endif ! 274: default: /* Chain of indirect blocks. */ ! 275: inp = a + --depth; ! 276: if (inp->in_off > 0 && lbn != lastblock) { ! 277: lbn -= inp->in_off < lbn - lastblock ? ! 278: inp->in_off : lbn - lastblock; ! 279: break; ! 280: } ! 281: for (; depth && (inp->in_off == 0 || lbn == lastblock); ! 282: --inp, --depth) { ! 283: if (bread(vp, ! 284: inp->in_lbn, fs->lfs_bsize, NOCRED, &bp)) ! 285: panic("lfs_truncate: bread bno %d", ! 286: inp->in_lbn); ! 287: daddrp = (daddr_t *)bp->b_data + inp->in_off; ! 288: for (i = inp->in_off; ! 289: i++ <= a_end[depth].in_off;) { ! 290: daddr = *daddrp++; ! 291: SEGDEC; ! 292: } ! 293: a_end[depth].in_off = NINDIR(fs) - 1; ! 294: if (inp->in_off == 0) ! 295: brelse (bp); ! 296: else { ! 297: bzero((daddr_t *)bp->b_data + ! 298: inp->in_off, fs->lfs_bsize - ! 299: inp->in_off * sizeof(daddr_t)); ! 300: if (e1 = VOP_BWRITE(bp)) ! 301: return (e1); ! 302: } ! 303: } ! 304: if (depth == 0 && a[1].in_off == 0) { ! 305: off = a[0].in_off; ! 306: daddr = ip->i_ib[off]; ! 307: SEGDEC; ! 308: ip->i_ib[off] = 0; ! 309: } ! 310: if (lbn == lastblock || lbn <= NDADDR) ! 311: --lbn; ! 312: else { ! 313: lbn -= NINDIR(fs); ! 314: if (lbn < lastblock) ! 315: lbn = lastblock; ! 316: } ! 317: } ! 318: } ! 319: UPDATE_SEGUSE; ! 320: ! 321: /* If truncating the file to 0, update the version number. */ ! 322: if (length == 0) { ! 323: LFS_IENTRY(ifp, fs, ip->i_number, bp); ! 324: ++ifp->if_version; ! 325: (void) VOP_BWRITE(bp); ! 326: } ! 327: ! 328: #if DIAGNOSTIC ! 329: if (ip->i_blocks < fsbtodb(fs, blocksreleased)) { ! 330: printf("lfs_truncate: block count < 0\n"); ! 331: blocksreleased = ip->i_blocks; ! 332: } ! 333: #endif ! 334: ip->i_blocks -= fsbtodb(fs, blocksreleased); ! 335: fs->lfs_bfree += fsbtodb(fs, blocksreleased); ! 336: ip->i_flag |= IN_CHANGE | IN_UPDATE; ! 337: /* ! 338: * Traverse dirty block list counting number of dirty buffers ! 339: * that are being deleted out of the cache, so that the lfs_avail ! 340: * field can be updated. ! 341: */ ! 342: a_released = 0; ! 343: i_released = 0; ! 344: for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = bp->b_vnbufs.le_next) ! 345: if (bp->b_flags & B_LOCKED) { ! 346: ++a_released; ! 347: /* ! 348: * XXX ! 349: * When buffers are created in the cache, their block ! 350: * number is set equal to their logical block number. ! 351: * If that is still true, we are assuming that the ! 352: * blocks are new (not yet on disk) and weren't ! 353: * counted above. However, there is a slight chance ! 354: * that a block's disk address is equal to its logical ! 355: * block number in which case, we'll get an overcounting ! 356: * here. ! 357: */ ! 358: if (bp->b_blkno == bp->b_lblkno) ! 359: ++i_released; ! 360: } ! 361: blocksreleased = fsbtodb(fs, i_released); ! 362: #if DIAGNOSTIC ! 363: if (blocksreleased > ip->i_blocks) { ! 364: printf("lfs_inode: Warning! %s\n", ! 365: "more blocks released from inode than are in inode"); ! 366: blocksreleased = ip->i_blocks; ! 367: } ! 368: #endif ! 369: fs->lfs_bfree += blocksreleased; ! 370: ip->i_blocks -= blocksreleased; ! 371: #if DIAGNOSTIC ! 372: if (length == 0 && ip->i_blocks != 0) ! 373: printf("lfs_inode: Warning! %s%d%s\n", ! 374: "Truncation to zero, but ", ip->i_blocks, ! 375: " blocks left on inode"); ! 376: #endif ! 377: fs->lfs_avail += fsbtodb(fs, a_released); ! 378: e1 = vinvalbuf(vp, (length > 0) ? V_SAVE : 0, ap->a_cred, ap->a_p, ! 379: 0, 0); ! 380: e2 = VOP_UPDATE(vp, &tv, &tv, 0); ! 381: return (e1 ? e1 : e2 ? e2 : 0); ! 382: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.