[BACK]Return to ufs_readwrite.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / ufs / ufs

Annotation of src/sys/ufs/ufs/ufs_readwrite.c, Revision 1.37

1.37    ! lukem       1: /*     $NetBSD: ufs_readwrite.c,v 1.36 2001/10/03 05:02:46 chs Exp $   */
1.3       cgd         2:
1.1       mycroft     3: /*-
                      4:  * Copyright (c) 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by the University of
                     18:  *     California, Berkeley and its contributors.
                     19:  * 4. Neither the name of the University nor the names of its contributors
                     20:  *    may be used to endorse or promote products derived from this software
                     21:  *    without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     33:  * SUCH DAMAGE.
                     34:  *
1.16      fvdl       35:  *     @(#)ufs_readwrite.c     8.11 (Berkeley) 5/8/95
1.1       mycroft    36:  */
1.37    ! lukem      37:
        !            38: #include <sys/cdefs.h>
        !            39: __KERNEL_RCSID(1, "$NetBSD$");
1.15      mrg        40:
1.1       mycroft    41: #ifdef LFS_READWRITE
1.16      fvdl       42: #define        BLKSIZE(a, b, c)        blksize(a, b, c)
1.1       mycroft    43: #define        FS                      struct lfs
                     44: #define        I_FS                    i_lfs
                     45: #define        READ                    lfs_read
                     46: #define        READ_S                  "lfs_read"
                     47: #define        WRITE                   lfs_write
                     48: #define        WRITE_S                 "lfs_write"
                     49: #define        fs_bsize                lfs_bsize
                     50: #define        fs_maxfilesize          lfs_maxfilesize
                     51: #else
                     52: #define        BLKSIZE(a, b, c)        blksize(a, b, c)
                     53: #define        FS                      struct fs
                     54: #define        I_FS                    i_fs
                     55: #define        READ                    ffs_read
                     56: #define        READ_S                  "ffs_read"
                     57: #define        WRITE                   ffs_write
                     58: #define        WRITE_S                 "ffs_write"
                     59: #endif
                     60:
                     61: /*
                     62:  * Vnode op for reading.
                     63:  */
                     64: /* ARGSUSED */
