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