Annotation of XNU/bsd/ufs/lfs/lfs_inode.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.