1.8       christos   65: int
1.29      lukem      66: READ(void *v)
1.8       christos   67: {
1.1       mycroft    68:        struct vop_read_args /* {
                     69:                struct vnode *a_vp;
                     70:                struct uio *a_uio;
                     71:                int a_ioflag;
                     72:                struct ucred *a_cred;
1.8       christos   73:        } */ *ap = v;
1.24      augustss   74:        struct vnode *vp;
                     75:        struct inode *ip;
                     76:        struct uio *uio;
                     77:        FS *fs;
1.28      chs        78:        void *win;
                     79:        vsize_t bytelen;
1.1       mycroft    80:        struct buf *bp;
1.16      fvdl       81:        ufs_daddr_t lbn, nextlbn;
1.1       mycroft    82:        off_t bytesinfile;
                     83:        long size, xfersize, blkoffset;
                     84:        int error;
1.34      chs        85:        boolean_t usepc = FALSE;
1.1       mycroft    86:
                     87:        vp = ap->a_vp;
                     88:        ip = VTOI(vp);
                     89:        uio = ap->a_uio;
1.28      chs        90:        error = 0;
1.1       mycroft    91:
                     92: #ifdef DIAGNOSTIC
                     93:        if (uio->uio_rw != UIO_READ)
                     94:                panic("%s: mode", READ_S);
                     95:
                     96:        if (vp->v_type == VLNK) {
1.12      bouyer     97:                if ((int)ip->i_ffs_size < vp->v_mount->mnt_maxsymlinklen ||
1.2       mycroft    98:                    (vp->v_mount->mnt_maxsymlinklen == 0 &&
1.12      bouyer     99:                     ip->i_ffs_blocks == 0))
1.1       mycroft   100:                        panic("%s: short symlink", READ_S);
                    101:        } else if (vp->v_type != VREG && vp->v_type != VDIR)
                    102:                panic("%s: type %d", READ_S, vp->v_type);
                    103: #endif
                    104:        fs = ip->I_FS;
1.4       cgd       105:        if ((u_int64_t)uio->uio_offset > fs->fs_maxfilesize)
1.1       mycroft   106:                return (EFBIG);
1.11      kleink    107:        if (uio->uio_resid == 0)
                    108:                return (0);
1.28      chs       109:        if (uio->uio_offset >= ip->i_ffs_size) {
                    110:                goto out;
                    111:        }
                    112:
1.34      chs       113: #ifndef LFS_READWRITE
                    114:        usepc = vp->v_type == VREG;
                    115: #endif
                    116:        if (usepc) {
1.28      chs       117:                while (uio->uio_resid > 0) {
1.30      chs       118:                        bytelen = MIN(ip->i_ffs_size - uio->uio_offset,
1.28      chs       119:                            uio->uio_resid);
                    120:                        if (bytelen == 0)
                    121:                                break;
                    122:
1.33      chs       123:                        win = ubc_alloc(&vp->v_uobj, uio->uio_offset,
1.28      chs       124:                                        &bytelen, UBC_READ);
                    125:                        error = uiomove(win, bytelen, uio);
                    126:                        ubc_release(win, 0);
                    127:                        if (error)
                    128:                                break;
                    129:                }
                    130:                goto out;
                    131:        }
1.1       mycroft   132:
                    133:        for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
1.28      chs       134:                bytesinfile = ip->i_ffs_size - uio->uio_offset;
                    135:                if (bytesinfile <= 0)
1.1       mycroft   136:                        break;
                    137:                lbn = lblkno(fs, uio->uio_offset);
                    138:                nextlbn = lbn + 1;
                    139:                size = BLKSIZE(fs, ip, lbn);
                    140:                blkoffset = blkoff(fs, uio->uio_offset);
1.30      chs       141:                xfersize = MIN(MIN(fs->fs_bsize - blkoffset, uio->uio_resid),
1.28      chs       142:                    bytesinfile);
1.1       mycroft   143:
1.19      bouyer    144:                if (lblktosize(fs, nextlbn) >= ip->i_ffs_size)
1.1       mycroft   145:                        error = bread(vp, lbn, size, NOCRED, &bp);
1.33      chs       146:                else {
1.1       mycroft   147:                        int nextsize = BLKSIZE(fs, ip, nextlbn);
                    148:                        error = breadn(vp, lbn,
                    149:                            size, &nextlbn, &nextsize, 1, NOCRED, &bp);
1.33      chs       150:                }
1.1       mycroft   151:                if (error)
                    152:                        break;
                    153:
                    154:                /*
                    155:                 * We should only get non-zero b_resid when an I/O error
                    156:                 * has occurred, which should cause us to break above.
                    157:                 * However, if the short read did not cause an error,
                    158:                 * then we want to ensure that we do not uiomove bad
                    159:                 * or uninitialized data.
                    160:                 */
                    161:                size -= bp->b_resid;
                    162:                if (size < xfersize) {
                    163:                        if (size == 0)
                    164:                                break;
                    165:                        xfersize = size;
                    166:                }
1.28      chs       167:                error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
1.8       christos  168:                if (error)
1.1       mycroft   169:                        break;
                    170:                brelse(bp);
                    171:        }
                    172:        if (bp != NULL)
                    173:                brelse(bp);
1.28      chs       174:
1.29      lukem     175:  out:
1.18      kleink    176:        if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
1.10      tls       177:                ip->i_flag |= IN_ACCESS;
1.20      mycroft   178:                if ((ap->a_ioflag & IO_SYNC) == IO_SYNC)
1.25      perseant  179:                        error = VOP_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
1.18      kleink    180:        }
1.1       mycroft   181:        return (error);
                    182: }
                    183:
                    184: /*
                    185:  * Vnode op for writing.
                    186:  */
1.8       christos  187: int
1.29      lukem     188: WRITE(void *v)
1.8       christos  189: {
1.1       mycroft   190:        struct vop_write_args /* {
                    191:                struct vnode *a_vp;
                    192:                struct uio *a_uio;
                    193:                int a_ioflag;
                    194:                struct ucred *a_cred;
1.8       christos  195:        } */ *ap = v;
1.24      augustss  196:        struct vnode *vp;
                    197:        struct uio *uio;
                    198:        struct inode *ip;
1.33      chs       199:        struct genfs_node *gp;
1.24      augustss  200:        FS *fs;
1.1       mycroft   201:        struct buf *bp;
                    202:        struct proc *p;
1.33      chs       203:        struct ucred *cred;
1.16      fvdl      204:        ufs_daddr_t lbn;
1.33      chs       205:        off_t osize, origoff, oldoff, preallocoff, endallocoff, nsize;
1.1       mycroft   206:        int blkoffset, error, flags, ioflag, resid, size, xfersize;
1.33      chs       207:        int bsize, aflag;
                    208:        int ubc_alloc_flags;
1.28      chs       209:        void *win;
                    210:        vsize_t bytelen;
1.36      chs       211:        boolean_t async;
1.34      chs       212:        boolean_t usepc = FALSE;
1.1       mycroft   213:
1.33      chs       214:        cred = ap->a_cred;
1.1       mycroft   215:        ioflag = ap->a_ioflag;
                    216:        uio = ap->a_uio;
                    217:        vp = ap->a_vp;
                    218:        ip = VTOI(vp);
1.33      chs       219:        gp = VTOG(vp);
1.1       mycroft   220:
1.33      chs       221:        KASSERT(vp->v_size == ip->i_ffs_size);
1.1       mycroft   222: #ifdef DIAGNOSTIC
                    223:        if (uio->uio_rw != UIO_WRITE)
                    224:                panic("%s: mode", WRITE_S);
                    225: #endif
                    226:
                    227:        switch (vp->v_type) {
                    228:        case VREG:
                    229:                if (ioflag & IO_APPEND)
1.12      bouyer    230:                        uio->uio_offset = ip->i_ffs_size;
                    231:                if ((ip->i_ffs_flags & APPEND) && uio->uio_offset != ip->i_ffs_size)
1.1       mycroft   232:                        return (EPERM);
                    233:                /* FALLTHROUGH */
                    234:        case VLNK:
                    235:                break;
                    236:        case VDIR:
                    237:                if ((ioflag & IO_SYNC) == 0)
                    238:                        panic("%s: nonsync dir write", WRITE_S);
                    239:                break;
                    240:        default:
                    241:                panic("%s: type", WRITE_S);
                    242:        }
                    243:
                    244:        fs = ip->I_FS;
                    245:        if (uio->uio_offset < 0 ||
1.4       cgd       246:            (u_int64_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize)
1.1       mycroft   247:                return (EFBIG);
1.26      perseant  248: #ifdef LFS_READWRITE
                    249:        /* Disallow writes to the Ifile, even if noschg flag is removed */
                    250:        /* XXX can this go away when the Ifile is no longer in the namespace? */
                    251:        if (vp == fs->lfs_ivnode)
                    252:                return (EPERM);
                    253: #endif
                    254:
1.1       mycroft   255:        /*
                    256:         * Maybe this should be above the vnode op call, but so long as
                    257:         * file servers have no limits, I don't think it matters.
                    258:         */
                    259:        p = uio->uio_procp;
                    260:        if (vp->v_type == VREG && p &&
                    261:            uio->uio_offset + uio->uio_resid >
                    262:            p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
                    263:                psignal(p, SIGXFSZ);
                    264:                return (EFBIG);
                    265:        }
                    266:
1.36      chs       267:        async = vp->v_mount->mnt_flag & MNT_ASYNC;
1.1       mycroft   268:        resid = uio->uio_resid;
1.12      bouyer    269:        osize = ip->i_ffs_size;
1.33      chs       270:        bsize = fs->fs_bsize;
1.28      chs       271:        error = 0;
                    272:
1.34      chs       273: #ifndef LFS_READWRITE
                    274:        usepc = vp->v_type == VREG;
                    275: #endif
                    276:        if (!usepc) {
1.28      chs       277:                goto bcache;
                    278:        }
                    279:
1.33      chs       280:        preallocoff = round_page(blkroundup(fs, MAX(osize, uio->uio_offset)));
                    281:        aflag = ioflag & IO_SYNC ? B_SYNC : 0;
                    282:        nsize = MAX(osize, uio->uio_offset + uio->uio_resid);
                    283:        endallocoff = nsize - blkoff(fs, nsize);
                    284:
                    285:        /*
                    286:         * if we're increasing the file size, deal with expanding
                    287:         * the fragment if there is one.
                    288:         */
                    289:
                    290:        if (nsize > osize && lblkno(fs, osize) < NDADDR &&
                    291:            lblkno(fs, osize) != lblkno(fs, nsize) &&
                    292:            blkroundup(fs, osize) != osize) {
                    293:                error = ufs_balloc_range(vp, osize, blkroundup(fs, osize) -
                    294:                    osize, cred, aflag);
                    295:                if (error) {
                    296:                        goto out;
                    297:                }
                    298:        }
                    299:
                    300:        ubc_alloc_flags = UBC_WRITE;
                    301:        origoff = uio->uio_offset;
1.28      chs       302:        while (uio->uio_resid > 0) {
                    303:                oldoff = uio->uio_offset;
                    304:                blkoffset = blkoff(fs, uio->uio_offset);
1.30      chs       305:                bytelen = MIN(fs->fs_bsize - blkoffset, uio->uio_resid);
1.28      chs       306:
                    307:                /*
1.33      chs       308:                 * if we're filling in a hole, allocate the blocks now and
                    309:                 * initialize the pages first.  if we're extending the file,
                    310:                 * we can safely allocate blocks without initializing pages
                    311:                 * since the new blocks will be inaccessible until the write
                    312:                 * is complete.
1.28      chs       313:                 */
                    314:
1.33      chs       315:                if (uio->uio_offset < preallocoff ||
                    316:                    uio->uio_offset >= endallocoff) {
                    317:                        error = ufs_balloc_range(vp, uio->uio_offset, bytelen,
                    318:                            cred, aflag);
                    319:                        if (error) {
                    320:                                break;
                    321:                        }
                    322:                        ubc_alloc_flags &= ~UBC_FAULTBUSY;
1.35      chs       323:                } else {
1.33      chs       324:                        lockmgr(&gp->g_glock, LK_EXCLUSIVE, NULL);
1.35      chs       325:                        error = GOP_ALLOC(vp, uio->uio_offset, bytelen,
1.33      chs       326:                            aflag, cred);
                    327:                        lockmgr(&gp->g_glock, LK_RELEASE, NULL);
                    328:                        if (error) {
                    329:                                break;
                    330:                        }
                    331:                        ubc_alloc_flags |= UBC_FAULTBUSY;
1.28      chs       332:                }
                    333:
1.33      chs       334:                /*
                    335:                 * copy the data.
                    336:                 */
                    337:
                    338:                win = ubc_alloc(&vp->v_uobj, uio->uio_offset, &bytelen,
                    339:                    ubc_alloc_flags);
1.28      chs       340:                error = uiomove(win, bytelen, uio);
                    341:                ubc_release(win, 0);
1.33      chs       342:                if (error) {
                    343:                        break;
                    344:                }
                    345:
                    346:                /*
                    347:                 * update UVM's notion of the size now that we've
                    348:                 * copied the data into the vnode's pages.
                    349:                 */
                    350:
                    351:                if (vp->v_size < uio->uio_offset) {
                    352:                        uvm_vnp_setsize(vp, uio->uio_offset);
                    353:                }
1.28      chs       354:
                    355:                /*
                    356:                 * flush what we just wrote if necessary.
                    357:                 * XXXUBC simplistic async flushing.
                    358:                 */
                    359:
1.36      chs       360:                if (!async && oldoff >> 16 != uio->uio_offset >> 16) {
1.33      chs       361:                        simple_lock(&vp->v_uobj.vmobjlock);
                    362:                        error = (vp->v_uobj.pgops->pgo_put)(&vp->v_uobj,
                    363:                            (oldoff >> 16) << 16, (uio->uio_offset >> 16) << 16,
                    364:                            PGO_CLEANIT);
                    365:                        if (error) {
                    366:                                break;
                    367:                        }
1.28      chs       368:                }
1.33      chs       369:        }
                    370:        if (error == 0 && ioflag & IO_SYNC) {
                    371:                simple_lock(&vp->v_uobj.vmobjlock);
                    372:                error = (vp->v_uobj.pgops->pgo_put)(&vp->v_uobj,
                    373:                    origoff & ~(bsize - 1), blkroundup(fs, uio->uio_offset),
                    374:                    PGO_CLEANIT|PGO_SYNCIO);
1.28      chs       375:        }
                    376:        goto out;
                    377:
1.29      lukem     378:  bcache:
1.1       mycroft   379:        flags = ioflag & IO_SYNC ? B_SYNC : 0;
1.28      chs       380:        while (uio->uio_resid > 0) {
1.1       mycroft   381:                lbn = lblkno(fs, uio->uio_offset);
                    382:                blkoffset = blkoff(fs, uio->uio_offset);
1.30      chs       383:                xfersize = MIN(fs->fs_bsize - blkoffset, uio->uio_resid);
1.1       mycroft   384:                if (fs->fs_bsize > xfersize)
                    385:                        flags |= B_CLRBUF;
                    386:                else
                    387:                        flags &= ~B_CLRBUF;
                    388:
1.23      fvdl      389:                error = VOP_BALLOC(vp, uio->uio_offset, xfersize,
                    390:                    ap->a_cred, flags, &bp);
                    391:
1.1       mycroft   392:                if (error)
                    393:                        break;
1.12      bouyer    394:                if (uio->uio_offset + xfersize > ip->i_ffs_size) {
                    395:                        ip->i_ffs_size = uio->uio_offset + xfersize;
1.14      mrg       396:                        uvm_vnp_setsize(vp, ip->i_ffs_size);
1.1       mycroft   397:                }
                    398:                size = BLKSIZE(fs, ip, lbn) - bp->b_resid;
1.28      chs       399:                if (xfersize > size)
1.1       mycroft   400:                        xfersize = size;
                    401:
1.28      chs       402:                error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
                    403:
                    404:                /*
                    405:                 * if we didn't clear the block and the uiomove failed,
                    406:                 * the buf will now contain part of some other file,
                    407:                 * so we need to invalidate it.
                    408:                 */
                    409:                if (error && (flags & B_CLRBUF) == 0) {
                    410:                        bp->b_flags |= B_INVAL;
                    411:                        brelse(bp);
                    412:                        break;
                    413:                }
1.1       mycroft   414: #ifdef LFS_READWRITE
1.27      perseant  415:                if (!error)
1.32      perseant  416:                        error = lfs_reserve(fs, vp, btofsb(fs, (NIADDR + 1) << fs->lfs_bshift));
1.1       mycroft   417:                (void)VOP_BWRITE(bp);
1.27      perseant  418:                if (!error)
1.32      perseant  419:                        lfs_reserve(fs, vp, -btofsb(fs, (NIADDR + 1) << fs->lfs_bshift));
1.1       mycroft   420: #else
                    421:                if (ioflag & IO_SYNC)
                    422:                        (void)bwrite(bp);
                    423:                else if (xfersize + blkoffset == fs->fs_bsize)
1.33      chs       424:                        bawrite(bp);
1.1       mycroft   425:                else
                    426:                        bdwrite(bp);
                    427: #endif
                    428:                if (error || xfersize == 0)
                    429:                        break;
                    430:        }
                    431:        /*
                    432:         * If we successfully wrote any data, and we are not the superuser
                    433:         * we clear the setuid and setgid bits as a precaution against
                    434:         * tampering.
                    435:         */
1.33      chs       436: out:
1.28      chs       437:        ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.1       mycroft   438:        if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
1.12      bouyer    439:                ip->i_ffs_mode &= ~(ISUID | ISGID);
1.1       mycroft   440:        if (error) {
1.33      chs       441:                (void) VOP_TRUNCATE(vp, osize, ioflag & IO_SYNC, ap->a_cred,
                    442:                    uio->uio_procp);
                    443:                uio->uio_offset -= resid - uio->uio_resid;
                    444:                uio->uio_resid = resid;
1.20      mycroft   445:        } else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC)
1.25      perseant  446:                error = VOP_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
1.33      chs       447:        KASSERT(vp->v_size == ip->i_ffs_size);
1.1       mycroft   448:        return (error);
                    449: }

CVSweb <webmaster@jp.NetBSD.org>