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

Annotation of src/sys/nfs/nfs_serv.c, Revision 1.99

1.99    ! christos    1: /*     $NetBSD: nfs_serv.c,v 1.79.2.8 2005/11/10 14:11:55 skrll Exp $  */
1.16      cgd         2:
1.1       cgd         3: /*
1.15      mycroft     4:  * Copyright (c) 1989, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd         6:  *
                      7:  * This code is derived from software contributed to Berkeley by
                      8:  * Rick Macklem at The University of Guelph.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
1.81      agc        18:  * 3. Neither the name of the University nor the names of its contributors
1.1       cgd        19:  *    may be used to endorse or promote products derived from this software
                     20:  *    without specific prior written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     25:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     32:  * SUCH DAMAGE.
                     33:  *
1.42      fvdl       34:  *     @(#)nfs_serv.c  8.8 (Berkeley) 7/31/95
1.1       cgd        35:  */
                     36:
                     37: /*
1.23      fvdl       38:  * nfs version 2 and 3 server calls to vnode ops
1.1       cgd        39:  * - these routines generally have 3 phases
                     40:  *   1 - break down and validate rpc request in mbuf list
                     41:  *   2 - do the vnode ops for the request
                     42:  *       (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
                     43:  *   3 - build the rpc reply in an mbuf list
                     44:  *   nb:
                     45:  *     - do not mix the phases, since the nfsm_?? macros can return failures
                     46:  *       on a bad rpc or similar and do not do any vrele() or vput()'s
                     47:  *
                     48:  *      - the nfsm_reply() macro generates an nfs rpc reply with the nfs
                     49:  *     error number iff error != 0 whereas
                     50:  *     returning an error from the server function implies a fatal error
                     51:  *     such as a badly constructed rpc request that should be dropped without
                     52:  *     a reply.
1.23      fvdl       53:  *     For Version 3, nfsm_reply() does not return for the error case, since
                     54:  *     most version 3 rpcs return more than the status for error cases.
1.1       cgd        55:  */
1.62      lukem      56:
                     57: #include <sys/cdefs.h>
1.99    ! christos   58: __KERNEL_RCSID(0, "$NetBSD: nfs_serv.c,v 1.79.2.8 2005/11/10 14:11:55 skrll Exp $");
1.41      mrg        59:
1.10      mycroft    60: #include <sys/param.h>
                     61: #include <sys/systm.h>
                     62: #include <sys/proc.h>
                     63: #include <sys/file.h>
                     64: #include <sys/namei.h>
                     65: #include <sys/vnode.h>
                     66: #include <sys/mount.h>
1.23      fvdl       67: #include <sys/socket.h>
                     68: #include <sys/socketvar.h>
1.10      mycroft    69: #include <sys/mbuf.h>
1.15      mycroft    70: #include <sys/dirent.h>
                     71: #include <sys/stat.h>
1.23      fvdl       72: #include <sys/kernel.h>
1.1       cgd        73:
1.72      yamt       74: #include <uvm/uvm.h>
1.40      mrg        75:
1.23      fvdl       76: #include <nfs/nfsproto.h>
1.15      mycroft    77: #include <nfs/rpcv2.h>
1.10      mycroft    78: #include <nfs/nfs.h>
                     79: #include <nfs/xdr_subs.h>
                     80: #include <nfs/nfsm_subs.h>
1.15      mycroft    81: #include <nfs/nqnfs.h>
1.22      christos   82: #include <nfs/nfs_var.h>
1.1       cgd        83:
                     84: /* Global vars */
1.19      cgd        85: extern u_int32_t nfs_xdrneg1;
                     86: extern u_int32_t nfs_false, nfs_true;
1.23      fvdl       87: extern enum vtype nv3tov_type[8];
                     88: extern struct nfsstats nfsstats;
1.66      matt       89: extern const nfstype nfsv2_type[9];
                     90: extern const nfstype nfsv3_type[9];
1.23      fvdl       91: int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
1.72      yamt       92: int nfsd_use_loan = 1; /* use page-loan for READ OP */
1.1       cgd        93:
1.15      mycroft    94: /*
1.23      fvdl       95:  * nfs v3 access service
1.15      mycroft    96:  */
1.22      christos   97: int
1.99    ! christos   98: nfsrv3_access(nfsd, slp, lwp, mrq)
1.23      fvdl       99:        struct nfsrv_descript *nfsd;
                    100:        struct nfssvc_sock *slp;
1.99    ! christos  101:        struct lwp *lwp;
1.23      fvdl      102:        struct mbuf **mrq;
1.15      mycroft   103: {
1.23      fvdl      104:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                    105:        struct mbuf *nam = nfsd->nd_nam;
                    106:        caddr_t dpos = nfsd->nd_dpos;
                    107:        struct ucred *cred = &nfsd->nd_cr;
1.15      mycroft   108:        struct vnode *vp;
1.23      fvdl      109:        nfsfh_t nfh;
1.15      mycroft   110:        fhandle_t *fhp;
1.54      augustss  111:        u_int32_t *tl;
                    112:        int32_t t1;
1.15      mycroft   113:        caddr_t bpos;
1.23      fvdl      114:        int error = 0, rdonly, cache = 0, getret;
1.15      mycroft   115:        char *cp2;
1.67      matt      116:        struct mbuf *mb, *mreq;
1.23      fvdl      117:        struct vattr va;
1.32      mycroft   118:        u_long inmode, testmode, outmode;
1.15      mycroft   119:        u_quad_t frev;
                    120:
                    121:        fhp = &nfh.fh_generic;
                    122:        nfsm_srvmtofh(fhp);
1.23      fvdl      123:        nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
                    124:        error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
1.78      thorpej   125:            (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl      126:        if (error) {
                    127:                nfsm_reply(NFSX_UNSIGNED);
                    128:                nfsm_srvpostop_attr(1, (struct vattr *)0);
                    129:                return (0);
                    130:        }
1.32      mycroft   131:        inmode = fxdr_unsigned(u_int32_t, *tl);
                    132:        outmode = 0;
                    133:        if ((inmode & NFSV3ACCESS_READ) &&
1.99    ! christos  134:            nfsrv_access(vp, VREAD, cred, rdonly, lwp, 0) == 0)
1.32      mycroft   135:                outmode |= NFSV3ACCESS_READ;
                    136:        if (vp->v_type != VDIR) {
                    137:                testmode = inmode & (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
                    138:                if (testmode &&
1.99    ! christos  139:                    nfsrv_access(vp, VWRITE, cred, rdonly, lwp, 0) == 0)
1.32      mycroft   140:                        outmode |= testmode;
                    141:                if ((inmode & NFSV3ACCESS_EXECUTE) &&
1.99    ! christos  142:                    nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 0) == 0)
1.32      mycroft   143:                        outmode |= NFSV3ACCESS_EXECUTE;
                    144:        } else {
                    145:                testmode = inmode & (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
                    146:                    NFSV3ACCESS_DELETE);
                    147:                if (testmode &&
1.99    ! christos  148:                    nfsrv_access(vp, VWRITE, cred, rdonly, lwp, 0) == 0)
1.32      mycroft   149:                        outmode |= testmode;
                    150:                if ((inmode & NFSV3ACCESS_LOOKUP) &&
1.99    ! christos  151:                    nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 0) == 0)
1.32      mycroft   152:                        outmode |= NFSV3ACCESS_LOOKUP;
                    153:        }
1.99    ! christos  154:        getret = VOP_GETATTR(vp, &va, cred, lwp);
1.15      mycroft   155:        vput(vp);
1.23      fvdl      156:        nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
                    157:        nfsm_srvpostop_attr(getret, &va);
                    158:        nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1.32      mycroft   159:        *tl = txdr_unsigned(outmode);
1.15      mycroft   160:        nfsm_srvdone;
                    161: }
                    162:
1.1       cgd       163: /*
                    164:  * nfs getattr service
                    165:  */
1.22      christos  166: int
1.99    ! christos  167: nfsrv_getattr(nfsd, slp, lwp, mrq)
1.23      fvdl      168:        struct nfsrv_descript *nfsd;
                    169:        struct nfssvc_sock *slp;
1.99    ! christos  170:        struct lwp *lwp;
1.23      fvdl      171:        struct mbuf **mrq;
1.1       cgd       172: {
1.23      fvdl      173:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                    174:        struct mbuf *nam = nfsd->nd_nam;
                    175:        caddr_t dpos = nfsd->nd_dpos;
                    176:        struct ucred *cred = &nfsd->nd_cr;
1.54      augustss  177:        struct nfs_fattr *fp;
1.1       cgd       178:        struct vattr va;
                    179:        struct vnode *vp;
1.23      fvdl      180:        nfsfh_t nfh;
1.1       cgd       181:        fhandle_t *fhp;
1.54      augustss  182:        u_int32_t *tl;
                    183:        int32_t t1;
1.1       cgd       184:        caddr_t bpos;
1.15      mycroft   185:        int error = 0, rdonly, cache;
1.1       cgd       186:        char *cp2;
1.67      matt      187:        struct mbuf *mb, *mreq;
1.15      mycroft   188:        u_quad_t frev;
1.1       cgd       189:
                    190:        fhp = &nfh.fh_generic;
                    191:        nfsm_srvmtofh(fhp);
1.23      fvdl      192:        error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
1.78      thorpej   193:            (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl      194:        if (error) {
1.1       cgd       195:                nfsm_reply(0);
1.23      fvdl      196:                return (0);
                    197:        }
                    198:        nqsrv_getl(vp, ND_READ);
1.99    ! christos  199:        error = VOP_GETATTR(vp, &va, cred, lwp);
1.1       cgd       200:        vput(vp);
1.23      fvdl      201:        nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
                    202:        if (error)
                    203:                return (0);
                    204:        nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
                    205:        nfsm_srvfillattr(&va, fp);
1.1       cgd       206:        nfsm_srvdone;
                    207: }
                    208:
                    209: /*
                    210:  * nfs setattr service
                    211:  */
1.22      christos  212: int
1.99    ! christos  213: nfsrv_setattr(nfsd, slp, lwp, mrq)
1.23      fvdl      214:        struct nfsrv_descript *nfsd;
                    215:        struct nfssvc_sock *slp;
1.99    ! christos  216:        struct lwp *lwp;
1.23      fvdl      217:        struct mbuf **mrq;
1.1       cgd       218: {
1.23      fvdl      219:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                    220:        struct mbuf *nam = nfsd->nd_nam;
                    221:        caddr_t dpos = nfsd->nd_dpos;
                    222:        struct ucred *cred = &nfsd->nd_cr;
                    223:        struct vattr va, preat;
1.54      augustss  224:        struct nfsv2_sattr *sp;
                    225:        struct nfs_fattr *fp;
1.1       cgd       226:        struct vnode *vp;
1.23      fvdl      227:        nfsfh_t nfh;
1.1       cgd       228:        fhandle_t *fhp;
1.54      augustss  229:        u_int32_t *tl;
                    230:        int32_t t1;
1.1       cgd       231:        caddr_t bpos;
1.23      fvdl      232:        int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1;
                    233:        int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
1.1       cgd       234:        char *cp2;
1.67      matt      235:        struct mbuf *mb, *mreq;
1.23      fvdl      236:        u_quad_t frev;
                    237:        struct timespec guard;
1.82      hannken   238:        struct mount *mp = NULL;
1.1       cgd       239:
                    240:        fhp = &nfh.fh_generic;
                    241:        nfsm_srvmtofh(fhp);
1.82      hannken   242:        if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
                    243:                return (ESTALE);
                    244:        vn_start_write(NULL, &mp, V_WAIT);
1.18      mycroft   245:        VATTR_NULL(&va);
1.23      fvdl      246:        if (v3) {
                    247:                nfsm_srvsattr(&va);
                    248:                nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
                    249:                gcheck = fxdr_unsigned(int, *tl);
                    250:                if (gcheck) {
                    251:                        nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
                    252:                        fxdr_nfsv3time(tl, &guard);
                    253:                }
                    254:        } else {
                    255:                nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
                    256:                /*
                    257:                 * Nah nah nah nah na nah
                    258:                 * There is a bug in the Sun client that puts 0xffff in the mode
                    259:                 * field of sattr when it should put in 0xffffffff. The u_short
                    260:                 * doesn't sign extend.
                    261:                 * --> check the low order 2 bytes for 0xffff
                    262:                 */
                    263:                if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
                    264:                        va.va_mode = nfstov_mode(sp->sa_mode);
                    265:                if (sp->sa_uid != nfs_xdrneg1)
                    266:                        va.va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
                    267:                if (sp->sa_gid != nfs_xdrneg1)
                    268:                        va.va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
                    269:                if (sp->sa_size != nfs_xdrneg1)
                    270:                        va.va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
                    271:                if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
1.15      mycroft   272: #ifdef notyet
1.23      fvdl      273:                        fxdr_nfsv2time(&sp->sa_atime, &va.va_atime);
1.15      mycroft   274: #else
1.20      jtc       275:                        va.va_atime.tv_sec =
1.23      fvdl      276:                                fxdr_unsigned(u_int32_t,sp->sa_atime.nfsv2_sec);
1.20      jtc       277:                        va.va_atime.tv_nsec = 0;
1.15      mycroft   278: #endif
                    279:                }
1.23      fvdl      280:                if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
                    281:                        fxdr_nfsv2time(&sp->sa_mtime, &va.va_mtime);
                    282:
                    283:        }
                    284:
                    285:        /*
                    286:         * Now that we have all the fields, lets do it.
                    287:         */
                    288:        error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
1.78      thorpej   289:            (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl      290:        if (error) {
                    291:                nfsm_reply(2 * NFSX_UNSIGNED);
                    292:                nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va);
1.82      hannken   293:                vn_finished_write(mp, 0);
1.23      fvdl      294:                return (0);
                    295:        }
                    296:        nqsrv_getl(vp, ND_WRITE);
                    297:        if (v3) {
1.99    ! christos  298:                error = preat_ret = VOP_GETATTR(vp, &preat, cred, lwp);
1.23      fvdl      299:                if (!error && gcheck &&
                    300:                        (preat.va_ctime.tv_sec != guard.tv_sec ||
                    301:                         preat.va_ctime.tv_nsec != guard.tv_nsec))
                    302:                        error = NFSERR_NOT_SYNC;
                    303:                if (error) {
                    304:                        vput(vp);
                    305:                        nfsm_reply(NFSX_WCCDATA(v3));
                    306:                        nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va);
1.82      hannken   307:                        vn_finished_write(mp, 0);
1.23      fvdl      308:                        return (0);
                    309:                }
1.15      mycroft   310:        }
                    311:
1.1       cgd       312:        /*
1.15      mycroft   313:         * If the size is being changed write acces is required, otherwise
                    314:         * just check for a read only file system.
1.1       cgd       315:         */
1.18      mycroft   316:        if (va.va_size == ((u_quad_t)((quad_t) -1))) {
1.15      mycroft   317:                if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
                    318:                        error = EROFS;
                    319:                        goto out;
                    320:                }
                    321:        } else {
                    322:                if (vp->v_type == VDIR) {
                    323:                        error = EISDIR;
                    324:                        goto out;
1.22      christos  325:                } else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly,
1.99    ! christos  326:                        lwp, 0)) != 0)
1.15      mycroft   327:                        goto out;
1.1       cgd       328:        }
1.99    ! christos  329:        error = VOP_SETATTR(vp, &va, cred, lwp);
        !           330:        postat_ret = VOP_GETATTR(vp, &va, cred, lwp);
1.23      fvdl      331:        if (!error)
                    332:                error = postat_ret;
1.1       cgd       333: out:
                    334:        vput(vp);
1.82      hannken   335:        vn_finished_write(mp, 0);
1.23      fvdl      336:        nfsm_reply(NFSX_WCCORFATTR(v3));
                    337:        if (v3) {
                    338:                nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va);
                    339:                return (0);
                    340:        } else {
                    341:                nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
                    342:                nfsm_srvfillattr(&va, fp);
1.15      mycroft   343:        }
1.1       cgd       344:        nfsm_srvdone;
                    345: }
                    346:
                    347: /*
                    348:  * nfs lookup rpc
                    349:  */
1.22      christos  350: int
1.99    ! christos  351: nfsrv_lookup(nfsd, slp, lwp, mrq)
1.23      fvdl      352:        struct nfsrv_descript *nfsd;
                    353:        struct nfssvc_sock *slp;
1.99    ! christos  354:        struct lwp *lwp;
1.23      fvdl      355:        struct mbuf **mrq;
1.1       cgd       356: {
1.23      fvdl      357:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                    358:        struct mbuf *nam = nfsd->nd_nam;
                    359:        caddr_t dpos = nfsd->nd_dpos;
                    360:        struct ucred *cred = &nfsd->nd_cr;
1.54      augustss  361:        struct nfs_fattr *fp;
1.35      fvdl      362:        struct nameidata nd, ind, *ndp = &nd;
1.23      fvdl      363:        struct vnode *vp, *dirp;
                    364:        nfsfh_t nfh;
1.1       cgd       365:        fhandle_t *fhp;
1.54      augustss  366:        caddr_t cp;
                    367:        u_int32_t *tl;
                    368:        int32_t t1;
1.1       cgd       369:        caddr_t bpos;
1.68      yamt      370:        int error = 0, cache, dirattr_ret = 1;
                    371:        uint32_t len;
1.35      fvdl      372:        int v3 = (nfsd->nd_flag & ND_NFSV3), pubflag;
1.1       cgd       373:        char *cp2;
1.67      matt      374:        struct mbuf *mb, *mreq;
1.23      fvdl      375:        struct vattr va, dirattr;
                    376:        u_quad_t frev;
1.1       cgd       377:
                    378:        fhp = &nfh.fh_generic;
                    379:        nfsm_srvmtofh(fhp);
1.23      fvdl      380:        nfsm_srvnamesiz(len);
1.35      fvdl      381:
                    382:        pubflag = nfs_ispublicfh(fhp);
                    383:
1.15      mycroft   384:        nd.ni_cnd.cn_cred = cred;
                    385:        nd.ni_cnd.cn_nameiop = LOOKUP;
                    386:        nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
1.23      fvdl      387:        error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1.99    ! christos  388:                &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), pubflag);
1.35      fvdl      389:
                    390:        if (!error && pubflag) {
                    391:                if (nd.ni_vp->v_type == VDIR && nfs_pub.np_index != NULL) {
                    392:                        /*
                    393:                         * Setup call to lookup() to see if we can find
                    394:                         * the index file. Arguably, this doesn't belong
                    395:                         * in a kernel.. Ugh.
                    396:                         */
                    397:                        ind = nd;
1.42      fvdl      398:                        VOP_UNLOCK(nd.ni_vp, 0);
1.35      fvdl      399:                        ind.ni_pathlen = strlen(nfs_pub.np_index);
                    400:                        ind.ni_cnd.cn_nameptr = ind.ni_cnd.cn_pnbuf =
                    401:                            nfs_pub.np_index;
                    402:                        ind.ni_startdir = nd.ni_vp;
                    403:                        VREF(ind.ni_startdir);
                    404:                        error = lookup(&ind);
                    405:                        if (!error) {
                    406:                                /*
                    407:                                 * Found an index file. Get rid of
                    408:                                 * the old references.
                    409:                                 */
1.94      perry     410:                                if (dirp)
1.35      fvdl      411:                                        vrele(dirp);
                    412:                                dirp = nd.ni_vp;
                    413:                                vrele(nd.ni_startdir);
                    414:                                ndp = &ind;
                    415:                        } else
                    416:                                error = 0;
                    417:                }
                    418:                /*
                    419:                 * If the public filehandle was used, check that this lookup
                    420:                 * didn't result in a filehandle outside the publicly exported
                    421:                 * filesystem.
                    422:                 */
                    423:
                    424:                if (!error && ndp->ni_vp->v_mount != nfs_pub.np_mount) {
                    425:                        vput(nd.ni_vp);
                    426:                        error = EPERM;
                    427:                }
                    428:        }
                    429:
1.23      fvdl      430:        if (dirp) {
                    431:                if (v3)
1.99    ! christos  432:                        dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred, lwp);
1.23      fvdl      433:                vrele(dirp);
                    434:        }
1.35      fvdl      435:
1.23      fvdl      436:        if (error) {
                    437:                nfsm_reply(NFSX_POSTOPATTR(v3));
                    438:                nfsm_srvpostop_attr(dirattr_ret, &dirattr);
                    439:                return (0);
                    440:        }
1.35      fvdl      441:
                    442:        nqsrv_getl(ndp->ni_startdir, ND_READ);
                    443:        vrele(ndp->ni_startdir);
1.57      thorpej   444:        PNBUF_PUT(nd.ni_cnd.cn_pnbuf);
1.35      fvdl      445:        vp = ndp->ni_vp;
1.44      perry     446:        memset((caddr_t)fhp, 0, sizeof(nfh));
1.88      christos  447:        fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsidx;
1.23      fvdl      448:        error = VFS_VPTOFH(vp, &fhp->fh_fid);
                    449:        if (!error)
1.99    ! christos  450:                error = VOP_GETATTR(vp, &va, cred, lwp);
1.23      fvdl      451:        vput(vp);
                    452:        nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
                    453:        if (error) {
                    454:                nfsm_srvpostop_attr(dirattr_ret, &dirattr);
                    455:                return (0);
1.1       cgd       456:        }
1.23      fvdl      457:        nfsm_srvfhtom(fhp, v3);
                    458:        if (v3) {
                    459:                nfsm_srvpostop_attr(0, &va);
                    460:                nfsm_srvpostop_attr(dirattr_ret, &dirattr);
                    461:        } else {
                    462:                nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
                    463:                nfsm_srvfillattr(&va, fp);
1.15      mycroft   464:        }
1.1       cgd       465:        nfsm_srvdone;
                    466: }
                    467:
                    468: /*
                    469:  * nfs readlink service
                    470:  */
1.22      christos  471: int
1.99    ! christos  472: nfsrv_readlink(nfsd, slp, lwp, mrq)
1.23      fvdl      473:        struct nfsrv_descript *nfsd;
                    474:        struct nfssvc_sock *slp;
1.99    ! christos  475:        struct lwp *lwp;
1.23      fvdl      476:        struct mbuf **mrq;
1.1       cgd       477: {
1.23      fvdl      478:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                    479:        struct mbuf *nam = nfsd->nd_nam;
                    480:        caddr_t dpos = nfsd->nd_dpos;
                    481:        struct ucred *cred = &nfsd->nd_cr;
1.1       cgd       482:        struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
1.54      augustss  483:        struct iovec *ivp = iv;
                    484:        struct mbuf *mp;
                    485:        u_int32_t *tl;
                    486:        int32_t t1;
1.1       cgd       487:        caddr_t bpos;
1.76      yamt      488:        int error = 0, rdonly, cache, i, padlen, getret;
                    489:        uint32_t len;
1.23      fvdl      490:        int v3 = (nfsd->nd_flag & ND_NFSV3);
1.1       cgd       491:        char *cp2;
1.67      matt      492:        struct mbuf *mb, *mp2 = NULL, *mp3 = NULL, *mreq;
1.1       cgd       493:        struct vnode *vp;
1.23      fvdl      494:        struct vattr attr;
                    495:        nfsfh_t nfh;
1.1       cgd       496:        fhandle_t *fhp;
                    497:        struct uio io, *uiop = &io;
1.15      mycroft   498:        u_quad_t frev;
1.1       cgd       499:
                    500:        fhp = &nfh.fh_generic;
                    501:        nfsm_srvmtofh(fhp);
                    502:        len = 0;
                    503:        i = 0;
                    504:        while (len < NFS_MAXPATHLEN) {
1.67      matt      505:                mp = m_get(M_WAIT, MT_DATA);
                    506:                MCLAIM(mp, &nfs_mowner);
                    507:                m_clget(mp, M_WAIT);
1.1       cgd       508:                mp->m_len = NFSMSIZ(mp);
                    509:                if (len == 0)
                    510:                        mp3 = mp2 = mp;
                    511:                else {
                    512:                        mp2->m_next = mp;
                    513:                        mp2 = mp;
                    514:                }
                    515:                if ((len+mp->m_len) > NFS_MAXPATHLEN) {
                    516:                        mp->m_len = NFS_MAXPATHLEN-len;
                    517:                        len = NFS_MAXPATHLEN;
                    518:                } else
                    519:                        len += mp->m_len;
                    520:                ivp->iov_base = mtod(mp, caddr_t);
                    521:                ivp->iov_len = mp->m_len;
                    522:                i++;
                    523:                ivp++;
                    524:        }
                    525:        uiop->uio_iov = iv;
                    526:        uiop->uio_iovcnt = i;
                    527:        uiop->uio_offset = 0;
                    528:        uiop->uio_resid = len;
                    529:        uiop->uio_rw = UIO_READ;
                    530:        uiop->uio_segflg = UIO_SYSSPACE;
1.99    ! christos  531:        uiop->uio_lwp = NULL;
1.23      fvdl      532:        error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.78      thorpej   533:                 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.22      christos  534:        if (error) {
1.1       cgd       535:                m_freem(mp3);
1.23      fvdl      536:                nfsm_reply(2 * NFSX_UNSIGNED);
                    537:                nfsm_srvpostop_attr(1, (struct vattr *)0);
                    538:                return (0);
1.1       cgd       539:        }
                    540:        if (vp->v_type != VLNK) {
1.23      fvdl      541:                if (v3)
                    542:                        error = EINVAL;
                    543:                else
                    544:                        error = ENXIO;
1.1       cgd       545:                goto out;
                    546:        }
1.23      fvdl      547:        nqsrv_getl(vp, ND_READ);
1.1       cgd       548:        error = VOP_READLINK(vp, uiop, cred);
                    549: out:
1.99    ! christos  550:        getret = VOP_GETATTR(vp, &attr, cred, lwp);
1.1       cgd       551:        vput(vp);
                    552:        if (error)
                    553:                m_freem(mp3);
1.23      fvdl      554:        nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
                    555:        if (v3) {
                    556:                nfsm_srvpostop_attr(getret, &attr);
                    557:                if (error)
                    558:                        return (0);
                    559:        }
1.76      yamt      560:        len -= uiop->uio_resid;
                    561:        padlen = nfsm_padlen(len);
                    562:        if (uiop->uio_resid || padlen)
                    563:                nfs_zeropad(mp3, uiop->uio_resid, padlen);
1.19      cgd       564:        nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1.1       cgd       565:        *tl = txdr_unsigned(len);
                    566:        mb->m_next = mp3;
                    567:        nfsm_srvdone;
                    568: }
                    569:
                    570: /*
                    571:  * nfs read service
                    572:  */
1.22      christos  573: int
1.99    ! christos  574: nfsrv_read(nfsd, slp, lwp, mrq)
1.23      fvdl      575:        struct nfsrv_descript *nfsd;
                    576:        struct nfssvc_sock *slp;
1.99    ! christos  577:        struct lwp *lwp;
1.23      fvdl      578:        struct mbuf **mrq;
1.1       cgd       579: {
1.23      fvdl      580:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                    581:        struct mbuf *nam = nfsd->nd_nam;
                    582:        caddr_t dpos = nfsd->nd_dpos;
                    583:        struct ucred *cred = &nfsd->nd_cr;
1.54      augustss  584:        struct mbuf *m;
                    585:        struct nfs_fattr *fp;
                    586:        u_int32_t *tl;
                    587:        int32_t t1;
                    588:        int i;
1.1       cgd       589:        caddr_t bpos;
1.72      yamt      590:        int error = 0, rdonly, cache, getret;
1.68      yamt      591:        int v3 = (nfsd->nd_flag & ND_NFSV3);
1.76      yamt      592:        uint32_t reqlen, len, cnt, left;
                    593:        int padlen;
1.1       cgd       594:        char *cp2;
1.67      matt      595:        struct mbuf *mb, *mreq;
1.1       cgd       596:        struct vnode *vp;
1.23      fvdl      597:        nfsfh_t nfh;
1.1       cgd       598:        fhandle_t *fhp;
                    599:        struct uio io, *uiop = &io;
1.18      mycroft   600:        struct vattr va;
1.1       cgd       601:        off_t off;
1.15      mycroft   602:        u_quad_t frev;
1.1       cgd       603:
                    604:        fhp = &nfh.fh_generic;
                    605:        nfsm_srvmtofh(fhp);
1.23      fvdl      606:        if (v3) {
                    607:                nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1.48      fair      608:                off = fxdr_hyper(tl);
1.23      fvdl      609:        } else {
1.19      cgd       610:                nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
                    611:                off = (off_t)fxdr_unsigned(u_int32_t, *tl);
1.15      mycroft   612:        }
1.71      yamt      613:        nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED);
                    614:        reqlen = fxdr_unsigned(uint32_t, *tl);
                    615:        reqlen = MIN(reqlen, NFS_SRVMAXDATA(nfsd));
1.23      fvdl      616:        error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.78      thorpej   617:                 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl      618:        if (error) {
                    619:                nfsm_reply(2 * NFSX_UNSIGNED);
                    620:                nfsm_srvpostop_attr(1, (struct vattr *)0);
                    621:                return (0);
                    622:        }
1.15      mycroft   623:        if (vp->v_type != VREG) {
1.23      fvdl      624:                if (v3)
                    625:                        error = EINVAL;
                    626:                else
                    627:                        error = (vp->v_type == VDIR) ? EISDIR : EACCES;
1.1       cgd       628:        }
1.23      fvdl      629:        if (!error) {
                    630:            nqsrv_getl(vp, ND_READ);
1.99    ! christos  631:            if ((error = nfsrv_access(vp, VREAD, cred, rdonly, lwp, 1)) != 0)
        !           632:                error = nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 1);
1.23      fvdl      633:        }
1.99    ! christos  634:        getret = VOP_GETATTR(vp, &va, cred, lwp);
1.23      fvdl      635:        if (!error)
                    636:                error = getret;
1.22      christos  637:        if (error) {
1.1       cgd       638:                vput(vp);
1.23      fvdl      639:                nfsm_reply(NFSX_POSTOPATTR(v3));
                    640:                nfsm_srvpostop_attr(getret, &va);
                    641:                return (0);
1.1       cgd       642:        }
1.18      mycroft   643:        if (off >= va.va_size)
1.15      mycroft   644:                cnt = 0;
1.23      fvdl      645:        else if ((off + reqlen) > va.va_size)
1.76      yamt      646:                cnt = va.va_size - off;
1.23      fvdl      647:        else
                    648:                cnt = reqlen;
                    649:        nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
                    650:        if (v3) {
                    651:                nfsm_build(tl, u_int32_t *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
                    652:                *tl++ = nfs_true;
                    653:                fp = (struct nfs_fattr *)tl;
                    654:                tl += (NFSX_V3FATTR / sizeof (u_int32_t));
                    655:        } else {
                    656:                nfsm_build(tl, u_int32_t *, NFSX_V2FATTR + NFSX_UNSIGNED);
                    657:                fp = (struct nfs_fattr *)tl;
                    658:                tl += (NFSX_V2FATTR / sizeof (u_int32_t));
                    659:        }
1.15      mycroft   660:        len = left = cnt;
1.73      yamt      661:        if (cnt > 0) {
1.72      yamt      662:                if (nfsd_use_loan) {
                    663:                        struct vm_page **pgpp;
                    664:                        voff_t pgoff = trunc_page(off);
1.87      yamt      665:                        int npages;
                    666:                        vaddr_t lva;
1.72      yamt      667:
1.87      yamt      668:                        npages = (round_page(off + cnt) - pgoff) >> PAGE_SHIFT;
                    669:                        KASSERT(npages <= M_EXT_MAXPAGES); /* XXX */
1.72      yamt      670:
1.87      yamt      671:                        /* allocate kva for mbuf data */
                    672:                        lva = sokvaalloc(npages << PAGE_SHIFT, slp->ns_so);
1.72      yamt      673:                        if (lva == 0) {
                    674:                                /* fall back to VOP_READ */
                    675:                                goto loan_fail;
                    676:                        }
                    677:
1.87      yamt      678:                        /* allocate mbuf */
1.72      yamt      679:                        m = m_get(M_WAIT, MT_DATA);
1.87      yamt      680:                        MCLAIM(m, &nfs_mowner);
1.72      yamt      681:                        pgpp = m->m_ext.ext_pgs;
1.75      yamt      682:
1.87      yamt      683:                        /* loan pages */
                    684:                        error = uvm_loanuobjpages(&vp->v_uobj, pgoff, npages,
                    685:                            pgpp);
                    686:                        if (error) {
                    687:                                sokvafree(lva, npages << PAGE_SHIFT);
                    688:                                m_free(m);
1.91      yamt      689:                                if (error == EBUSY)
                    690:                                        goto loan_fail;
1.87      yamt      691:                                goto read_error;
1.15      mycroft   692:                        }
1.72      yamt      693:
1.87      yamt      694:                        /* associate kva to mbuf */
                    695:                        MEXTADD(m, (void *)(lva + ((vaddr_t)off & PAGE_MASK)),
                    696:                            cnt, M_MBUF, soloanfree, slp->ns_so);
1.72      yamt      697:                        m->m_flags |= M_EXT_PAGES | M_EXT_ROMAP;
                    698:                        m->m_len = cnt;
                    699:
1.87      yamt      700:                        /* map pages */
                    701:                        for (i = 0; i < npages; i++) {
                    702:                                pmap_kenter_pa(lva, VM_PAGE_TO_PHYS(pgpp[i]),
                    703:                                    VM_PROT_READ);
                    704:                                lva += PAGE_SIZE;
                    705:                        }
                    706:
1.72      yamt      707:                        pmap_update(pmap_kernel());
1.87      yamt      708:
1.72      yamt      709:                        mb->m_next = m;
                    710:                        mb = m;
                    711:                        error = 0;
                    712:                        uiop->uio_resid = 0;
                    713:                } else {
                    714:                        struct iovec *iv;
                    715:                        struct iovec *iv2;
                    716:                        struct mbuf *m2;
                    717:                        int siz;
                    718: loan_fail:
                    719:                        /*
                    720:                         * Generate the mbuf list with the uio_iov ref. to it.
                    721:                         */
                    722:                        i = 0;
                    723:                        m = m2 = mb;
                    724:                        while (left > 0) {
                    725:                                siz = min(M_TRAILINGSPACE(m), left);
                    726:                                if (siz > 0) {
                    727:                                        left -= siz;
                    728:                                        i++;
                    729:                                }
                    730:                                if (left > 0) {
                    731:                                        m = m_get(M_WAIT, MT_DATA);
                    732:                                        MCLAIM(m, &nfs_mowner);
                    733:                                        m_clget(m, M_WAIT);
                    734:                                        m->m_len = 0;
                    735:                                        m2->m_next = m;
                    736:                                        m2 = m;
                    737:                                }
                    738:                        }
                    739:                        iv = malloc(i * sizeof(struct iovec), M_TEMP, M_WAITOK);
                    740:                        uiop->uio_iov = iv2 = iv;
                    741:                        m = mb;
                    742:                        left = cnt;
                    743:                        i = 0;
                    744:                        while (left > 0) {
                    745:                                if (m == NULL)
                    746:                                        panic("nfsrv_read iov");
                    747:                                siz = min(M_TRAILINGSPACE(m), left);
                    748:                                if (siz > 0) {
                    749:                                        iv->iov_base = mtod(m, caddr_t) +
                    750:                                            m->m_len;
                    751:                                        iv->iov_len = siz;
                    752:                                        m->m_len += siz;
                    753:                                        left -= siz;
                    754:                                        iv++;
                    755:                                        i++;
                    756:                                }
                    757:                                m = m->m_next;
1.23      fvdl      758:                        }
1.72      yamt      759:                        uiop->uio_iovcnt = i;
                    760:                        uiop->uio_offset = off;
                    761:                        uiop->uio_resid = cnt;
                    762:                        uiop->uio_rw = UIO_READ;
                    763:                        uiop->uio_segflg = UIO_SYSSPACE;
                    764:                        error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
                    765:                        free((caddr_t)iv2, M_TEMP);
1.23      fvdl      766:                }
1.72      yamt      767: read_error:
1.99    ! christos  768:                if (error || (getret = VOP_GETATTR(vp, &va, cred, lwp)) != 0){
1.23      fvdl      769:                        if (!error)
                    770:                                error = getret;
1.15      mycroft   771:                        m_freem(mreq);
                    772:                        vput(vp);
1.23      fvdl      773:                        nfsm_reply(NFSX_POSTOPATTR(v3));
                    774:                        nfsm_srvpostop_attr(getret, &va);
                    775:                        return (0);
1.15      mycroft   776:                }
1.72      yamt      777:        } else {
1.15      mycroft   778:                uiop->uio_resid = 0;
1.72      yamt      779:        }
1.1       cgd       780:        vput(vp);
1.23      fvdl      781:        nfsm_srvfillattr(&va, fp);
1.1       cgd       782:        len -= uiop->uio_resid;
1.76      yamt      783:        padlen = nfsm_padlen(len);
                    784:        if (uiop->uio_resid || padlen)
                    785:                nfs_zeropad(mb, uiop->uio_resid, padlen);
1.23      fvdl      786:        if (v3) {
1.83      yamt      787:                /* count */
1.23      fvdl      788:                *tl++ = txdr_unsigned(len);
1.83      yamt      789:                /* eof */
                    790:                if (off + len >= va.va_size)
1.23      fvdl      791:                        *tl++ = nfs_true;
                    792:                else
                    793:                        *tl++ = nfs_false;
                    794:        }
1.1       cgd       795:        *tl = txdr_unsigned(len);
                    796:        nfsm_srvdone;
                    797: }
                    798:
                    799: /*
                    800:  * nfs write service
                    801:  */
1.22      christos  802: int
1.99    ! christos  803: nfsrv_write(nfsd, slp, lwp, mrq)
1.23      fvdl      804:        struct nfsrv_descript *nfsd;
                    805:        struct nfssvc_sock *slp;
1.99    ! christos  806:        struct lwp *lwp;
1.23      fvdl      807:        struct mbuf **mrq;
1.1       cgd       808: {
1.23      fvdl      809:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                    810:        struct mbuf *nam = nfsd->nd_nam;
                    811:        caddr_t dpos = nfsd->nd_dpos;
                    812:        struct ucred *cred = &nfsd->nd_cr;
1.54      augustss  813:        struct iovec *ivp;
                    814:        int i, cnt;
                    815:        struct mbuf *mp;
                    816:        struct nfs_fattr *fp;
1.23      fvdl      817:        struct iovec *iv;
                    818:        struct vattr va, forat;
1.54      augustss  819:        u_int32_t *tl;
                    820:        int32_t t1;
1.1       cgd       821:        caddr_t bpos;
1.23      fvdl      822:        int error = 0, rdonly, cache, len, forat_ret = 1;
                    823:        int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
                    824:        int stable = NFSV3WRITE_FILESYNC;
                    825:        int v3 = (nfsd->nd_flag & ND_NFSV3);
1.1       cgd       826:        char *cp2;
1.67      matt      827:        struct mbuf *mb, *mreq;
1.1       cgd       828:        struct vnode *vp;
1.23      fvdl      829:        nfsfh_t nfh;
1.1       cgd       830:        fhandle_t *fhp;
                    831:        struct uio io, *uiop = &io;
                    832:        off_t off;
1.15      mycroft   833:        u_quad_t frev;
1.82      hannken   834:        struct mount *mntp = NULL;
1.1       cgd       835:
1.23      fvdl      836:        if (mrep == NULL) {
                    837:                *mrq = NULL;
                    838:                return (0);
                    839:        }
1.1       cgd       840:        fhp = &nfh.fh_generic;
                    841:        nfsm_srvmtofh(fhp);
1.82      hannken   842:        if ((mntp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
                    843:                return (ESTALE);
                    844:        vn_start_write(NULL, &mntp, V_WAIT);
1.23      fvdl      845:        if (v3) {
                    846:                nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1.48      fair      847:                off = fxdr_hyper(tl);
1.23      fvdl      848:                tl += 3;
                    849:                stable = fxdr_unsigned(int, *tl++);
                    850:        } else {
                    851:                nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1.19      cgd       852:                off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
1.15      mycroft   853:                tl += 2;
                    854:        }
1.23      fvdl      855:        retlen = len = fxdr_unsigned(int32_t, *tl);
                    856:        cnt = i = 0;
                    857:
                    858:        /*
                    859:         * For NFS Version 2, it is not obvious what a write of zero length
                    860:         * should do, but I might as well be consistent with Version 3,
                    861:         * which is to return ok so long as there are no permission problems.
                    862:         */
                    863:        if (len > 0) {
1.74      yamt      864:                zeroing = 1;
                    865:                mp = mrep;
                    866:                while (mp) {
                    867:                        if (mp == md) {
                    868:                                zeroing = 0;
                    869:                                adjust = dpos - mtod(mp, caddr_t);
                    870:                                mp->m_len -= adjust;
                    871:                                if (mp->m_len > 0 && adjust > 0)
                    872:                                        NFSMADV(mp, adjust);
1.23      fvdl      873:                        }
1.74      yamt      874:                        if (zeroing)
                    875:                                mp->m_len = 0;
                    876:                        else if (mp->m_len > 0) {
                    877:                                i += mp->m_len;
                    878:                                if (i > len) {
                    879:                                        mp->m_len -= (i - len);
                    880:                                        zeroing = 1;
                    881:                                }
                    882:                                if (mp->m_len > 0)
                    883:                                        cnt++;
                    884:                        }
                    885:                        mp = mp->m_next;
1.23      fvdl      886:                }
                    887:        }
                    888:        if (len > NFS_MAXDATA || len < 0 || i < len) {
                    889:                error = EIO;
                    890:                nfsm_reply(2 * NFSX_UNSIGNED);
                    891:                nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1.82      hannken   892:                vn_finished_write(mntp, 0);
1.23      fvdl      893:                return (0);
1.1       cgd       894:        }
1.23      fvdl      895:        error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.78      thorpej   896:                 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl      897:        if (error) {
                    898:                nfsm_reply(2 * NFSX_UNSIGNED);
                    899:                nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1.82      hannken   900:                vn_finished_write(mntp, 0);
1.23      fvdl      901:                return (0);
1.1       cgd       902:        }
1.23      fvdl      903:        if (v3)
1.99    ! christos  904:                forat_ret = VOP_GETATTR(vp, &forat, cred, lwp);
1.15      mycroft   905:        if (vp->v_type != VREG) {
1.23      fvdl      906:                if (v3)
                    907:                        error = EINVAL;
                    908:                else
                    909:                        error = (vp->v_type == VDIR) ? EISDIR : EACCES;
                    910:        }
                    911:        if (!error) {
                    912:                nqsrv_getl(vp, ND_WRITE);
1.99    ! christos  913:                error = nfsrv_access(vp, VWRITE, cred, rdonly, lwp, 1);
1.15      mycroft   914:        }
1.22      christos  915:        if (error) {
1.1       cgd       916:                vput(vp);
1.23      fvdl      917:                nfsm_reply(NFSX_WCCDATA(v3));
                    918:                nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1.82      hannken   919:                vn_finished_write(mntp, 0);
1.23      fvdl      920:                return (0);
                    921:        }
                    922:
                    923:        if (len > 0) {
1.74      yamt      924:                ivp = malloc(cnt * sizeof (struct iovec), M_TEMP, M_WAITOK);
                    925:                uiop->uio_iov = iv = ivp;
                    926:                uiop->uio_iovcnt = cnt;
                    927:                mp = mrep;
                    928:                while (mp) {
                    929:                        if (mp->m_len > 0) {
                    930:                                ivp->iov_base = mtod(mp, caddr_t);
                    931:                                ivp->iov_len = mp->m_len;
                    932:                                ivp++;
                    933:                        }
                    934:                        mp = mp->m_next;
                    935:                }
                    936:
                    937:                /*
                    938:                 * XXX
                    939:                 * The IO_METASYNC flag indicates that all metadata (and not
                    940:                 * just enough to ensure data integrity) must be written to
                    941:                 * stable storage synchronously.
                    942:                 * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
                    943:                 */
                    944:                if (stable == NFSV3WRITE_UNSTABLE)
                    945:                        ioflags = IO_NODELOCKED;
                    946:                else if (stable == NFSV3WRITE_DATASYNC)
                    947:                        ioflags = (IO_SYNC | IO_NODELOCKED);
                    948:                else
                    949:                        ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
                    950:                uiop->uio_resid = len;
                    951:                uiop->uio_rw = UIO_WRITE;
                    952:                uiop->uio_segflg = UIO_SYSSPACE;
1.99    ! christos  953:                uiop->uio_lwp = NULL;
1.74      yamt      954:                uiop->uio_offset = off;
                    955:                error = VOP_WRITE(vp, uiop, ioflags, cred);
                    956:                nfsstats.srvvop_writes++;
                    957:                free(iv, M_TEMP);
1.23      fvdl      958:        }
1.99    ! christos  959:        aftat_ret = VOP_GETATTR(vp, &va, cred, lwp);
1.23      fvdl      960:        vput(vp);
1.82      hannken   961:        vn_finished_write(mntp, 0);
1.23      fvdl      962:        if (!error)
                    963:                error = aftat_ret;
                    964:        nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
                    965:                2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
                    966:        if (v3) {
                    967:                nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
                    968:                if (error)
                    969:                        return (0);
                    970:                nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
                    971:                *tl++ = txdr_unsigned(retlen);
                    972:                if (stable == NFSV3WRITE_UNSTABLE)
                    973:                        *tl++ = txdr_unsigned(stable);
                    974:                else
                    975:                        *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
                    976:                /*
                    977:                 * Actually, there is no need to txdr these fields,
                    978:                 * but it may make the values more human readable,
                    979:                 * for debugging purposes.
                    980:                 */
                    981:                *tl++ = txdr_unsigned(boottime.tv_sec);
                    982:                *tl = txdr_unsigned(boottime.tv_usec);
                    983:        } else {
                    984:                nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
                    985:                nfsm_srvfillattr(&va, fp);
                    986:        }
                    987:        nfsm_srvdone;
                    988: }
                    989:
                    990: /*
                    991:  * NFS write service with write gathering support. Called when
                    992:  * nfsrvw_procrastinate > 0.
                    993:  * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
                    994:  * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
                    995:  * Jan. 1994.
                    996:  */
                    997: int
1.99    ! christos  998: nfsrv_writegather(ndp, slp, lwp, mrq)
1.23      fvdl      999:        struct nfsrv_descript **ndp;
                   1000:        struct nfssvc_sock *slp;
1.99    ! christos 1001:        struct lwp *lwp;
1.23      fvdl     1002:        struct mbuf **mrq;
                   1003: {
1.54      augustss 1004:        struct iovec *ivp;
                   1005:        struct mbuf *mp;
                   1006:        struct nfsrv_descript *wp, *nfsd, *owp, *swp;
                   1007:        struct nfs_fattr *fp;
                   1008:        int i = 0;
1.23      fvdl     1009:        struct iovec *iov;
                   1010:        struct nfsrvw_delayhash *wpp;
                   1011:        struct ucred *cred;
                   1012:        struct vattr va, forat;
1.54      augustss 1013:        u_int32_t *tl;
                   1014:        int32_t t1;
1.23      fvdl     1015:        caddr_t bpos, dpos;
                   1016:        int error = 0, rdonly, cache, len = 0, forat_ret = 1;
                   1017:        int ioflags, aftat_ret = 1, s, adjust, v3, zeroing;
                   1018:        char *cp2;
1.67      matt     1019:        struct mbuf *mb, *mreq, *mrep, *md;
1.23      fvdl     1020:        struct vnode *vp;
                   1021:        struct uio io, *uiop = &io;
                   1022:        u_quad_t frev, cur_usec;
1.82      hannken  1023:        struct mount *mntp = NULL;
1.23      fvdl     1024:
                   1025:        *mrq = NULL;
                   1026:        if (*ndp) {
                   1027:            nfsd = *ndp;
                   1028:            *ndp = NULL;
                   1029:            mrep = nfsd->nd_mrep;
                   1030:            md = nfsd->nd_md;
                   1031:            dpos = nfsd->nd_dpos;
                   1032:            cred = &nfsd->nd_cr;
                   1033:            v3 = (nfsd->nd_flag & ND_NFSV3);
                   1034:            LIST_INIT(&nfsd->nd_coalesce);
                   1035:            nfsd->nd_mreq = NULL;
                   1036:            nfsd->nd_stable = NFSV3WRITE_FILESYNC;
                   1037:            cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
                   1038:            nfsd->nd_time = cur_usec + nfsrvw_procrastinate;
1.94      perry    1039:
1.23      fvdl     1040:            /*
                   1041:             * Now, get the write header..
                   1042:             */
                   1043:            nfsm_srvmtofh(&nfsd->nd_fh);
                   1044:            if (v3) {
                   1045:                nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1.48      fair     1046:                nfsd->nd_off = fxdr_hyper(tl);
1.23      fvdl     1047:                tl += 3;
                   1048:                nfsd->nd_stable = fxdr_unsigned(int, *tl++);
                   1049:            } else {
                   1050:                nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
                   1051:                nfsd->nd_off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
                   1052:                tl += 2;
                   1053:            }
                   1054:            len = fxdr_unsigned(int32_t, *tl);
                   1055:            nfsd->nd_len = len;
                   1056:            nfsd->nd_eoff = nfsd->nd_off + len;
1.94      perry    1057:
1.23      fvdl     1058:            /*
                   1059:             * Trim the header out of the mbuf list and trim off any trailing
                   1060:             * junk so that the mbuf list has only the write data.
                   1061:             */
                   1062:            zeroing = 1;
                   1063:            i = 0;
                   1064:            mp = mrep;
                   1065:            while (mp) {
                   1066:                if (mp == md) {
                   1067:                    zeroing = 0;
                   1068:                    adjust = dpos - mtod(mp, caddr_t);
                   1069:                    mp->m_len -= adjust;
                   1070:                    if (mp->m_len > 0 && adjust > 0)
                   1071:                        NFSMADV(mp, adjust);
                   1072:                }
                   1073:                if (zeroing)
                   1074:                    mp->m_len = 0;
                   1075:                else {
                   1076:                    i += mp->m_len;
                   1077:                    if (i > len) {
                   1078:                        mp->m_len -= (i - len);
                   1079:                        zeroing = 1;
                   1080:                    }
                   1081:                }
                   1082:                mp = mp->m_next;
                   1083:            }
                   1084:            if (len > NFS_MAXDATA || len < 0  || i < len) {
                   1085: nfsmout:
                   1086:                m_freem(mrep);
                   1087:                error = EIO;
                   1088:                nfsm_writereply(2 * NFSX_UNSIGNED, v3);
                   1089:                if (v3)
                   1090:                    nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
                   1091:                nfsd->nd_mreq = mreq;
                   1092:                nfsd->nd_mrep = NULL;
                   1093:                nfsd->nd_time = 0;
                   1094:            }
1.94      perry    1095:
1.23      fvdl     1096:            /*
                   1097:             * Add this entry to the hash and time queues.
                   1098:             */
                   1099:            s = splsoftclock();
                   1100:            owp = NULL;
1.70      yamt     1101:            wp = LIST_FIRST(&slp->ns_tq);
1.23      fvdl     1102:            while (wp && wp->nd_time < nfsd->nd_time) {
                   1103:                owp = wp;
1.70      yamt     1104:                wp = LIST_NEXT(wp, nd_tq);
1.23      fvdl     1105:            }
                   1106:            if (owp) {
                   1107:                LIST_INSERT_AFTER(owp, nfsd, nd_tq);
                   1108:            } else {
                   1109:                LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
                   1110:            }
                   1111:            if (nfsd->nd_mrep) {
                   1112:                wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data);
                   1113:                owp = NULL;
1.70      yamt     1114:                wp = LIST_FIRST(wpp);
1.23      fvdl     1115:                while (wp &&
1.44      perry    1116:                    memcmp((caddr_t)&nfsd->nd_fh, (caddr_t)&wp->nd_fh, NFSX_V3FH)) {
1.23      fvdl     1117:                    owp = wp;
1.70      yamt     1118:                    wp = LIST_NEXT(wp, nd_hash);
1.23      fvdl     1119:                }
                   1120:                while (wp && wp->nd_off < nfsd->nd_off &&
1.44      perry    1121:                    !memcmp((caddr_t)&nfsd->nd_fh, (caddr_t)&wp->nd_fh, NFSX_V3FH)) {
1.23      fvdl     1122:                    owp = wp;
1.70      yamt     1123:                    wp = LIST_NEXT(wp, nd_hash);
1.23      fvdl     1124:                }
                   1125:                if (owp) {
                   1126:                    LIST_INSERT_AFTER(owp, nfsd, nd_hash);
                   1127:
                   1128:                    /*
                   1129:                     * Search the hash list for overlapping entries and
                   1130:                     * coalesce.
                   1131:                     */
                   1132:                    for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
1.70      yamt     1133:                        wp = LIST_NEXT(nfsd, nd_hash);
1.23      fvdl     1134:                        if (NFSW_SAMECRED(owp, nfsd))
                   1135:                            nfsrvw_coalesce(owp, nfsd);
                   1136:                    }
                   1137:                } else {
                   1138:                    LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
                   1139:                }
                   1140:            }
                   1141:            splx(s);
1.1       cgd      1142:        }
1.94      perry    1143:
1.1       cgd      1144:        /*
1.23      fvdl     1145:         * Now, do VOP_WRITE()s for any one(s) that need to be done now
                   1146:         * and generate the associated reply mbuf list(s).
1.1       cgd      1147:         */
1.23      fvdl     1148: loop1:
                   1149:        cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
                   1150:        s = splsoftclock();
1.70      yamt     1151:        for (nfsd = LIST_FIRST(&slp->ns_tq); nfsd; nfsd = owp) {
                   1152:                owp = LIST_NEXT(nfsd, nd_tq);
1.23      fvdl     1153:                if (nfsd->nd_time > cur_usec)
                   1154:                    break;
                   1155:                if (nfsd->nd_mreq)
                   1156:                    continue;
                   1157:                LIST_REMOVE(nfsd, nd_tq);
                   1158:                LIST_REMOVE(nfsd, nd_hash);
                   1159:                splx(s);
                   1160:                mrep = nfsd->nd_mrep;
                   1161:                nfsd->nd_mrep = NULL;
                   1162:                cred = &nfsd->nd_cr;
                   1163:                v3 = (nfsd->nd_flag & ND_NFSV3);
                   1164:                forat_ret = aftat_ret = 1;
1.94      perry    1165:                error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
1.35      fvdl     1166:                    nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH),
1.78      thorpej  1167:                    FALSE);
1.23      fvdl     1168:                if (!error) {
                   1169:                    if (v3)
1.99    ! christos 1170:                        forat_ret = VOP_GETATTR(vp, &forat, cred, lwp);
1.23      fvdl     1171:                    if (vp->v_type != VREG) {
                   1172:                        if (v3)
                   1173:                            error = EINVAL;
1.1       cgd      1174:                        else
1.23      fvdl     1175:                            error = (vp->v_type == VDIR) ? EISDIR : EACCES;
                   1176:                    }
                   1177:                } else
                   1178:                    vp = NULL;
                   1179:                if (!error) {
                   1180:                    nqsrv_getl(vp, ND_WRITE);
1.99    ! christos 1181:                    error = nfsrv_access(vp, VWRITE, cred, rdonly, lwp, 1);
1.23      fvdl     1182:                }
1.94      perry    1183:
1.23      fvdl     1184:                if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
                   1185:                    ioflags = IO_NODELOCKED;
                   1186:                else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
                   1187:                    ioflags = (IO_SYNC | IO_NODELOCKED);
                   1188:                else
                   1189:                    ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
                   1190:                uiop->uio_rw = UIO_WRITE;
                   1191:                uiop->uio_segflg = UIO_SYSSPACE;
1.99    ! christos 1192:                uiop->uio_lwp = NULL;
1.23      fvdl     1193:                uiop->uio_offset = nfsd->nd_off;
                   1194:                uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
                   1195:                if (uiop->uio_resid > 0) {
                   1196:                    mp = mrep;
                   1197:                    i = 0;
                   1198:                    while (mp) {
                   1199:                        if (mp->m_len > 0)
                   1200:                            i++;
                   1201:                        mp = mp->m_next;
                   1202:                    }
                   1203:                    uiop->uio_iovcnt = i;
1.56      thorpej  1204:                    iov = malloc(i * sizeof (struct iovec), M_TEMP, M_WAITOK);
1.23      fvdl     1205:                    uiop->uio_iov = ivp = iov;
                   1206:                    mp = mrep;
                   1207:                    while (mp) {
                   1208:                        if (mp->m_len > 0) {
                   1209:                            ivp->iov_base = mtod(mp, caddr_t);
                   1210:                            ivp->iov_len = mp->m_len;
                   1211:                            ivp++;
                   1212:                        }
1.1       cgd      1213:                        mp = mp->m_next;
1.23      fvdl     1214:                    }
                   1215:                    if (!error) {
1.82      hannken  1216:                        if (vn_start_write(vp, &mntp, V_NOWAIT) != 0) {
                   1217:                            VOP_UNLOCK(vp, 0);
1.86      hannken  1218:                            vn_start_write(NULL, &mntp, V_WAIT);
1.82      hannken  1219:                            vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                   1220:                        }
                   1221:                        if (!error) {
                   1222:                            error = VOP_WRITE(vp, uiop, ioflags, cred);
                   1223:                            nfsstats.srvvop_writes++;
                   1224:                            vn_finished_write(mntp, 0);
                   1225:                        }
1.23      fvdl     1226:                    }
1.56      thorpej  1227:                    free((caddr_t)iov, M_TEMP);
1.1       cgd      1228:                }
1.23      fvdl     1229:                m_freem(mrep);
                   1230:                if (vp) {
1.99    ! christos 1231:                    aftat_ret = VOP_GETATTR(vp, &va, cred, lwp);
1.23      fvdl     1232:                    vput(vp);
1.1       cgd      1233:                }
1.23      fvdl     1234:
                   1235:                /*
                   1236:                 * Loop around generating replies for all write rpcs that have
                   1237:                 * now been completed.
                   1238:                 */
                   1239:                swp = nfsd;
                   1240:                do {
                   1241:                    if (error) {
                   1242:                        nfsm_writereply(NFSX_WCCDATA(v3), v3);
                   1243:                        if (v3) {
                   1244:                            nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
                   1245:                        }
                   1246:                    } else {
                   1247:                        nfsm_writereply(NFSX_PREOPATTR(v3) +
                   1248:                            NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
                   1249:                            NFSX_WRITEVERF(v3), v3);
                   1250:                        if (v3) {
                   1251:                            nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
                   1252:                            nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
                   1253:                            *tl++ = txdr_unsigned(nfsd->nd_len);
                   1254:                            *tl++ = txdr_unsigned(swp->nd_stable);
                   1255:                            /*
                   1256:                             * Actually, there is no need to txdr these fields,
                   1257:                             * but it may make the values more human readable,
                   1258:                             * for debugging purposes.
                   1259:                             */
                   1260:                            *tl++ = txdr_unsigned(boottime.tv_sec);
                   1261:                            *tl = txdr_unsigned(boottime.tv_usec);
                   1262:                        } else {
                   1263:                            nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
                   1264:                            nfsm_srvfillattr(&va, fp);
                   1265:                        }
                   1266:                    }
                   1267:                    nfsd->nd_mreq = mreq;
                   1268:                    if (nfsd->nd_mrep)
                   1269:                        panic("nfsrv_write: nd_mrep not free");
                   1270:
                   1271:                    /*
                   1272:                     * Done. Put it at the head of the timer queue so that
                   1273:                     * the final phase can return the reply.
                   1274:                     */
                   1275:                    s = splsoftclock();
                   1276:                    if (nfsd != swp) {
                   1277:                        nfsd->nd_time = 0;
                   1278:                        LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
                   1279:                    }
1.70      yamt     1280:                    nfsd = LIST_FIRST(&swp->nd_coalesce);
1.23      fvdl     1281:                    if (nfsd) {
                   1282:                        LIST_REMOVE(nfsd, nd_tq);
                   1283:                    }
                   1284:                    splx(s);
                   1285:                } while (nfsd);
                   1286:                s = splsoftclock();
                   1287:                swp->nd_time = 0;
                   1288:                LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
                   1289:                splx(s);
                   1290:                goto loop1;
                   1291:        }
                   1292:        splx(s);
                   1293:
                   1294:        /*
                   1295:         * Search for a reply to return.
                   1296:         */
                   1297:        s = splsoftclock();
1.70      yamt     1298:        LIST_FOREACH(nfsd, &slp->ns_tq, nd_tq) {
1.23      fvdl     1299:                if (nfsd->nd_mreq) {
                   1300:                    LIST_REMOVE(nfsd, nd_tq);
                   1301:                    *mrq = nfsd->nd_mreq;
                   1302:                    *ndp = nfsd;
                   1303:                    break;
1.1       cgd      1304:                }
1.70      yamt     1305:        }
1.23      fvdl     1306:        splx(s);
                   1307:        return (0);
                   1308: }
                   1309:
                   1310: /*
                   1311:  * Coalesce the write request nfsd into owp. To do this we must:
                   1312:  * - remove nfsd from the queues
                   1313:  * - merge nfsd->nd_mrep into owp->nd_mrep
                   1314:  * - update the nd_eoff and nd_stable for owp
                   1315:  * - put nfsd on owp's nd_coalesce list
                   1316:  * NB: Must be called at splsoftclock().
                   1317:  */
                   1318: void
                   1319: nfsrvw_coalesce(owp, nfsd)
1.54      augustss 1320:         struct nfsrv_descript *owp;
                   1321:         struct nfsrv_descript *nfsd;
1.23      fvdl     1322: {
1.54      augustss 1323:         int overlap;
                   1324:         struct mbuf *mp;
1.70      yamt     1325:        struct nfsrv_descript *m;
1.23      fvdl     1326:
                   1327:         LIST_REMOVE(nfsd, nd_hash);
                   1328:         LIST_REMOVE(nfsd, nd_tq);
                   1329:         if (owp->nd_eoff < nfsd->nd_eoff) {
                   1330:             overlap = owp->nd_eoff - nfsd->nd_off;
                   1331:             if (overlap < 0)
                   1332:                 panic("nfsrv_coalesce: bad off");
                   1333:             if (overlap > 0)
                   1334:                 m_adj(nfsd->nd_mrep, overlap);
                   1335:             mp = owp->nd_mrep;
                   1336:             while (mp->m_next)
                   1337:                 mp = mp->m_next;
                   1338:             mp->m_next = nfsd->nd_mrep;
                   1339:             owp->nd_eoff = nfsd->nd_eoff;
                   1340:         } else
                   1341:             m_freem(nfsd->nd_mrep);
                   1342:         nfsd->nd_mrep = NULL;
                   1343:         if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
                   1344:             owp->nd_stable = NFSV3WRITE_FILESYNC;
                   1345:         else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
                   1346:             owp->nd_stable == NFSV3WRITE_UNSTABLE)
                   1347:             owp->nd_stable = NFSV3WRITE_DATASYNC;
                   1348:         LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
1.34      fvdl     1349:        /*
                   1350:         * nfsd might hold coalesce elements! Move them to owp.
                   1351:         * Otherwise, requests may be lost and clients will be stuck.
                   1352:         */
1.70      yamt     1353:        while ((m = LIST_FIRST(&nfsd->nd_coalesce)) != NULL) {
                   1354:                LIST_REMOVE(m, nd_tq);
                   1355:                LIST_INSERT_HEAD(&owp->nd_coalesce, m, nd_tq);
                   1356:        }
1.1       cgd      1357: }
                   1358:
                   1359: /*
                   1360:  * nfs create service
1.15      mycroft  1361:  * now does a truncate to 0 length via. setattr if it already exists
1.1       cgd      1362:  */
1.22      christos 1363: int
1.99    ! christos 1364: nfsrv_create(nfsd, slp, lwp, mrq)
1.23      fvdl     1365:        struct nfsrv_descript *nfsd;
                   1366:        struct nfssvc_sock *slp;
1.99    ! christos 1367:        struct lwp *lwp;
1.23      fvdl     1368:        struct mbuf **mrq;
1.1       cgd      1369: {
1.23      fvdl     1370:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                   1371:        struct mbuf *nam = nfsd->nd_nam;
                   1372:        caddr_t dpos = nfsd->nd_dpos;
                   1373:        struct ucred *cred = &nfsd->nd_cr;
1.54      augustss 1374:        struct nfs_fattr *fp;
1.23      fvdl     1375:        struct vattr va, dirfor, diraft;
1.54      augustss 1376:        struct nfsv2_sattr *sp;
                   1377:        u_int32_t *tl;
1.1       cgd      1378:        struct nameidata nd;
1.54      augustss 1379:        caddr_t cp;
                   1380:        int32_t t1;
1.1       cgd      1381:        caddr_t bpos;
1.23      fvdl     1382:        int error = 0, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
                   1383:        int rdev = 0;
                   1384:        int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
1.1       cgd      1385:        char *cp2;
1.67      matt     1386:        struct mbuf *mb, *mreq;
1.23      fvdl     1387:        struct vnode *vp = NULL, *dirp = NULL;
                   1388:        nfsfh_t nfh;
1.1       cgd      1389:        fhandle_t *fhp;
1.23      fvdl     1390:        u_quad_t frev, tempsize;
                   1391:        u_char cverf[NFSX_V3CREATEVERF];
1.82      hannken  1392:        struct mount *mp = NULL;
1.1       cgd      1393:
1.15      mycroft  1394:        nd.ni_cnd.cn_nameiop = 0;
1.1       cgd      1395:        fhp = &nfh.fh_generic;
                   1396:        nfsm_srvmtofh(fhp);
1.82      hannken  1397:        if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
                   1398:                return (ESTALE);
                   1399:        vn_start_write(NULL, &mp, V_WAIT);
1.23      fvdl     1400:        nfsm_srvnamesiz(len);
1.15      mycroft  1401:        nd.ni_cnd.cn_cred = cred;
                   1402:        nd.ni_cnd.cn_nameiop = CREATE;
1.61      chs      1403:        nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1.23      fvdl     1404:        error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1.99    ! christos 1405:                &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl     1406:        if (dirp) {
                   1407:                if (v3)
1.99    ! christos 1408:                        dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, lwp);
1.23      fvdl     1409:                else {
                   1410:                        vrele(dirp);
                   1411:                        dirp = (struct vnode *)0;
                   1412:                }
                   1413:        }
                   1414:        if (error) {
                   1415:                nfsm_reply(NFSX_WCCDATA(v3));
                   1416:                nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
                   1417:                if (dirp)
                   1418:                        vrele(dirp);
1.82      hannken  1419:                vn_finished_write(mp, 0);
1.23      fvdl     1420:                return (0);
                   1421:        }
1.18      mycroft  1422:        VATTR_NULL(&va);
1.23      fvdl     1423:        if (v3) {
1.92      yamt     1424:                va.va_mode = 0;
1.23      fvdl     1425:                nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
                   1426:                how = fxdr_unsigned(int, *tl);
                   1427:                switch (how) {
                   1428:                case NFSV3CREATE_GUARDED:
                   1429:                        if (nd.ni_vp) {
                   1430:                                error = EEXIST;
                   1431:                                break;
                   1432:                        }
                   1433:                case NFSV3CREATE_UNCHECKED:
                   1434:                        nfsm_srvsattr(&va);
                   1435:                        break;
                   1436:                case NFSV3CREATE_EXCLUSIVE:
                   1437:                        nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
1.44      perry    1438:                        memcpy(cverf, cp, NFSX_V3CREATEVERF);
1.23      fvdl     1439:                        exclusive_flag = 1;
                   1440:                        break;
                   1441:                };
                   1442:                va.va_type = VREG;
                   1443:        } else {
                   1444:                nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
                   1445:                va.va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
                   1446:                if (va.va_type == VNON)
                   1447:                        va.va_type = VREG;
                   1448:                va.va_mode = nfstov_mode(sp->sa_mode);
                   1449:                switch (va.va_type) {
                   1450:                case VREG:
                   1451:                        tsize = fxdr_unsigned(int32_t, sp->sa_size);
                   1452:                        if (tsize != -1)
                   1453:                                va.va_size = (u_quad_t)tsize;
                   1454:                        break;
                   1455:                case VCHR:
                   1456:                case VBLK:
                   1457:                case VFIFO:
                   1458:                        rdev = fxdr_unsigned(int32_t, sp->sa_size);
                   1459:                        break;
                   1460:                default:
                   1461:                        break;
                   1462:                };
                   1463:        }
                   1464:
1.1       cgd      1465:        /*
1.15      mycroft  1466:         * Iff doesn't exist, create it
                   1467:         * otherwise just truncate to 0 length
1.1       cgd      1468:         *   should I set the mode too ??
                   1469:         */
                   1470:        if (nd.ni_vp == NULL) {
1.18      mycroft  1471:                if (va.va_type == VREG || va.va_type == VSOCK) {
1.23      fvdl     1472:                        nqsrv_getl(nd.ni_dvp, ND_WRITE);
                   1473:                        error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
                   1474:                        if (!error) {
                   1475:                                if (exclusive_flag) {
                   1476:                                        exclusive_flag = 0;
                   1477:                                        VATTR_NULL(&va);
1.89      yamt     1478:                                        /*
                   1479:                                         * XXX
                   1480:                                         * assuming NFSX_V3CREATEVERF
                   1481:                                         * == sizeof(nfstime3)
                   1482:                                         */
                   1483:                                        fxdr_nfsv3time(cverf, &va.va_atime);
1.23      fvdl     1484:                                        error = VOP_SETATTR(nd.ni_vp, &va, cred,
1.99    ! christos 1485:                                                lwp);
1.23      fvdl     1486:                                }
                   1487:                        }
1.18      mycroft  1488:                } else if (va.va_type == VCHR || va.va_type == VBLK ||
                   1489:                        va.va_type == VFIFO) {
                   1490:                        if (va.va_type == VCHR && rdev == 0xffffffff)
                   1491:                                va.va_type = VFIFO;
1.46      mrg      1492:                        if (va.va_type != VFIFO &&
                   1493:                            (error = suser(cred, (u_short *)0))) {
1.15      mycroft  1494:                                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1       cgd      1495:                                vput(nd.ni_dvp);
1.23      fvdl     1496:                                nfsm_reply(0);
1.82      hannken  1497:                                vn_finished_write(mp, 0);
1.23      fvdl     1498:                                return (error);
1.1       cgd      1499:                        } else
1.18      mycroft  1500:                                va.va_rdev = (dev_t)rdev;
1.23      fvdl     1501:                        nqsrv_getl(nd.ni_dvp, ND_WRITE);
1.22      christos 1502:                        error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd,
1.23      fvdl     1503:                            &va);
1.22      christos 1504:                        if (error) {
1.1       cgd      1505:                                nfsm_reply(0);
                   1506:                        }
1.15      mycroft  1507:                        if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1.1       cgd      1508:                                vrele(nd.ni_dvp);
                   1509:                                vput(nd.ni_vp);
1.15      mycroft  1510:                                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1       cgd      1511:                                error = EINVAL;
                   1512:                                nfsm_reply(0);
                   1513:                        }
                   1514:                } else {
1.15      mycroft  1515:                        VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1       cgd      1516:                        vput(nd.ni_dvp);
                   1517:                        error = ENXIO;
                   1518:                }
                   1519:                vp = nd.ni_vp;
                   1520:        } else {
                   1521:                vp = nd.ni_vp;
                   1522:                if (nd.ni_dvp == vp)
                   1523:                        vrele(nd.ni_dvp);
                   1524:                else
                   1525:                        vput(nd.ni_dvp);
1.15      mycroft  1526:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.50      mycroft  1527:                if (!error && va.va_size != -1) {
1.22      christos 1528:                        error = nfsrv_access(vp, VWRITE, cred,
1.99    ! christos 1529:                            (nd.ni_cnd.cn_flags & RDONLY), lwp, 0);
1.23      fvdl     1530:                        if (!error) {
                   1531:                                nqsrv_getl(vp, ND_WRITE);
                   1532:                                tempsize = va.va_size;
                   1533:                                VATTR_NULL(&va);
                   1534:                                va.va_size = tempsize;
1.99    ! christos 1535:                                error = VOP_SETATTR(vp, &va, cred, lwp);
1.15      mycroft  1536:                        }
1.1       cgd      1537:                }
1.50      mycroft  1538:                if (error)
                   1539:                        vput(vp);
1.1       cgd      1540:        }
1.23      fvdl     1541:        if (!error) {
1.44      perry    1542:                memset((caddr_t)fhp, 0, sizeof(nfh));
1.88      christos 1543:                fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsidx;
1.23      fvdl     1544:                error = VFS_VPTOFH(vp, &fhp->fh_fid);
                   1545:                if (!error)
1.99    ! christos 1546:                        error = VOP_GETATTR(vp, &va, cred, lwp);
1.1       cgd      1547:                vput(vp);
                   1548:        }
1.23      fvdl     1549:        if (v3) {
1.89      yamt     1550:                if (exclusive_flag && !error) {
                   1551:                        /*
                   1552:                         * XXX assuming NFSX_V3CREATEVERF == sizeof(nfstime3)
                   1553:                         */
                   1554:                        char oldverf[NFSX_V3CREATEVERF];
                   1555:
                   1556:                        txdr_nfsv3time(&va.va_atime, oldverf);
                   1557:                        if (memcmp(cverf, oldverf, NFSX_V3CREATEVERF))
                   1558:                                error = EEXIST;
                   1559:                }
1.99    ! christos 1560:                diraft_ret = VOP_GETATTR(dirp, &diraft, cred, lwp);
1.23      fvdl     1561:                vrele(dirp);
                   1562:        }
                   1563:        nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
                   1564:        if (v3) {
                   1565:                if (!error) {
                   1566:                        nfsm_srvpostop_fh(fhp);
                   1567:                        nfsm_srvpostop_attr(0, &va);
                   1568:                }
                   1569:                nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
                   1570:        } else {
                   1571:                nfsm_srvfhtom(fhp, v3);
                   1572:                nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
                   1573:                nfsm_srvfillattr(&va, fp);
                   1574:        }
1.82      hannken  1575:        vn_finished_write(mp, 0);
1.23      fvdl     1576:        return (0);
1.1       cgd      1577: nfsmout:
1.23      fvdl     1578:        if (dirp)
                   1579:                vrele(dirp);
1.15      mycroft  1580:        VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1       cgd      1581:        if (nd.ni_dvp == nd.ni_vp)
                   1582:                vrele(nd.ni_dvp);
                   1583:        else
                   1584:                vput(nd.ni_dvp);
                   1585:        if (nd.ni_vp)
                   1586:                vput(nd.ni_vp);
1.82      hannken  1587:        vn_finished_write(mp, 0);
1.1       cgd      1588:        return (error);
1.23      fvdl     1589: }
                   1590:
                   1591: /*
                   1592:  * nfs v3 mknod service
                   1593:  */
                   1594: int
1.99    ! christos 1595: nfsrv_mknod(nfsd, slp, lwp, mrq)
1.23      fvdl     1596:        struct nfsrv_descript *nfsd;
                   1597:        struct nfssvc_sock *slp;
1.99    ! christos 1598:        struct lwp *lwp;
1.23      fvdl     1599:        struct mbuf **mrq;
                   1600: {
                   1601:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                   1602:        struct mbuf *nam = nfsd->nd_nam;
                   1603:        caddr_t dpos = nfsd->nd_dpos;
                   1604:        struct ucred *cred = &nfsd->nd_cr;
                   1605:        struct vattr va, dirfor, diraft;
1.54      augustss 1606:        u_int32_t *tl;
1.23      fvdl     1607:        struct nameidata nd;
1.54      augustss 1608:        int32_t t1;
1.23      fvdl     1609:        caddr_t bpos;
                   1610:        int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
                   1611:        u_int32_t major, minor;
                   1612:        enum vtype vtyp;
                   1613:        char *cp2;
1.67      matt     1614:        struct mbuf *mb, *mreq;
1.23      fvdl     1615:        struct vnode *vp, *dirp = (struct vnode *)0;
                   1616:        nfsfh_t nfh;
                   1617:        fhandle_t *fhp;
                   1618:        u_quad_t frev;
1.82      hannken  1619:        struct mount *mp = NULL;
1.23      fvdl     1620:
                   1621:        nd.ni_cnd.cn_nameiop = 0;
                   1622:        fhp = &nfh.fh_generic;
                   1623:        nfsm_srvmtofh(fhp);
1.82      hannken  1624:        if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
                   1625:                return (ESTALE);
                   1626:        vn_start_write(NULL, &mp, V_WAIT);
1.23      fvdl     1627:        nfsm_srvnamesiz(len);
                   1628:        nd.ni_cnd.cn_cred = cred;
                   1629:        nd.ni_cnd.cn_nameiop = CREATE;
1.61      chs      1630:        nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1.23      fvdl     1631:        error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1.99    ! christos 1632:                &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl     1633:        if (dirp)
1.99    ! christos 1634:                dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, lwp);
1.23      fvdl     1635:        if (error) {
                   1636:                nfsm_reply(NFSX_WCCDATA(1));
                   1637:                nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
                   1638:                if (dirp)
                   1639:                        vrele(dirp);
1.82      hannken  1640:                vn_finished_write(mp, 0);
1.23      fvdl     1641:                return (0);
                   1642:        }
                   1643:        nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
                   1644:        vtyp = nfsv3tov_type(*tl);
                   1645:        if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
                   1646:                error = NFSERR_BADTYPE;
1.95      yamt     1647:                goto abort;
1.23      fvdl     1648:        }
                   1649:        VATTR_NULL(&va);
1.92      yamt     1650:        va.va_mode = 0;
1.23      fvdl     1651:        nfsm_srvsattr(&va);
                   1652:        if (vtyp == VCHR || vtyp == VBLK) {
1.95      yamt     1653:                dev_t rdev;
                   1654:
1.23      fvdl     1655:                nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
                   1656:                major = fxdr_unsigned(u_int32_t, *tl++);
                   1657:                minor = fxdr_unsigned(u_int32_t, *tl);
1.95      yamt     1658:                rdev = makedev(major, minor);
                   1659:                if (major(rdev) != major || minor(rdev) != minor) {
                   1660:                        error = EINVAL;
                   1661:                        goto abort;
                   1662:                }
                   1663:                va.va_rdev = rdev;
1.23      fvdl     1664:        }
1.1       cgd      1665:
1.23      fvdl     1666:        /*
                   1667:         * Iff doesn't exist, create it.
                   1668:         */
                   1669:        if (nd.ni_vp) {
                   1670:                error = EEXIST;
1.95      yamt     1671: abort:
1.23      fvdl     1672:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.51      sommerfe 1673:                if (nd.ni_dvp == nd.ni_vp)
                   1674:                        vrele(nd.ni_dvp);
                   1675:                else
                   1676:                        vput(nd.ni_dvp);
1.95      yamt     1677:                if (nd.ni_vp)
                   1678:                        vput(nd.ni_vp);
1.23      fvdl     1679:                goto out;
                   1680:        }
                   1681:        va.va_type = vtyp;
                   1682:        if (vtyp == VSOCK) {
                   1683:                nqsrv_getl(nd.ni_dvp, ND_WRITE);
                   1684:                error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
                   1685:        } else {
1.46      mrg      1686:                if (va.va_type != VFIFO &&
                   1687:                    (error = suser(cred, (u_short *)0))) {
1.23      fvdl     1688:                        VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   1689:                        vput(nd.ni_dvp);
                   1690:                        goto out;
                   1691:                }
                   1692:                nqsrv_getl(nd.ni_dvp, ND_WRITE);
                   1693:                error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
                   1694:                if (error) {
                   1695:                        goto out;
                   1696:                }
                   1697:                if (error)
                   1698:                        goto out;
                   1699:                if (nd.ni_cnd.cn_flags & ISSYMLINK) {
                   1700:                        vput(nd.ni_vp);
                   1701:                        VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   1702:                        error = EINVAL;
                   1703:                }
                   1704:        }
1.1       cgd      1705: out:
1.23      fvdl     1706:        vp = nd.ni_vp;
                   1707:        if (!error) {
1.44      perry    1708:                memset((caddr_t)fhp, 0, sizeof(nfh));
1.88      christos 1709:                fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsidx;
1.23      fvdl     1710:                error = VFS_VPTOFH(vp, &fhp->fh_fid);
                   1711:                if (!error)
1.99    ! christos 1712:                        error = VOP_GETATTR(vp, &va, cred, lwp);
1.23      fvdl     1713:                vput(vp);
                   1714:        }
1.99    ! christos 1715:        diraft_ret = VOP_GETATTR(dirp, &diraft, cred, lwp);
1.23      fvdl     1716:        vrele(dirp);
                   1717:        nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
                   1718:        if (!error) {
                   1719:                nfsm_srvpostop_fh(fhp);
                   1720:                nfsm_srvpostop_attr(0, &va);
                   1721:        }
                   1722:        nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1.82      hannken  1723:        vn_finished_write(mp, 0);
1.23      fvdl     1724:        return (0);
                   1725: nfsmout:
                   1726:        if (dirp)
                   1727:                vrele(dirp);
                   1728:        VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   1729:        if (nd.ni_dvp == nd.ni_vp)
                   1730:                vrele(nd.ni_dvp);
                   1731:        else
                   1732:                vput(nd.ni_dvp);
                   1733:        if (nd.ni_vp)
                   1734:                vput(nd.ni_vp);
1.82      hannken  1735:        vn_finished_write(mp, 0);
1.23      fvdl     1736:        return (error);
1.1       cgd      1737: }
                   1738:
                   1739: /*
                   1740:  * nfs remove service
                   1741:  */
1.22      christos 1742: int
1.99    ! christos 1743: nfsrv_remove(nfsd, slp, lwp, mrq)
1.23      fvdl     1744:        struct nfsrv_descript *nfsd;
                   1745:        struct nfssvc_sock *slp;
1.99    ! christos 1746:        struct lwp *lwp;
1.23      fvdl     1747:        struct mbuf **mrq;
1.1       cgd      1748: {
1.23      fvdl     1749:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                   1750:        struct mbuf *nam = nfsd->nd_nam;
                   1751:        caddr_t dpos = nfsd->nd_dpos;
                   1752:        struct ucred *cred = &nfsd->nd_cr;
1.1       cgd      1753:        struct nameidata nd;
1.54      augustss 1754:        u_int32_t *tl;
                   1755:        int32_t t1;
1.1       cgd      1756:        caddr_t bpos;
1.23      fvdl     1757:        int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
                   1758:        int v3 = (nfsd->nd_flag & ND_NFSV3);
1.1       cgd      1759:        char *cp2;
                   1760:        struct mbuf *mb, *mreq;
1.23      fvdl     1761:        struct vnode *vp, *dirp;
                   1762:        struct vattr dirfor, diraft;
                   1763:        nfsfh_t nfh;
1.1       cgd      1764:        fhandle_t *fhp;
1.15      mycroft  1765:        u_quad_t frev;
1.82      hannken  1766:        struct mount *mp = NULL;
1.1       cgd      1767:
1.23      fvdl     1768: #ifndef nolint
                   1769:        vp = (struct vnode *)0;
                   1770: #endif
1.1       cgd      1771:        fhp = &nfh.fh_generic;
                   1772:        nfsm_srvmtofh(fhp);
1.82      hannken  1773:        if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
                   1774:                return (ESTALE);
                   1775:        vn_start_write(NULL, &mp, V_WAIT);
1.23      fvdl     1776:        nfsm_srvnamesiz(len);
1.15      mycroft  1777:        nd.ni_cnd.cn_cred = cred;
                   1778:        nd.ni_cnd.cn_nameiop = DELETE;
                   1779:        nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1.23      fvdl     1780:        error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1.99    ! christos 1781:                &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl     1782:        if (dirp) {
                   1783:                if (v3)
1.99    ! christos 1784:                        dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, lwp);
1.1       cgd      1785:                else
1.23      fvdl     1786:                        vrele(dirp);
1.1       cgd      1787:        }
1.23      fvdl     1788:        if (!error) {
                   1789:                vp = nd.ni_vp;
                   1790:                if (vp->v_type == VDIR &&
                   1791:                    (error = suser(cred, (u_short *)0)) != 0)
                   1792:                        goto out;
                   1793:                /*
                   1794:                 * The root of a mounted filesystem cannot be deleted.
                   1795:                 */
                   1796:                if (vp->v_flag & VROOT) {
                   1797:                        error = EBUSY;
                   1798:                        goto out;
                   1799:                }
1.21      mycroft  1800: out:
1.23      fvdl     1801:                if (!error) {
                   1802:                        nqsrv_getl(nd.ni_dvp, ND_WRITE);
                   1803:                        nqsrv_getl(vp, ND_WRITE);
                   1804:                        error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
                   1805:                } else {
                   1806:                        VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                   1807:                        if (nd.ni_dvp == vp)
                   1808:                                vrele(nd.ni_dvp);
                   1809:                        else
                   1810:                                vput(nd.ni_dvp);
                   1811:                        vput(vp);
                   1812:                }
                   1813:        }
                   1814:        if (dirp && v3) {
1.99    ! christos 1815:                diraft_ret = VOP_GETATTR(dirp, &diraft, cred, lwp);
1.23      fvdl     1816:                vrele(dirp);
                   1817:        }
                   1818:        nfsm_reply(NFSX_WCCDATA(v3));
                   1819:        if (v3) {
                   1820:                nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1.82      hannken  1821:                vn_finished_write(mp, 0);
1.23      fvdl     1822:                return (0);
                   1823:        }
1.82      hannken  1824:        vn_finished_write(mp, 0);
1.1       cgd      1825:        nfsm_srvdone;
                   1826: }
                   1827:
                   1828: /*
                   1829:  * nfs rename service
                   1830:  */
1.22      christos 1831: int
1.99    ! christos 1832: nfsrv_rename(nfsd, slp, lwp, mrq)
1.23      fvdl     1833:        struct nfsrv_descript *nfsd;
                   1834:        struct nfssvc_sock *slp;
1.99    ! christos 1835:        struct lwp *lwp;
1.23      fvdl     1836:        struct mbuf **mrq;
1.1       cgd      1837: {
1.23      fvdl     1838:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                   1839:        struct mbuf *nam = nfsd->nd_nam;
                   1840:        caddr_t dpos = nfsd->nd_dpos;
                   1841:        struct ucred *cred = &nfsd->nd_cr;
1.54      augustss 1842:        u_int32_t *tl;
                   1843:        int32_t t1;
1.1       cgd      1844:        caddr_t bpos;
1.68      yamt     1845:        int error = 0, cache, fdirfor_ret = 1, fdiraft_ret = 1;
                   1846:        uint32_t len, len2;
1.23      fvdl     1847:        int tdirfor_ret = 1, tdiraft_ret = 1;
                   1848:        int v3 = (nfsd->nd_flag & ND_NFSV3);
1.1       cgd      1849:        char *cp2;
                   1850:        struct mbuf *mb, *mreq;
                   1851:        struct nameidata fromnd, tond;
1.23      fvdl     1852:        struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0;
                   1853:        struct vnode *tdirp = (struct vnode *)0;
                   1854:        struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
                   1855:        nfsfh_t fnfh, tnfh;
1.1       cgd      1856:        fhandle_t *ffhp, *tfhp;
1.15      mycroft  1857:        u_quad_t frev;
                   1858:        uid_t saved_uid;
1.82      hannken  1859:        struct mount *mp = NULL;
1.1       cgd      1860:
1.23      fvdl     1861: #ifndef nolint
                   1862:        fvp = (struct vnode *)0;
                   1863: #endif
1.1       cgd      1864:        ffhp = &fnfh.fh_generic;
                   1865:        tfhp = &tnfh.fh_generic;
1.15      mycroft  1866:        fromnd.ni_cnd.cn_nameiop = 0;
                   1867:        tond.ni_cnd.cn_nameiop = 0;
1.1       cgd      1868:        nfsm_srvmtofh(ffhp);
1.82      hannken  1869:        if ((mp = vfs_getvfs(&ffhp->fh_fsid)) == NULL)
                   1870:                return (ESTALE);
                   1871:        vn_start_write(NULL, &mp, V_WAIT);
1.23      fvdl     1872:        nfsm_srvnamesiz(len);
1.1       cgd      1873:        /*
1.15      mycroft  1874:         * Remember our original uid so that we can reset cr_uid before
                   1875:         * the second nfs_namei() call, in case it is remapped.
1.1       cgd      1876:         */
1.15      mycroft  1877:        saved_uid = cred->cr_uid;
                   1878:        fromnd.ni_cnd.cn_cred = cred;
                   1879:        fromnd.ni_cnd.cn_nameiop = DELETE;
                   1880:        fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
1.23      fvdl     1881:        error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
1.99    ! christos 1882:                &dpos, &fdirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl     1883:        if (fdirp) {
                   1884:                if (v3)
1.99    ! christos 1885:                        fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred, lwp);
1.23      fvdl     1886:                else {
                   1887:                        vrele(fdirp);
                   1888:                        fdirp = (struct vnode *)0;
                   1889:                }
                   1890:        }
                   1891:        if (error) {
                   1892:                nfsm_reply(2 * NFSX_WCCDATA(v3));
                   1893:                nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
                   1894:                nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
                   1895:                if (fdirp)
                   1896:                        vrele(fdirp);
1.82      hannken  1897:                vn_finished_write(mp, 0);
1.23      fvdl     1898:                return (0);
                   1899:        }
1.1       cgd      1900:        fvp = fromnd.ni_vp;
                   1901:        nfsm_srvmtofh(tfhp);
1.68      yamt     1902:        if (v3) {
                   1903:                nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED);
                   1904:                len2 = fxdr_unsigned(uint32_t, *tl);
                   1905:                /* len2 will be checked by nfs_namei */
                   1906:        }
                   1907:        else {
                   1908:                /* NFSv2 */
                   1909:                nfsm_strsiz(len2, NFS_MAXNAMLEN);
                   1910:        }
1.15      mycroft  1911:        cred->cr_uid = saved_uid;
                   1912:        tond.ni_cnd.cn_cred = cred;
                   1913:        tond.ni_cnd.cn_nameiop = RENAME;
                   1914:        tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
1.23      fvdl     1915:        error = nfs_namei(&tond, tfhp, len2, slp, nam, &md,
1.99    ! christos 1916:                &dpos, &tdirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl     1917:        if (tdirp) {
                   1918:                if (v3)
1.99    ! christos 1919:                        tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred, lwp);
1.23      fvdl     1920:                else {
                   1921:                        vrele(tdirp);
                   1922:                        tdirp = (struct vnode *)0;
                   1923:                }
                   1924:        }
1.22      christos 1925:        if (error) {
1.15      mycroft  1926:                VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1.1       cgd      1927:                vrele(fromnd.ni_dvp);
                   1928:                vrele(fvp);
                   1929:                goto out1;
                   1930:        }
                   1931:        tdvp = tond.ni_dvp;
                   1932:        tvp = tond.ni_vp;
                   1933:        if (tvp != NULL) {
                   1934:                if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1.23      fvdl     1935:                        if (v3)
                   1936:                                error = EEXIST;
                   1937:                        else
                   1938:                                error = EISDIR;
1.1       cgd      1939:                        goto out;
                   1940:                } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1.23      fvdl     1941:                        if (v3)
                   1942:                                error = EEXIST;
                   1943:                        else
                   1944:                                error = ENOTDIR;
1.1       cgd      1945:                        goto out;
                   1946:                }
1.15      mycroft  1947:                if (tvp->v_type == VDIR && tvp->v_mountedhere) {
1.23      fvdl     1948:                        if (v3)
                   1949:                                error = EXDEV;
                   1950:                        else
                   1951:                                error = ENOTEMPTY;
1.15      mycroft  1952:                        goto out;
                   1953:                }
                   1954:        }
                   1955:        if (fvp->v_type == VDIR && fvp->v_mountedhere) {
1.23      fvdl     1956:                if (v3)
                   1957:                        error = EXDEV;
                   1958:                else
                   1959:                        error = ENOTEMPTY;
1.15      mycroft  1960:                goto out;
1.1       cgd      1961:        }
                   1962:        if (fvp->v_mount != tdvp->v_mount) {
1.23      fvdl     1963:                if (v3)
                   1964:                        error = EXDEV;
                   1965:                else
                   1966:                        error = ENOTEMPTY;
1.1       cgd      1967:                goto out;
                   1968:        }
1.45      thorpej  1969:        if (fvp == tdvp) {
1.23      fvdl     1970:                if (v3)
                   1971:                        error = EINVAL;
                   1972:                else
                   1973:                        error = ENOTEMPTY;
1.45      thorpej  1974:        }
1.1       cgd      1975:        /*
                   1976:         * If source is the same as the destination (that is the
                   1977:         * same vnode with the same name in the same directory),
                   1978:         * then there is nothing to do.
                   1979:         */
                   1980:        if (fvp == tvp && fromnd.ni_dvp == tdvp &&
1.15      mycroft  1981:            fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
1.44      perry    1982:            !memcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
1.15      mycroft  1983:              fromnd.ni_cnd.cn_namelen))
1.1       cgd      1984:                error = -1;
                   1985: out:
                   1986:        if (!error) {
1.23      fvdl     1987:                nqsrv_getl(fromnd.ni_dvp, ND_WRITE);
                   1988:                nqsrv_getl(tdvp, ND_WRITE);
1.30      fvdl     1989:                if (tvp) {
1.23      fvdl     1990:                        nqsrv_getl(tvp, ND_WRITE);
1.30      fvdl     1991:                }
1.15      mycroft  1992:                error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
                   1993:                                   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
1.1       cgd      1994:        } else {
1.15      mycroft  1995:                VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
1.1       cgd      1996:                if (tdvp == tvp)
                   1997:                        vrele(tdvp);
                   1998:                else
                   1999:                        vput(tdvp);
                   2000:                if (tvp)
                   2001:                        vput(tvp);
1.15      mycroft  2002:                VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1.1       cgd      2003:                vrele(fromnd.ni_dvp);
                   2004:                vrele(fvp);
1.23      fvdl     2005:                if (error == -1)
                   2006:                        error = 0;
1.1       cgd      2007:        }
                   2008:        vrele(tond.ni_startdir);
1.57      thorpej  2009:        PNBUF_PUT(tond.ni_cnd.cn_pnbuf);
1.1       cgd      2010: out1:
1.23      fvdl     2011:        if (fdirp) {
1.99    ! christos 2012:                fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, lwp);
1.23      fvdl     2013:                vrele(fdirp);
                   2014:        }
                   2015:        if (tdirp) {
1.99    ! christos 2016:                tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, lwp);
1.23      fvdl     2017:                vrele(tdirp);
                   2018:        }
1.1       cgd      2019:        vrele(fromnd.ni_startdir);
1.57      thorpej  2020:        PNBUF_PUT(fromnd.ni_cnd.cn_pnbuf);
1.23      fvdl     2021:        nfsm_reply(2 * NFSX_WCCDATA(v3));
                   2022:        if (v3) {
                   2023:                nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
                   2024:                nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
                   2025:        }
1.82      hannken  2026:        vn_finished_write(mp, 0);
1.23      fvdl     2027:        return (0);
1.1       cgd      2028:
                   2029: nfsmout:
1.23      fvdl     2030:        if (fdirp)
                   2031:                vrele(fdirp);
                   2032:        if (tdirp)
                   2033:                vrele(tdirp);
                   2034:        if (tond.ni_cnd.cn_nameiop) {
1.1       cgd      2035:                vrele(tond.ni_startdir);
1.57      thorpej  2036:                PNBUF_PUT(tond.ni_cnd.cn_pnbuf);
1.1       cgd      2037:        }
1.23      fvdl     2038:        if (fromnd.ni_cnd.cn_nameiop) {
1.1       cgd      2039:                vrele(fromnd.ni_startdir);
1.57      thorpej  2040:                PNBUF_PUT(fromnd.ni_cnd.cn_pnbuf);
1.15      mycroft  2041:                VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1.1       cgd      2042:                vrele(fromnd.ni_dvp);
                   2043:                vrele(fvp);
                   2044:        }
                   2045:        return (error);
                   2046: }
                   2047:
                   2048: /*
                   2049:  * nfs link service
                   2050:  */
1.22      christos 2051: int
1.99    ! christos 2052: nfsrv_link(nfsd, slp, lwp, mrq)
1.23      fvdl     2053:        struct nfsrv_descript *nfsd;
                   2054:        struct nfssvc_sock *slp;
1.99    ! christos 2055:        struct lwp *lwp;
1.23      fvdl     2056:        struct mbuf **mrq;
1.1       cgd      2057: {
1.23      fvdl     2058:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                   2059:        struct mbuf *nam = nfsd->nd_nam;
                   2060:        caddr_t dpos = nfsd->nd_dpos;
                   2061:        struct ucred *cred = &nfsd->nd_cr;
1.1       cgd      2062:        struct nameidata nd;
1.54      augustss 2063:        u_int32_t *tl;
                   2064:        int32_t t1;
1.1       cgd      2065:        caddr_t bpos;
1.23      fvdl     2066:        int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1;
                   2067:        int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
1.1       cgd      2068:        char *cp2;
                   2069:        struct mbuf *mb, *mreq;
1.23      fvdl     2070:        struct vnode *vp, *xp, *dirp = (struct vnode *)0;
                   2071:        struct vattr dirfor, diraft, at;
                   2072:        nfsfh_t nfh, dnfh;
1.1       cgd      2073:        fhandle_t *fhp, *dfhp;
1.15      mycroft  2074:        u_quad_t frev;
1.82      hannken  2075:        struct mount *mp = NULL;
1.1       cgd      2076:
                   2077:        fhp = &nfh.fh_generic;
                   2078:        dfhp = &dnfh.fh_generic;
                   2079:        nfsm_srvmtofh(fhp);
1.82      hannken  2080:        if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
                   2081:                return (ESTALE);
                   2082:        vn_start_write(NULL, &mp, V_WAIT);
1.1       cgd      2083:        nfsm_srvmtofh(dfhp);
1.23      fvdl     2084:        nfsm_srvnamesiz(len);
                   2085:        error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam,
1.78      thorpej  2086:                 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl     2087:        if (error) {
                   2088:                nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
                   2089:                nfsm_srvpostop_attr(getret, &at);
                   2090:                nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1.82      hannken  2091:                vn_finished_write(mp, 0);
1.23      fvdl     2092:                return (0);
                   2093:        }
                   2094:        if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0)) != 0)
                   2095:                goto out1;
1.15      mycroft  2096:        nd.ni_cnd.cn_cred = cred;
                   2097:        nd.ni_cnd.cn_nameiop = CREATE;
                   2098:        nd.ni_cnd.cn_flags = LOCKPARENT;
1.23      fvdl     2099:        error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos,
1.99    ! christos 2100:                &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl     2101:        if (dirp) {
                   2102:                if (v3)
1.99    ! christos 2103:                        dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, lwp);
1.23      fvdl     2104:                else {
                   2105:                        vrele(dirp);
                   2106:                        dirp = (struct vnode *)0;
                   2107:                }
                   2108:        }
1.22      christos 2109:        if (error)
1.23      fvdl     2110:                goto out1;
                   2111:        xp = nd.ni_vp;
                   2112:        if (xp != NULL) {
                   2113:                error = EEXIST;
1.1       cgd      2114:                goto out;
1.23      fvdl     2115:        }
                   2116:        xp = nd.ni_dvp;
                   2117:        if (vp->v_mount != xp->v_mount)
                   2118:                error = EXDEV;
                   2119: out:
                   2120:        if (!error) {
                   2121:                nqsrv_getl(vp, ND_WRITE);
                   2122:                nqsrv_getl(xp, ND_WRITE);
                   2123:                error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
                   2124:        } else {
1.15      mycroft  2125:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1       cgd      2126:                if (nd.ni_dvp == nd.ni_vp)
                   2127:                        vrele(nd.ni_dvp);
                   2128:                else
                   2129:                        vput(nd.ni_dvp);
1.23      fvdl     2130:                if (nd.ni_vp)
                   2131:                        vrele(nd.ni_vp);
                   2132:        }
                   2133: out1:
                   2134:        if (v3)
1.99    ! christos 2135:                getret = VOP_GETATTR(vp, &at, cred, lwp);
1.23      fvdl     2136:        if (dirp) {
1.99    ! christos 2137:                diraft_ret = VOP_GETATTR(dirp, &diraft, cred, lwp);
1.23      fvdl     2138:                vrele(dirp);
1.1       cgd      2139:        }
                   2140:        vrele(vp);
1.23      fvdl     2141:        nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
                   2142:        if (v3) {
                   2143:                nfsm_srvpostop_attr(getret, &at);
                   2144:                nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1.82      hannken  2145:                vn_finished_write(mp, 0);
1.23      fvdl     2146:                return (0);
                   2147:        }
1.82      hannken  2148:        vn_finished_write(mp, 0);
1.1       cgd      2149:        nfsm_srvdone;
                   2150: }
                   2151:
                   2152: /*
                   2153:  * nfs symbolic link service
                   2154:  */
1.22      christos 2155: int
1.99    ! christos 2156: nfsrv_symlink(nfsd, slp, lwp, mrq)
1.23      fvdl     2157:        struct nfsrv_descript *nfsd;
                   2158:        struct nfssvc_sock *slp;
1.99    ! christos 2159:        struct lwp *lwp;
1.23      fvdl     2160:        struct mbuf **mrq;
1.1       cgd      2161: {
1.23      fvdl     2162:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                   2163:        struct mbuf *nam = nfsd->nd_nam;
                   2164:        caddr_t dpos = nfsd->nd_dpos;
                   2165:        struct ucred *cred = &nfsd->nd_cr;
                   2166:        struct vattr va, dirfor, diraft;
1.1       cgd      2167:        struct nameidata nd;
1.54      augustss 2168:        u_int32_t *tl;
                   2169:        int32_t t1;
1.1       cgd      2170:        struct nfsv2_sattr *sp;
1.23      fvdl     2171:        char *bpos, *pathcp = NULL, *cp2;
1.1       cgd      2172:        struct uio io;
                   2173:        struct iovec iv;
1.68      yamt     2174:        int error = 0, cache, dirfor_ret = 1, diraft_ret = 1;
                   2175:        uint32_t len, len2;
1.23      fvdl     2176:        int v3 = (nfsd->nd_flag & ND_NFSV3);
1.67      matt     2177:        struct mbuf *mb, *mreq;
1.23      fvdl     2178:        struct vnode *dirp = (struct vnode *)0;
                   2179:        nfsfh_t nfh;
1.1       cgd      2180:        fhandle_t *fhp;
1.15      mycroft  2181:        u_quad_t frev;
1.82      hannken  2182:        struct mount *mp = NULL;
1.1       cgd      2183:
1.23      fvdl     2184:        nd.ni_cnd.cn_nameiop = 0;
1.1       cgd      2185:        fhp = &nfh.fh_generic;
                   2186:        nfsm_srvmtofh(fhp);
1.82      hannken  2187:        if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
                   2188:                return (ESTALE);
                   2189:        vn_start_write(NULL, &mp, V_WAIT);
1.23      fvdl     2190:        nfsm_srvnamesiz(len);
1.15      mycroft  2191:        nd.ni_cnd.cn_cred = cred;
                   2192:        nd.ni_cnd.cn_nameiop = CREATE;
1.61      chs      2193:        nd.ni_cnd.cn_flags = LOCKPARENT;
1.23      fvdl     2194:        error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1.99    ! christos 2195:                &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl     2196:        if (dirp) {
                   2197:                if (v3)
1.99    ! christos 2198:                        dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, lwp);
1.23      fvdl     2199:                else {
                   2200:                        vrele(dirp);
                   2201:                        dirp = (struct vnode *)0;
                   2202:                }
                   2203:        }
1.22      christos 2204:        if (error)
1.1       cgd      2205:                goto out;
1.23      fvdl     2206:        VATTR_NULL(&va);
1.97      jmmv     2207:        va.va_type = VLNK;
1.68      yamt     2208:        if (v3) {
1.92      yamt     2209:                va.va_mode = 0;
1.23      fvdl     2210:                nfsm_srvsattr(&va);
1.68      yamt     2211:                nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED);
                   2212:                len2 = fxdr_unsigned(uint32_t, *tl);
                   2213:                if (len2 > PATH_MAX) {
                   2214:                        /* XXX should check _PC_NO_TRUNC */
                   2215:                        error = ENAMETOOLONG;
                   2216:                        goto abortop;
                   2217:                }
                   2218:        }
                   2219:        else {
                   2220:                /* NFSv2 */
                   2221:                nfsm_strsiz(len2, NFS_MAXPATHLEN);
                   2222:        }
1.56      thorpej  2223:        pathcp = malloc(len2 + 1, M_TEMP, M_WAITOK);
1.1       cgd      2224:        iv.iov_base = pathcp;
                   2225:        iv.iov_len = len2;
                   2226:        io.uio_resid = len2;
                   2227:        io.uio_offset = 0;
                   2228:        io.uio_iov = &iv;
                   2229:        io.uio_iovcnt = 1;
                   2230:        io.uio_segflg = UIO_SYSSPACE;
                   2231:        io.uio_rw = UIO_READ;
1.99    ! christos 2232:        io.uio_lwp = NULL;
1.1       cgd      2233:        nfsm_mtouio(&io, len2);
1.23      fvdl     2234:        if (!v3) {
                   2235:                nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
                   2236:                va.va_mode = fxdr_unsigned(u_int16_t, sp->sa_mode);
                   2237:        }
1.1       cgd      2238:        *(pathcp + len2) = '\0';
                   2239:        if (nd.ni_vp) {
1.68      yamt     2240:                error = EEXIST;
                   2241: abortop:
1.15      mycroft  2242:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1       cgd      2243:                if (nd.ni_dvp == nd.ni_vp)
                   2244:                        vrele(nd.ni_dvp);
                   2245:                else
                   2246:                        vput(nd.ni_dvp);
1.68      yamt     2247:                if (nd.ni_vp)
                   2248:                        vrele(nd.ni_vp);
1.1       cgd      2249:                goto out;
                   2250:        }
1.23      fvdl     2251:        nqsrv_getl(nd.ni_dvp, ND_WRITE);
                   2252:        error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, pathcp);
1.61      chs      2253:        if (!error) {
1.23      fvdl     2254:            if (v3) {
1.60      assar    2255:                memset((caddr_t)fhp, 0, sizeof(nfh));
1.88      christos 2256:                fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsidx;
1.60      assar    2257:                error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
                   2258:                if (!error)
1.99    ! christos 2259:                    error = VOP_GETATTR(nd.ni_vp, &va, cred, lwp);
1.60      assar    2260:                vput(nd.ni_vp);
                   2261:            } else {
                   2262:                vput(nd.ni_vp);
                   2263:            }
1.23      fvdl     2264:        }
1.1       cgd      2265: out:
                   2266:        if (pathcp)
1.56      thorpej  2267:                free(pathcp, M_TEMP);
1.23      fvdl     2268:        if (dirp) {
1.99    ! christos 2269:                diraft_ret = VOP_GETATTR(dirp, &diraft, cred, lwp);
1.23      fvdl     2270:                vrele(dirp);
                   2271:        }
                   2272:        nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
                   2273:        if (v3) {
                   2274:                if (!error) {
                   2275:                        nfsm_srvpostop_fh(fhp);
                   2276:                        nfsm_srvpostop_attr(0, &va);
                   2277:                }
                   2278:                nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
                   2279:        }
1.82      hannken  2280:        vn_finished_write(mp, 0);
1.23      fvdl     2281:        return (0);
1.1       cgd      2282: nfsmout:
1.23      fvdl     2283:        if (dirp)
                   2284:                vrele(dirp);
1.15      mycroft  2285:        VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1       cgd      2286:        if (nd.ni_dvp == nd.ni_vp)
                   2287:                vrele(nd.ni_dvp);
                   2288:        else
                   2289:                vput(nd.ni_dvp);
                   2290:        if (nd.ni_vp)
                   2291:                vrele(nd.ni_vp);
                   2292:        if (pathcp)
1.56      thorpej  2293:                free(pathcp, M_TEMP);
1.82      hannken  2294:        vn_finished_write(mp, 0);
1.1       cgd      2295:        return (error);
                   2296: }
                   2297:
                   2298: /*
                   2299:  * nfs mkdir service
                   2300:  */
1.22      christos 2301: int
1.99    ! christos 2302: nfsrv_mkdir(nfsd, slp, lwp, mrq)
1.23      fvdl     2303:        struct nfsrv_descript *nfsd;
                   2304:        struct nfssvc_sock *slp;
1.99    ! christos 2305:        struct lwp *lwp;
1.23      fvdl     2306:        struct mbuf **mrq;
1.1       cgd      2307: {
1.23      fvdl     2308:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                   2309:        struct mbuf *nam = nfsd->nd_nam;
                   2310:        caddr_t dpos = nfsd->nd_dpos;
                   2311:        struct ucred *cred = &nfsd->nd_cr;
                   2312:        struct vattr va, dirfor, diraft;
1.54      augustss 2313:        struct nfs_fattr *fp;
1.1       cgd      2314:        struct nameidata nd;
1.54      augustss 2315:        caddr_t cp;
                   2316:        u_int32_t *tl;
                   2317:        int32_t t1;
1.1       cgd      2318:        caddr_t bpos;
1.23      fvdl     2319:        int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
                   2320:        int v3 = (nfsd->nd_flag & ND_NFSV3);
1.1       cgd      2321:        char *cp2;
1.67      matt     2322:        struct mbuf *mb, *mreq;
1.23      fvdl     2323:        struct vnode *vp, *dirp = (struct vnode *)0;
                   2324:        nfsfh_t nfh;
1.1       cgd      2325:        fhandle_t *fhp;
1.15      mycroft  2326:        u_quad_t frev;
1.82      hannken  2327:        struct mount *mp = NULL;
1.1       cgd      2328:
                   2329:        fhp = &nfh.fh_generic;
                   2330:        nfsm_srvmtofh(fhp);
1.82      hannken  2331:        if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
                   2332:                return (ESTALE);
                   2333:        vn_start_write(NULL, &mp, V_WAIT);
1.23      fvdl     2334:        nfsm_srvnamesiz(len);
1.15      mycroft  2335:        nd.ni_cnd.cn_cred = cred;
                   2336:        nd.ni_cnd.cn_nameiop = CREATE;
                   2337:        nd.ni_cnd.cn_flags = LOCKPARENT;
1.23      fvdl     2338:        error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1.99    ! christos 2339:                &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl     2340:        if (dirp) {
                   2341:                if (v3)
1.99    ! christos 2342:                        dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, lwp);
1.23      fvdl     2343:                else {
                   2344:                        vrele(dirp);
                   2345:                        dirp = (struct vnode *)0;
                   2346:                }
                   2347:        }
                   2348:        if (error) {
                   2349:                nfsm_reply(NFSX_WCCDATA(v3));
                   2350:                nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
                   2351:                if (dirp)
                   2352:                        vrele(dirp);
1.82      hannken  2353:                vn_finished_write(mp, 0);
1.23      fvdl     2354:                return (0);
                   2355:        }
1.18      mycroft  2356:        VATTR_NULL(&va);
1.23      fvdl     2357:        if (v3) {
1.92      yamt     2358:                va.va_mode = 0;
1.23      fvdl     2359:                nfsm_srvsattr(&va);
                   2360:        } else {
                   2361:                nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
                   2362:                va.va_mode = nfstov_mode(*tl++);
                   2363:        }
1.18      mycroft  2364:        va.va_type = VDIR;
1.1       cgd      2365:        vp = nd.ni_vp;
                   2366:        if (vp != NULL) {
1.15      mycroft  2367:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1       cgd      2368:                if (nd.ni_dvp == vp)
                   2369:                        vrele(nd.ni_dvp);
                   2370:                else
                   2371:                        vput(nd.ni_dvp);
                   2372:                vrele(vp);
                   2373:                error = EEXIST;
1.23      fvdl     2374:                goto out;
1.1       cgd      2375:        }
1.23      fvdl     2376:        nqsrv_getl(nd.ni_dvp, ND_WRITE);
                   2377:        error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
                   2378:        if (!error) {
                   2379:                vp = nd.ni_vp;
1.44      perry    2380:                memset((caddr_t)fhp, 0, sizeof(nfh));
1.88      christos 2381:                fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsidx;
1.23      fvdl     2382:                error = VFS_VPTOFH(vp, &fhp->fh_fid);
                   2383:                if (!error)
1.99    ! christos 2384:                        error = VOP_GETATTR(vp, &va, cred, lwp);
1.1       cgd      2385:                vput(vp);
                   2386:        }
1.23      fvdl     2387: out:
                   2388:        if (dirp) {
1.99    ! christos 2389:                diraft_ret = VOP_GETATTR(dirp, &diraft, cred, lwp);
1.23      fvdl     2390:                vrele(dirp);
                   2391:        }
                   2392:        nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
                   2393:        if (v3) {
                   2394:                if (!error) {
                   2395:                        nfsm_srvpostop_fh(fhp);
                   2396:                        nfsm_srvpostop_attr(0, &va);
                   2397:                }
                   2398:                nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
                   2399:        } else {
                   2400:                nfsm_srvfhtom(fhp, v3);
                   2401:                nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
                   2402:                nfsm_srvfillattr(&va, fp);
                   2403:        }
1.82      hannken  2404:        vn_finished_write(mp, 0);
1.23      fvdl     2405:        return (0);
1.1       cgd      2406: nfsmout:
1.23      fvdl     2407:        if (dirp)
                   2408:                vrele(dirp);
1.15      mycroft  2409:        VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1       cgd      2410:        if (nd.ni_dvp == nd.ni_vp)
                   2411:                vrele(nd.ni_dvp);
                   2412:        else
                   2413:                vput(nd.ni_dvp);
                   2414:        if (nd.ni_vp)
                   2415:                vrele(nd.ni_vp);
1.82      hannken  2416:        vn_finished_write(mp, 0);
1.1       cgd      2417:        return (error);
                   2418: }
                   2419:
                   2420: /*
                   2421:  * nfs rmdir service
                   2422:  */
1.22      christos 2423: int
1.99    ! christos 2424: nfsrv_rmdir(nfsd, slp, lwp, mrq)
1.23      fvdl     2425:        struct nfsrv_descript *nfsd;
                   2426:        struct nfssvc_sock *slp;
1.99    ! christos 2427:        struct lwp *lwp;
1.23      fvdl     2428:        struct mbuf **mrq;
1.1       cgd      2429: {
1.23      fvdl     2430:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                   2431:        struct mbuf *nam = nfsd->nd_nam;
                   2432:        caddr_t dpos = nfsd->nd_dpos;
                   2433:        struct ucred *cred = &nfsd->nd_cr;
1.54      augustss 2434:        u_int32_t *tl;
                   2435:        int32_t t1;
1.1       cgd      2436:        caddr_t bpos;
1.23      fvdl     2437:        int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
                   2438:        int v3 = (nfsd->nd_flag & ND_NFSV3);
1.1       cgd      2439:        char *cp2;
                   2440:        struct mbuf *mb, *mreq;
1.23      fvdl     2441:        struct vnode *vp, *dirp = (struct vnode *)0;
                   2442:        struct vattr dirfor, diraft;
                   2443:        nfsfh_t nfh;
1.1       cgd      2444:        fhandle_t *fhp;
                   2445:        struct nameidata nd;
1.15      mycroft  2446:        u_quad_t frev;
1.82      hannken  2447:        struct mount *mp = NULL;
1.1       cgd      2448:
                   2449:        fhp = &nfh.fh_generic;
                   2450:        nfsm_srvmtofh(fhp);
1.82      hannken  2451:        if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
                   2452:                return (ESTALE);
                   2453:        vn_start_write(NULL, &mp, V_WAIT);
1.23      fvdl     2454:        nfsm_srvnamesiz(len);
1.15      mycroft  2455:        nd.ni_cnd.cn_cred = cred;
                   2456:        nd.ni_cnd.cn_nameiop = DELETE;
                   2457:        nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1.23      fvdl     2458:        error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1.99    ! christos 2459:                &dirp, lwp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl     2460:        if (dirp) {
                   2461:                if (v3)
1.99    ! christos 2462:                        dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, lwp);
1.23      fvdl     2463:                else {
                   2464:                        vrele(dirp);
                   2465:                        dirp = (struct vnode *)0;
                   2466:                }
                   2467:        }
                   2468:        if (error) {
                   2469:                nfsm_reply(NFSX_WCCDATA(v3));
                   2470:                nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
                   2471:                if (dirp)
                   2472:                        vrele(dirp);
1.82      hannken  2473:                vn_finished_write(mp, 0);
1.23      fvdl     2474:                return (0);
                   2475:        }
1.1       cgd      2476:        vp = nd.ni_vp;
                   2477:        if (vp->v_type != VDIR) {
                   2478:                error = ENOTDIR;
                   2479:                goto out;
                   2480:        }
                   2481:        /*
                   2482:         * No rmdir "." please.
                   2483:         */
                   2484:        if (nd.ni_dvp == vp) {
                   2485:                error = EINVAL;
                   2486:                goto out;
                   2487:        }
                   2488:        /*
                   2489:         * The root of a mounted filesystem cannot be deleted.
                   2490:         */
                   2491:        if (vp->v_flag & VROOT)
                   2492:                error = EBUSY;
                   2493: out:
                   2494:        if (!error) {
1.23      fvdl     2495:                nqsrv_getl(nd.ni_dvp, ND_WRITE);
                   2496:                nqsrv_getl(vp, ND_WRITE);
1.15      mycroft  2497:                error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1.1       cgd      2498:        } else {
1.15      mycroft  2499:                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1       cgd      2500:                if (nd.ni_dvp == nd.ni_vp)
                   2501:                        vrele(nd.ni_dvp);
                   2502:                else
                   2503:                        vput(nd.ni_dvp);
                   2504:                vput(vp);
                   2505:        }
1.23      fvdl     2506:        if (dirp) {
1.99    ! christos 2507:                diraft_ret = VOP_GETATTR(dirp, &diraft, cred, lwp);
1.23      fvdl     2508:                vrele(dirp);
                   2509:        }
                   2510:        nfsm_reply(NFSX_WCCDATA(v3));
                   2511:        if (v3) {
                   2512:                nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1.82      hannken  2513:                vn_finished_write(mp, 0);
1.23      fvdl     2514:                return (0);
                   2515:        }
1.82      hannken  2516:        vn_finished_write(mp, 0);
1.1       cgd      2517:        nfsm_srvdone;
                   2518: }
                   2519:
                   2520: /*
                   2521:  * nfs readdir service
                   2522:  * - mallocs what it thinks is enough to read
1.98      yamt     2523:  *     count rounded up to a multiple of NFS_SRVDIRBLKSIZ <= NFS_MAXREADDIR
1.1       cgd      2524:  * - calls VOP_READDIR()
                   2525:  * - loops around building the reply
                   2526:  *     if the output generated exceeds count break out of loop
                   2527:  *     The nfsm_clget macro is used here so that the reply will be packed
                   2528:  *     tightly in mbuf clusters.
                   2529:  * - it only knows that it has encountered eof when the VOP_READDIR()
                   2530:  *     reads nothing
                   2531:  * - as such one readdir rpc will return eof false although you are there
                   2532:  *     and then the next will return eof
1.11      ws       2533:  * - it trims out records with d_fileno == 0
1.1       cgd      2534:  *     this doesn't matter for Unix clients, but they might confuse clients
                   2535:  *     for other os'.
1.25      jtk      2536:  * - it trims out records with d_type == DT_WHT
                   2537:  *     these cannot be seen through NFS (unless we extend the protocol)
1.1       cgd      2538:  * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
                   2539:  *     than requested, but this may not apply to all filesystems. For
                   2540:  *     example, client NFS does not { although it is never remote mounted
                   2541:  *     anyhow }
1.23      fvdl     2542:  *     The alternate call nfsrv_readdirplus() does lookups as well.
1.1       cgd      2543:  * PS: The NFS protocol spec. does not clarify what the "count" byte
                   2544:  *     argument is a count of.. just name strings and file id's or the
                   2545:  *     entire reply rpc or ...
                   2546:  *     I tried just file name and id sizes and it confused the Sun client,
                   2547:  *     so I am using the full rpc size now. The "paranoia.." comment refers
                   2548:  *     to including the status longwords that are not a part of the dir.
                   2549:  *     "entry" structures, but are in the rpc.
                   2550:  */
1.98      yamt     2551:
                   2552: #define        NFS_SRVDIRBLKSIZ        1024
                   2553:
1.15      mycroft  2554: struct flrep {
1.23      fvdl     2555:        nfsuint64 fl_off;
                   2556:        u_int32_t fl_postopok;
                   2557:        u_int32_t fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)];
                   2558:        u_int32_t fl_fhok;
                   2559:        u_int32_t fl_fhsize;
                   2560:        u_int32_t fl_nfh[NFSX_V3FH / sizeof (u_int32_t)];
1.15      mycroft  2561: };
                   2562:
1.22      christos 2563: int
1.99    ! christos 2564: nfsrv_readdir(nfsd, slp, lwp, mrq)
1.23      fvdl     2565:        struct nfsrv_descript *nfsd;
                   2566:        struct nfssvc_sock *slp;
1.99    ! christos 2567:        struct lwp *lwp;
1.23      fvdl     2568:        struct mbuf **mrq;
1.1       cgd      2569: {
1.23      fvdl     2570:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                   2571:        struct mbuf *nam = nfsd->nd_nam;
                   2572:        caddr_t dpos = nfsd->nd_dpos;
                   2573:        struct ucred *cred = &nfsd->nd_cr;
1.54      augustss 2574:        char *bp, *be;
                   2575:        struct mbuf *mp;
                   2576:        struct dirent *dp;
                   2577:        caddr_t cp;
                   2578:        u_int32_t *tl;
                   2579:        int32_t t1;
1.1       cgd      2580:        caddr_t bpos;
1.67      matt     2581:        struct mbuf *mb, *mreq, *mp2;
1.15      mycroft  2582:        char *cpos, *cend, *cp2, *rbuf;
1.1       cgd      2583:        struct vnode *vp;
1.23      fvdl     2584:        struct vattr at;
                   2585:        nfsfh_t nfh;
1.1       cgd      2586:        fhandle_t *fhp;
                   2587:        struct uio io;
                   2588:        struct iovec iv;
1.23      fvdl     2589:        int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
                   2590:        int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies;
                   2591:        int v3 = (nfsd->nd_flag & ND_NFSV3);
                   2592:        u_quad_t frev, off, toff, verf;
1.38      fvdl     2593:        off_t *cookies = NULL, *cookiep;
                   2594:        nfsuint64 jar;
1.15      mycroft  2595:
1.1       cgd      2596:        fhp = &nfh.fh_generic;
                   2597:        nfsm_srvmtofh(fhp);
1.23      fvdl     2598:        if (v3) {
                   2599:                nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1.48      fair     2600:                toff = fxdr_hyper(tl);
1.23      fvdl     2601:                tl += 2;
1.48      fair     2602:                verf = fxdr_hyper(tl);
1.23      fvdl     2603:                tl += 2;
                   2604:        } else {
                   2605:                nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
                   2606:                toff = fxdr_unsigned(u_quad_t, *tl++);
                   2607:        }
                   2608:        off = toff;
1.1       cgd      2609:        cnt = fxdr_unsigned(int, *tl);
1.98      yamt     2610:        siz = ((cnt + NFS_SRVDIRBLKSIZ - 1) & ~(NFS_SRVDIRBLKSIZ - 1));
1.23      fvdl     2611:        xfer = NFS_SRVMAXDATA(nfsd);
                   2612:        if (siz > xfer)
                   2613:                siz = xfer;
1.1       cgd      2614:        fullsiz = siz;
1.23      fvdl     2615:        error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.78      thorpej  2616:                 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.39      fvdl     2617:        if (!error && vp->v_type != VDIR) {
                   2618:                error = ENOTDIR;
                   2619:                vput(vp);
                   2620:        }
1.23      fvdl     2621:        if (error) {
                   2622:                nfsm_reply(NFSX_UNSIGNED);
                   2623:                nfsm_srvpostop_attr(getret, &at);
                   2624:                return (0);
                   2625:        }
                   2626:        nqsrv_getl(vp, ND_READ);
                   2627:        if (v3) {
1.99    ! christos 2628:                error = getret = VOP_GETATTR(vp, &at, cred, lwp);
1.23      fvdl     2629: #ifdef NFS3_STRICTVERF
                   2630:                /*
                   2631:                 * XXX This check is too strict for Solaris 2.5 clients.
                   2632:                 */
                   2633:                if (!error && toff && verf != at.va_filerev)
                   2634:                        error = NFSERR_BAD_COOKIE;
                   2635: #endif
                   2636:        }
                   2637:        if (!error)
1.99    ! christos 2638:                error = nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 0);
1.22      christos 2639:        if (error) {
1.1       cgd      2640:                vput(vp);
1.23      fvdl     2641:                nfsm_reply(NFSX_POSTOPATTR(v3));
                   2642:                nfsm_srvpostop_attr(getret, &at);
                   2643:                return (0);
1.1       cgd      2644:        }
1.42      fvdl     2645:        VOP_UNLOCK(vp, 0);
1.56      thorpej  2646:        rbuf = malloc(siz, M_TEMP, M_WAITOK);
1.1       cgd      2647: again:
                   2648:        iv.iov_base = rbuf;
                   2649:        iv.iov_len = fullsiz;
                   2650:        io.uio_iov = &iv;
                   2651:        io.uio_iovcnt = 1;
1.15      mycroft  2652:        io.uio_offset = (off_t)off;
1.1       cgd      2653:        io.uio_resid = fullsiz;
                   2654:        io.uio_segflg = UIO_SYSSPACE;
                   2655:        io.uio_rw = UIO_READ;
1.99    ! christos 2656:        io.uio_lwp = NULL;
1.23      fvdl     2657:        eofflag = 0;
1.42      fvdl     2658:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.23      fvdl     2659:
1.42      fvdl     2660:        error = VOP_READDIR(vp, &io, cred, &eofflag, &cookies, &ncookies);
1.23      fvdl     2661:
1.15      mycroft  2662:        off = (off_t)io.uio_offset;
1.23      fvdl     2663:        if (!cookies && !error)
                   2664:                error = NFSERR_PERM;
                   2665:        if (v3) {
1.99    ! christos 2666:                getret = VOP_GETATTR(vp, &at, cred, lwp);
1.23      fvdl     2667:                if (!error)
                   2668:                        error = getret;
                   2669:        }
                   2670:
1.42      fvdl     2671:        VOP_UNLOCK(vp, 0);
1.1       cgd      2672:        if (error) {
                   2673:                vrele(vp);
1.56      thorpej  2674:                free((caddr_t)rbuf, M_TEMP);
1.23      fvdl     2675:                if (cookies)
                   2676:                        free((caddr_t)cookies, M_TEMP);
                   2677:                nfsm_reply(NFSX_POSTOPATTR(v3));
                   2678:                nfsm_srvpostop_attr(getret, &at);
                   2679:                return (0);
1.1       cgd      2680:        }
                   2681:        if (io.uio_resid) {
                   2682:                siz -= io.uio_resid;
                   2683:
                   2684:                /*
                   2685:                 * If nothing read, return eof
                   2686:                 * rpc reply
                   2687:                 */
                   2688:                if (siz == 0) {
                   2689:                        vrele(vp);
1.23      fvdl     2690:                        nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
                   2691:                                2 * NFSX_UNSIGNED);
                   2692:                        if (v3) {
                   2693:                                nfsm_srvpostop_attr(getret, &at);
                   2694:                                nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1.48      fair     2695:                                txdr_hyper(at.va_filerev, tl);
1.23      fvdl     2696:                                tl += 2;
                   2697:                        } else
                   2698:                                nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1.1       cgd      2699:                        *tl++ = nfs_false;
                   2700:                        *tl = nfs_true;
1.56      thorpej  2701:                        free((caddr_t)rbuf, M_TEMP);
                   2702:                        free((caddr_t)cookies, M_TEMP);
1.1       cgd      2703:                        return (0);
                   2704:                }
                   2705:        }
                   2706:
                   2707:        /*
                   2708:         * Check for degenerate cases of nothing useful read.
                   2709:         * If so go try again
                   2710:         */
1.8       ws       2711:        cpos = rbuf;
1.1       cgd      2712:        cend = rbuf + siz;
1.23      fvdl     2713:        dp = (struct dirent *)cpos;
                   2714:        cookiep = cookies;
                   2715:
1.28      fvdl     2716:        while (cpos < cend && ncookies > 0 &&
                   2717:                (dp->d_fileno == 0 || dp->d_type == DT_WHT)) {
1.23      fvdl     2718:                cpos += dp->d_reclen;
1.11      ws       2719:                dp = (struct dirent *)cpos;
1.23      fvdl     2720:                cookiep++;
                   2721:                ncookies--;
1.1       cgd      2722:        }
1.23      fvdl     2723:        if (cpos >= cend || ncookies == 0) {
                   2724:                toff = off;
1.1       cgd      2725:                siz = fullsiz;
                   2726:                goto again;
                   2727:        }
                   2728:
1.23      fvdl     2729:        len = 3 * NFSX_UNSIGNED;        /* paranoia, probably can be 0 */
                   2730:        nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
                   2731:        if (v3) {
                   2732:                nfsm_srvpostop_attr(getret, &at);
                   2733:                nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1.48      fair     2734:                txdr_hyper(at.va_filerev, tl);
1.23      fvdl     2735:        }
1.15      mycroft  2736:        mp = mp2 = mb;
                   2737:        bp = bpos;
                   2738:        be = bp + M_TRAILINGSPACE(mp);
                   2739:
                   2740:        /* Loop through the records and build reply */
1.23      fvdl     2741:        while (cpos < cend && ncookies > 0) {
1.25      jtk      2742:                if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
1.15      mycroft  2743:                        nlen = dp->d_namlen;
                   2744:                        rem = nfsm_rndup(nlen)-nlen;
1.23      fvdl     2745:                        len += (4 * NFSX_UNSIGNED + nlen + rem);
                   2746:                        if (v3)
                   2747:                                len += 2 * NFSX_UNSIGNED;
1.15      mycroft  2748:                        if (len > cnt) {
                   2749:                                eofflag = 0;
                   2750:                                break;
                   2751:                        }
                   2752:                        /*
                   2753:                         * Build the directory record xdr from
                   2754:                         * the dirent entry.
                   2755:                         */
                   2756:                        nfsm_clget;
                   2757:                        *tl = nfs_true;
                   2758:                        bp += NFSX_UNSIGNED;
1.23      fvdl     2759:                        if (v3) {
                   2760:                                nfsm_clget;
1.96      yamt     2761:                                *tl = txdr_unsigned(dp->d_fileno >> 32);
1.23      fvdl     2762:                                bp += NFSX_UNSIGNED;
                   2763:                        }
1.15      mycroft  2764:                        nfsm_clget;
                   2765:                        *tl = txdr_unsigned(dp->d_fileno);
                   2766:                        bp += NFSX_UNSIGNED;
                   2767:                        nfsm_clget;
                   2768:                        *tl = txdr_unsigned(nlen);
                   2769:                        bp += NFSX_UNSIGNED;
1.94      perry    2770:
1.15      mycroft  2771:                        /* And loop around copying the name */
                   2772:                        xfer = nlen;
                   2773:                        cp = dp->d_name;
                   2774:                        while (xfer > 0) {
                   2775:                                nfsm_clget;
                   2776:                                if ((bp+xfer) > be)
                   2777:                                        tsiz = be-bp;
                   2778:                                else
                   2779:                                        tsiz = xfer;
1.44      perry    2780:                                memcpy(bp, cp, tsiz);
1.15      mycroft  2781:                                bp += tsiz;
                   2782:                                xfer -= tsiz;
                   2783:                                if (xfer > 0)
                   2784:                                        cp += tsiz;
                   2785:                        }
1.23      fvdl     2786:                        /* And null pad to an int32_t boundary */
1.15      mycroft  2787:                        for (i = 0; i < rem; i++)
                   2788:                                *bp++ = '\0';
                   2789:                        nfsm_clget;
1.94      perry    2790:
1.15      mycroft  2791:                        /* Finish off the record */
1.48      fair     2792:                        txdr_hyper(*cookiep, &jar);
1.23      fvdl     2793:                        if (v3) {
1.38      fvdl     2794:                                *tl = jar.nfsuquad[0];
1.23      fvdl     2795:                                bp += NFSX_UNSIGNED;
                   2796:                                nfsm_clget;
                   2797:                        }
1.38      fvdl     2798:                        *tl = jar.nfsuquad[1];
1.15      mycroft  2799:                        bp += NFSX_UNSIGNED;
                   2800:                }
                   2801:                cpos += dp->d_reclen;
                   2802:                dp = (struct dirent *)cpos;
1.23      fvdl     2803:                cookiep++;
                   2804:                ncookies--;
1.15      mycroft  2805:        }
1.1       cgd      2806:        vrele(vp);
1.15      mycroft  2807:        nfsm_clget;
                   2808:        *tl = nfs_false;
                   2809:        bp += NFSX_UNSIGNED;
                   2810:        nfsm_clget;
                   2811:        if (eofflag)
                   2812:                *tl = nfs_true;
                   2813:        else
                   2814:                *tl = nfs_false;
                   2815:        bp += NFSX_UNSIGNED;
                   2816:        if (mp != mb) {
                   2817:                if (bp < be)
                   2818:                        mp->m_len = bp - mtod(mp, caddr_t);
                   2819:        } else
                   2820:                mp->m_len += bp - bpos;
1.56      thorpej  2821:        free((caddr_t)rbuf, M_TEMP);
                   2822:        free((caddr_t)cookies, M_TEMP);
1.15      mycroft  2823:        nfsm_srvdone;
                   2824: }
                   2825:
1.22      christos 2826: int
1.99    ! christos 2827: nfsrv_readdirplus(nfsd, slp, lwp, mrq)
1.23      fvdl     2828:        struct nfsrv_descript *nfsd;
                   2829:        struct nfssvc_sock *slp;
1.99    ! christos 2830:        struct lwp *lwp;
1.23      fvdl     2831:        struct mbuf **mrq;
1.15      mycroft  2832: {
1.23      fvdl     2833:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                   2834:        struct mbuf *nam = nfsd->nd_nam;
                   2835:        caddr_t dpos = nfsd->nd_dpos;
                   2836:        struct ucred *cred = &nfsd->nd_cr;
1.54      augustss 2837:        char *bp, *be;
                   2838:        struct mbuf *mp;
                   2839:        struct dirent *dp;
                   2840:        caddr_t cp;
                   2841:        u_int32_t *tl;
                   2842:        int32_t t1;
1.15      mycroft  2843:        caddr_t bpos;
1.67      matt     2844:        struct mbuf *mb, *mreq, *mp2;
1.15      mycroft  2845:        char *cpos, *cend, *cp2, *rbuf;
                   2846:        struct vnode *vp, *nvp;
                   2847:        struct flrep fl;
1.23      fvdl     2848:        nfsfh_t nfh;
                   2849:        fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
1.15      mycroft  2850:        struct uio io;
                   2851:        struct iovec iv;
1.23      fvdl     2852:        struct vattr va, at, *vap = &va;
                   2853:        struct nfs_fattr *fp;
                   2854:        int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
                   2855:        int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies;
                   2856:        u_quad_t frev, off, toff, verf;
1.38      fvdl     2857:        off_t *cookies = NULL, *cookiep;
1.15      mycroft  2858:
                   2859:        fhp = &nfh.fh_generic;
                   2860:        nfsm_srvmtofh(fhp);
1.23      fvdl     2861:        nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
1.48      fair     2862:        toff = fxdr_hyper(tl);
1.23      fvdl     2863:        tl += 2;
1.48      fair     2864:        verf = fxdr_hyper(tl);
1.23      fvdl     2865:        tl += 2;
                   2866:        siz = fxdr_unsigned(int, *tl++);
                   2867:        cnt = fxdr_unsigned(int, *tl);
                   2868:        off = toff;
1.98      yamt     2869:        siz = ((siz + NFS_SRVDIRBLKSIZ - 1) & ~(NFS_SRVDIRBLKSIZ - 1));
1.23      fvdl     2870:        xfer = NFS_SRVMAXDATA(nfsd);
                   2871:        if (siz > xfer)
                   2872:                siz = xfer;
1.15      mycroft  2873:        fullsiz = siz;
1.23      fvdl     2874:        error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.78      thorpej  2875:                 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.39      fvdl     2876:        if (!error && vp->v_type != VDIR) {
                   2877:                error = ENOTDIR;
                   2878:                vput(vp);
                   2879:        }
1.23      fvdl     2880:        if (error) {
                   2881:                nfsm_reply(NFSX_UNSIGNED);
                   2882:                nfsm_srvpostop_attr(getret, &at);
                   2883:                return (0);
                   2884:        }
1.99    ! christos 2885:        error = getret = VOP_GETATTR(vp, &at, cred, lwp);
1.23      fvdl     2886: #ifdef NFS3_STRICTVERF
                   2887:        /*
                   2888:         * XXX This check is too strict for Solaris 2.5 clients.
                   2889:         */
                   2890:        if (!error && toff && verf != at.va_filerev)
                   2891:                error = NFSERR_BAD_COOKIE;
                   2892: #endif
                   2893:        if (!error) {
                   2894:                nqsrv_getl(vp, ND_READ);
1.99    ! christos 2895:                error = nfsrv_access(vp, VEXEC, cred, rdonly, lwp, 0);
1.23      fvdl     2896:        }
1.22      christos 2897:        if (error) {
1.15      mycroft  2898:                vput(vp);
1.23      fvdl     2899:                nfsm_reply(NFSX_V3POSTOPATTR);
                   2900:                nfsm_srvpostop_attr(getret, &at);
                   2901:                return (0);
1.15      mycroft  2902:        }
1.42      fvdl     2903:        VOP_UNLOCK(vp, 0);
1.23      fvdl     2904:
1.56      thorpej  2905:        rbuf = malloc(siz, M_TEMP, M_WAITOK);
1.15      mycroft  2906: again:
                   2907:        iv.iov_base = rbuf;
                   2908:        iv.iov_len = fullsiz;
                   2909:        io.uio_iov = &iv;
                   2910:        io.uio_iovcnt = 1;
                   2911:        io.uio_offset = (off_t)off;
                   2912:        io.uio_resid = fullsiz;
                   2913:        io.uio_segflg = UIO_SYSSPACE;
                   2914:        io.uio_rw = UIO_READ;
1.99    ! christos 2915:        io.uio_lwp = NULL;
1.23      fvdl     2916:        eofflag = 0;
                   2917:
1.42      fvdl     2918:        vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                   2919:
                   2920:        error = VOP_READDIR(vp, &io, cred, &eofflag, &cookies, &ncookies);
1.23      fvdl     2921:
                   2922:        off = (u_quad_t)io.uio_offset;
1.99    ! christos 2923:        getret = VOP_GETATTR(vp, &at, cred, lwp);
1.23      fvdl     2924:
1.42      fvdl     2925:        VOP_UNLOCK(vp, 0);
1.36      fvdl     2926:
                   2927:        /*
                   2928:         * If the VGET operation doesn't work for this filesystem,
                   2929:         * we can't support readdirplus. Returning NOTSUPP should
                   2930:         * make clients fall back to plain readdir.
                   2931:         * There's no need to check for VPTOFH as well, we wouldn't
                   2932:         * even be here otherwise.
                   2933:         */
                   2934:        if (!getret) {
1.78      thorpej  2935:                if ((getret = VFS_VGET(vp->v_mount, at.va_fileid, &nvp)))
1.36      fvdl     2936:                        getret = (getret == EOPNOTSUPP) ?
                   2937:                                NFSERR_NOTSUPP : NFSERR_IO;
                   2938:                else
                   2939:                        vput(nvp);
                   2940:        }
                   2941:
1.23      fvdl     2942:        if (!cookies && !error)
                   2943:                error = NFSERR_PERM;
                   2944:        if (!error)
                   2945:                error = getret;
1.15      mycroft  2946:        if (error) {
                   2947:                vrele(vp);
1.23      fvdl     2948:                if (cookies)
1.56      thorpej  2949:                        free((caddr_t)cookies, M_TEMP);
                   2950:                free((caddr_t)rbuf, M_TEMP);
1.23      fvdl     2951:                nfsm_reply(NFSX_V3POSTOPATTR);
                   2952:                nfsm_srvpostop_attr(getret, &at);
                   2953:                return (0);
1.15      mycroft  2954:        }
                   2955:        if (io.uio_resid) {
                   2956:                siz -= io.uio_resid;
                   2957:
                   2958:                /*
                   2959:                 * If nothing read, return eof
                   2960:                 * rpc reply
                   2961:                 */
                   2962:                if (siz == 0) {
                   2963:                        vrele(vp);
1.23      fvdl     2964:                        nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
                   2965:                                2 * NFSX_UNSIGNED);
                   2966:                        nfsm_srvpostop_attr(getret, &at);
                   2967:                        nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1.48      fair     2968:                        txdr_hyper(at.va_filerev, tl);
1.23      fvdl     2969:                        tl += 2;
1.15      mycroft  2970:                        *tl++ = nfs_false;
                   2971:                        *tl = nfs_true;
1.56      thorpej  2972:                        free((caddr_t)cookies, M_TEMP);
                   2973:                        free((caddr_t)rbuf, M_TEMP);
1.15      mycroft  2974:                        return (0);
                   2975:                }
                   2976:        }
                   2977:
                   2978:        /*
                   2979:         * Check for degenerate cases of nothing useful read.
                   2980:         * If so go try again
                   2981:         */
                   2982:        cpos = rbuf;
                   2983:        cend = rbuf + siz;
1.23      fvdl     2984:        dp = (struct dirent *)cpos;
                   2985:        cookiep = cookies;
                   2986:
1.29      fvdl     2987:        while (cpos < cend && ncookies > 0 &&
                   2988:                (dp->d_fileno == 0 || dp->d_type == DT_WHT)) {
1.23      fvdl     2989:                cpos += dp->d_reclen;
1.15      mycroft  2990:                dp = (struct dirent *)cpos;
1.23      fvdl     2991:                cookiep++;
                   2992:                ncookies--;
1.15      mycroft  2993:        }
1.23      fvdl     2994:        if (cpos >= cend || ncookies == 0) {
                   2995:                toff = off;
1.15      mycroft  2996:                siz = fullsiz;
                   2997:                goto again;
                   2998:        }
                   2999:
1.23      fvdl     3000:        dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
                   3001:        nfsm_reply(cnt);
                   3002:        nfsm_srvpostop_attr(getret, &at);
                   3003:        nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1.48      fair     3004:        txdr_hyper(at.va_filerev, tl);
1.15      mycroft  3005:        mp = mp2 = mb;
                   3006:        bp = bpos;
                   3007:        be = bp + M_TRAILINGSPACE(mp);
1.1       cgd      3008:
                   3009:        /* Loop through the records and build reply */
1.23      fvdl     3010:        while (cpos < cend && ncookies > 0) {
1.25      jtk      3011:                if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
1.1       cgd      3012:                        nlen = dp->d_namlen;
                   3013:                        rem = nfsm_rndup(nlen)-nlen;
1.94      perry    3014:
1.1       cgd      3015:                        /*
1.15      mycroft  3016:                         * For readdir_and_lookup get the vnode using
                   3017:                         * the file number.
1.1       cgd      3018:                         */
1.78      thorpej  3019:                        if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
1.15      mycroft  3020:                                goto invalid;
1.44      perry    3021:                        memset((caddr_t)nfhp, 0, NFSX_V3FH);
1.23      fvdl     3022:                        nfhp->fh_fsid =
1.88      christos 3023:                                nvp->v_mount->mnt_stat.f_fsidx;
1.23      fvdl     3024:                        if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
1.15      mycroft  3025:                                vput(nvp);
                   3026:                                goto invalid;
                   3027:                        }
1.99    ! christos 3028:                        if (VOP_GETATTR(nvp, vap, cred, lwp)) {
1.15      mycroft  3029:                                vput(nvp);
                   3030:                                goto invalid;
                   3031:                        }
                   3032:                        vput(nvp);
1.23      fvdl     3033:
                   3034:                        /*
                   3035:                         * If either the dircount or maxcount will be
                   3036:                         * exceeded, get out now. Both of these lengths
                   3037:                         * are calculated conservatively, including all
                   3038:                         * XDR overheads.
                   3039:                         */
1.52      fvdl     3040:                        len += (8 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
1.23      fvdl     3041:                                NFSX_V3POSTOPATTR);
                   3042:                        dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
                   3043:                        if (len > cnt || dirlen > fullsiz) {
1.1       cgd      3044:                                eofflag = 0;
                   3045:                                break;
                   3046:                        }
1.23      fvdl     3047:
1.15      mycroft  3048:                        /*
                   3049:                         * Build the directory record xdr from
                   3050:                         * the dirent entry.
                   3051:                         */
1.23      fvdl     3052:                        fp = (struct nfs_fattr *)&fl.fl_fattr;
                   3053:                        nfsm_srvfillattr(vap, fp);
                   3054:                        fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
                   3055:                        fl.fl_fhok = nfs_true;
                   3056:                        fl.fl_postopok = nfs_true;
1.48      fair     3057:                        txdr_hyper(*cookiep, fl.fl_off.nfsuquad);
1.23      fvdl     3058:
1.1       cgd      3059:                        nfsm_clget;
                   3060:                        *tl = nfs_true;
                   3061:                        bp += NFSX_UNSIGNED;
1.23      fvdl     3062:                        nfsm_clget;
1.96      yamt     3063:                        *tl = txdr_unsigned(dp->d_fileno >> 32);
1.23      fvdl     3064:                        bp += NFSX_UNSIGNED;
1.1       cgd      3065:                        nfsm_clget;
1.11      ws       3066:                        *tl = txdr_unsigned(dp->d_fileno);
1.1       cgd      3067:                        bp += NFSX_UNSIGNED;
                   3068:                        nfsm_clget;
                   3069:                        *tl = txdr_unsigned(nlen);
                   3070:                        bp += NFSX_UNSIGNED;
1.94      perry    3071:
1.15      mycroft  3072:                        /* And loop around copying the name */
1.1       cgd      3073:                        xfer = nlen;
                   3074:                        cp = dp->d_name;
                   3075:                        while (xfer > 0) {
                   3076:                                nfsm_clget;
1.23      fvdl     3077:                                if ((bp + xfer) > be)
                   3078:                                        tsiz = be - bp;
1.1       cgd      3079:                                else
                   3080:                                        tsiz = xfer;
1.44      perry    3081:                                memcpy(bp, cp, tsiz);
1.1       cgd      3082:                                bp += tsiz;
                   3083:                                xfer -= tsiz;
                   3084:                                if (xfer > 0)
                   3085:                                        cp += tsiz;
                   3086:                        }
1.23      fvdl     3087:                        /* And null pad to an int32_t boundary */
1.1       cgd      3088:                        for (i = 0; i < rem; i++)
                   3089:                                *bp++ = '\0';
1.94      perry    3090:
1.23      fvdl     3091:                        /*
                   3092:                         * Now copy the flrep structure out.
                   3093:                         */
                   3094:                        xfer = sizeof (struct flrep);
                   3095:                        cp = (caddr_t)&fl;
                   3096:                        while (xfer > 0) {
                   3097:                                nfsm_clget;
                   3098:                                if ((bp + xfer) > be)
                   3099:                                        tsiz = be - bp;
                   3100:                                else
                   3101:                                        tsiz = xfer;
1.44      perry    3102:                                memcpy(bp, cp, tsiz);
1.23      fvdl     3103:                                bp += tsiz;
                   3104:                                xfer -= tsiz;
                   3105:                                if (xfer > 0)
                   3106:                                        cp += tsiz;
                   3107:                        }
1.8       ws       3108:                }
1.15      mycroft  3109: invalid:
1.1       cgd      3110:                cpos += dp->d_reclen;
1.11      ws       3111:                dp = (struct dirent *)cpos;
1.23      fvdl     3112:                cookiep++;
                   3113:                ncookies--;
1.1       cgd      3114:        }
1.15      mycroft  3115:        vrele(vp);
1.1       cgd      3116:        nfsm_clget;
                   3117:        *tl = nfs_false;
                   3118:        bp += NFSX_UNSIGNED;
                   3119:        nfsm_clget;
                   3120:        if (eofflag)
                   3121:                *tl = nfs_true;
                   3122:        else
                   3123:                *tl = nfs_false;
                   3124:        bp += NFSX_UNSIGNED;
1.15      mycroft  3125:        if (mp != mb) {
                   3126:                if (bp < be)
                   3127:                        mp->m_len = bp - mtod(mp, caddr_t);
                   3128:        } else
                   3129:                mp->m_len += bp - bpos;
1.56      thorpej  3130:        free((caddr_t)cookies, M_TEMP);
                   3131:        free((caddr_t)rbuf, M_TEMP);
1.23      fvdl     3132:        nfsm_srvdone;
                   3133: }
                   3134:
                   3135: /*
                   3136:  * nfs commit service
                   3137:  */
                   3138: int
1.99    ! christos 3139: nfsrv_commit(nfsd, slp, lwp, mrq)
1.23      fvdl     3140:        struct nfsrv_descript *nfsd;
                   3141:        struct nfssvc_sock *slp;
1.99    ! christos 3142:        struct lwp *lwp;
1.23      fvdl     3143:        struct mbuf **mrq;
                   3144: {
                   3145:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                   3146:        struct mbuf *nam = nfsd->nd_nam;
                   3147:        caddr_t dpos = nfsd->nd_dpos;
                   3148:        struct ucred *cred = &nfsd->nd_cr;
                   3149:        struct vattr bfor, aft;
                   3150:        struct vnode *vp;
                   3151:        nfsfh_t nfh;
                   3152:        fhandle_t *fhp;
1.54      augustss 3153:        u_int32_t *tl;
                   3154:        int32_t t1;
1.23      fvdl     3155:        caddr_t bpos;
1.93      yamt     3156:        int error = 0, rdonly, for_ret = 1, aft_ret = 1, cache;
                   3157:        uint32_t cnt;
1.23      fvdl     3158:        char *cp2;
1.67      matt     3159:        struct mbuf *mb, *mreq;
1.65      bouyer   3160:        u_quad_t frev, off, end;
1.82      hannken  3161:        struct mount *mp = NULL;
1.23      fvdl     3162:
                   3163: #ifndef nolint
                   3164:        cache = 0;
                   3165: #endif
                   3166:        fhp = &nfh.fh_generic;
                   3167:        nfsm_srvmtofh(fhp);
1.82      hannken  3168:        if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL)
                   3169:                return (ESTALE);
                   3170:        vn_start_write(NULL, &mp, V_WAIT);
1.23      fvdl     3171:        nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
                   3172:
1.48      fair     3173:        off = fxdr_hyper(tl);
1.23      fvdl     3174:        tl += 2;
1.93      yamt     3175:        cnt = fxdr_unsigned(uint32_t, *tl);
1.23      fvdl     3176:        error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.78      thorpej  3177:                 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl     3178:        if (error) {
                   3179:                nfsm_reply(2 * NFSX_UNSIGNED);
                   3180:                nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
1.82      hannken  3181:                vn_finished_write(mp, 0);
1.23      fvdl     3182:                return (0);
                   3183:        }
1.99    ! christos 3184:        for_ret = VOP_GETATTR(vp, &bfor, cred, lwp);
1.65      bouyer   3185:        end = (cnt > 0) ? off + cnt : vp->v_size;
                   3186:        if (end < off || end > vp->v_size)
                   3187:                end = vp->v_size;
1.80      bouyer   3188:        if (off < vp->v_size)
1.99    ! christos 3189:                error = VOP_FSYNC(vp, cred, FSYNC_WAIT, off, end, lwp);
1.80      bouyer   3190:        /* else error == 0, from nfsrv_fhtovp() */
1.99    ! christos 3191:        aft_ret = VOP_GETATTR(vp, &aft, cred, lwp);
1.23      fvdl     3192:        vput(vp);
                   3193:        nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
                   3194:        nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
                   3195:        if (!error) {
                   3196:                nfsm_build(tl, u_int32_t *, NFSX_V3WRITEVERF);
                   3197:                *tl++ = txdr_unsigned(boottime.tv_sec);
                   3198:                *tl = txdr_unsigned(boottime.tv_usec);
1.82      hannken  3199:        } else {
                   3200:                vn_finished_write(mp, 0);
1.23      fvdl     3201:                return (0);
1.82      hannken  3202:        }
                   3203:        vn_finished_write(mp, 0);
1.1       cgd      3204:        nfsm_srvdone;
                   3205: }
                   3206:
                   3207: /*
                   3208:  * nfs statfs service
                   3209:  */
1.22      christos 3210: int
1.99    ! christos 3211: nfsrv_statfs(nfsd, slp, lwp, mrq)
1.23      fvdl     3212:        struct nfsrv_descript *nfsd;
                   3213:        struct nfssvc_sock *slp;
1.99    ! christos 3214:        struct lwp *lwp;
1.23      fvdl     3215:        struct mbuf **mrq;
1.1       cgd      3216: {
1.23      fvdl     3217:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                   3218:        struct mbuf *nam = nfsd->nd_nam;
                   3219:        caddr_t dpos = nfsd->nd_dpos;
                   3220:        struct ucred *cred = &nfsd->nd_cr;
1.88      christos 3221:        struct statvfs *sf;
1.54      augustss 3222:        struct nfs_statfs *sfp;
                   3223:        u_int32_t *tl;
                   3224:        int32_t t1;
1.1       cgd      3225:        caddr_t bpos;
1.23      fvdl     3226:        int error = 0, rdonly, cache, getret = 1;
                   3227:        int v3 = (nfsd->nd_flag & ND_NFSV3);
1.1       cgd      3228:        char *cp2;
1.67      matt     3229:        struct mbuf *mb, *mreq;
1.1       cgd      3230:        struct vnode *vp;
1.23      fvdl     3231:        struct vattr at;
                   3232:        nfsfh_t nfh;
1.1       cgd      3233:        fhandle_t *fhp;
1.88      christos 3234:        struct statvfs statvfs;
1.23      fvdl     3235:        u_quad_t frev, tval;
1.1       cgd      3236:
1.23      fvdl     3237: #ifndef nolint
                   3238:        cache = 0;
                   3239: #endif
1.1       cgd      3240:        fhp = &nfh.fh_generic;
                   3241:        nfsm_srvmtofh(fhp);
1.23      fvdl     3242:        error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.78      thorpej  3243:                 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl     3244:        if (error) {
                   3245:                nfsm_reply(NFSX_UNSIGNED);
                   3246:                nfsm_srvpostop_attr(getret, &at);
                   3247:                return (0);
                   3248:        }
1.88      christos 3249:        sf = &statvfs;
1.99    ! christos 3250:        error = VFS_STATVFS(vp->v_mount, sf, lwp);
        !          3251:        getret = VOP_GETATTR(vp, &at, cred, lwp);
1.1       cgd      3252:        vput(vp);
1.23      fvdl     3253:        nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
                   3254:        if (v3)
                   3255:                nfsm_srvpostop_attr(getret, &at);
                   3256:        if (error)
                   3257:                return (0);
                   3258:        nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
                   3259:        if (v3) {
1.88      christos 3260:                tval = (u_quad_t)((quad_t)sf->f_blocks * (quad_t)sf->f_frsize);
1.48      fair     3261:                txdr_hyper(tval, &sfp->sf_tbytes);
1.88      christos 3262:                tval = (u_quad_t)((quad_t)sf->f_bfree * (quad_t)sf->f_frsize);
1.48      fair     3263:                txdr_hyper(tval, &sfp->sf_fbytes);
1.88      christos 3264:                tval = (u_quad_t)((quad_t)sf->f_bavail * (quad_t)sf->f_frsize);
1.48      fair     3265:                txdr_hyper(tval, &sfp->sf_abytes);
1.47      mycroft  3266:                tval = (u_quad_t)sf->f_files;
1.48      fair     3267:                txdr_hyper(tval, &sfp->sf_tfiles);
1.47      mycroft  3268:                tval = (u_quad_t)sf->f_ffree;
1.48      fair     3269:                txdr_hyper(tval, &sfp->sf_ffiles);
                   3270:                txdr_hyper(tval, &sfp->sf_afiles);
1.23      fvdl     3271:                sfp->sf_invarsec = 0;
                   3272:        } else {
                   3273:                sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
1.88      christos 3274:                sfp->sf_bsize = txdr_unsigned(sf->f_frsize);
1.23      fvdl     3275:                sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
                   3276:                sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
                   3277:                sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
                   3278:        }
                   3279:        nfsm_srvdone;
                   3280: }
                   3281:
                   3282: /*
                   3283:  * nfs fsinfo service
                   3284:  */
                   3285: int
1.99    ! christos 3286: nfsrv_fsinfo(nfsd, slp, lwp, mrq)
1.23      fvdl     3287:        struct nfsrv_descript *nfsd;
                   3288:        struct nfssvc_sock *slp;
1.99    ! christos 3289:        struct lwp *lwp;
1.23      fvdl     3290:        struct mbuf **mrq;
                   3291: {
                   3292:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                   3293:        struct mbuf *nam = nfsd->nd_nam;
                   3294:        caddr_t dpos = nfsd->nd_dpos;
                   3295:        struct ucred *cred = &nfsd->nd_cr;
1.54      augustss 3296:        u_int32_t *tl;
                   3297:        struct nfsv3_fsinfo *sip;
                   3298:        int32_t t1;
1.23      fvdl     3299:        caddr_t bpos;
1.69      yamt     3300:        int error = 0, rdonly, cache, getret = 1;
                   3301:        uint32_t maxdata;
1.23      fvdl     3302:        char *cp2;
1.67      matt     3303:        struct mbuf *mb, *mreq;
1.23      fvdl     3304:        struct vnode *vp;
                   3305:        struct vattr at;
                   3306:        nfsfh_t nfh;
                   3307:        fhandle_t *fhp;
1.37      fvdl     3308:        u_quad_t frev, maxfsize;
1.88      christos 3309:        struct statvfs sb;
1.23      fvdl     3310:
                   3311: #ifndef nolint
                   3312:        cache = 0;
                   3313: #endif
                   3314:        fhp = &nfh.fh_generic;
                   3315:        nfsm_srvmtofh(fhp);
                   3316:        error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.78      thorpej  3317:                 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl     3318:        if (error) {
                   3319:                nfsm_reply(NFSX_UNSIGNED);
                   3320:                nfsm_srvpostop_attr(getret, &at);
                   3321:                return (0);
1.15      mycroft  3322:        }
1.37      fvdl     3323:
                   3324:        /* XXX Try to make a guess on the max file size. */
1.99    ! christos 3325:        VFS_STATVFS(vp->v_mount, &sb, (struct lwp *)0);
1.88      christos 3326:        maxfsize = (u_quad_t)0x80000000 * sb.f_frsize - 1;
1.37      fvdl     3327:
1.99    ! christos 3328:        getret = VOP_GETATTR(vp, &at, cred, lwp);
1.23      fvdl     3329:        vput(vp);
                   3330:        nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
                   3331:        nfsm_srvpostop_attr(getret, &at);
                   3332:        nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
                   3333:
                   3334:        /*
                   3335:         * XXX
                   3336:         * There should be file system VFS OP(s) to get this information.
                   3337:         * For now, assume ufs.
                   3338:         */
                   3339:        if (slp->ns_so->so_type == SOCK_DGRAM)
1.69      yamt     3340:                maxdata = NFS_MAXDGRAMDATA;
1.23      fvdl     3341:        else
1.69      yamt     3342:                maxdata = NFS_MAXDATA;
                   3343:        sip->fs_rtmax = txdr_unsigned(maxdata);
                   3344:        sip->fs_rtpref = txdr_unsigned(maxdata);
1.23      fvdl     3345:        sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
1.69      yamt     3346:        sip->fs_wtmax = txdr_unsigned(maxdata);
                   3347:        sip->fs_wtpref = txdr_unsigned(maxdata);
1.23      fvdl     3348:        sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
1.69      yamt     3349:        sip->fs_dtpref = txdr_unsigned(maxdata);
1.48      fair     3350:        txdr_hyper(maxfsize, &sip->fs_maxfilesize);
1.23      fvdl     3351:        sip->fs_timedelta.nfsv3_sec = 0;
                   3352:        sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
                   3353:        sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
                   3354:                NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
                   3355:                NFSV3FSINFO_CANSETTIME);
                   3356:        nfsm_srvdone;
                   3357: }
                   3358:
                   3359: /*
                   3360:  * nfs pathconf service
                   3361:  */
                   3362: int
1.99    ! christos 3363: nfsrv_pathconf(nfsd, slp, lwp, mrq)
1.23      fvdl     3364:        struct nfsrv_descript *nfsd;
                   3365:        struct nfssvc_sock *slp;
1.99    ! christos 3366:        struct lwp *lwp;
1.23      fvdl     3367:        struct mbuf **mrq;
                   3368: {
                   3369:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                   3370:        struct mbuf *nam = nfsd->nd_nam;
                   3371:        caddr_t dpos = nfsd->nd_dpos;
                   3372:        struct ucred *cred = &nfsd->nd_cr;
1.54      augustss 3373:        u_int32_t *tl;
                   3374:        struct nfsv3_pathconf *pc;
                   3375:        int32_t t1;
1.23      fvdl     3376:        caddr_t bpos;
1.24      cgd      3377:        int error = 0, rdonly, cache, getret = 1;
                   3378:        register_t linkmax, namemax, chownres, notrunc;
1.23      fvdl     3379:        char *cp2;
1.67      matt     3380:        struct mbuf *mb, *mreq;
1.23      fvdl     3381:        struct vnode *vp;
                   3382:        struct vattr at;
                   3383:        nfsfh_t nfh;
                   3384:        fhandle_t *fhp;
                   3385:        u_quad_t frev;
                   3386:
                   3387: #ifndef nolint
                   3388:        cache = 0;
                   3389: #endif
                   3390:        fhp = &nfh.fh_generic;
                   3391:        nfsm_srvmtofh(fhp);
                   3392:        error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.78      thorpej  3393:                 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23      fvdl     3394:        if (error) {
                   3395:                nfsm_reply(NFSX_UNSIGNED);
                   3396:                nfsm_srvpostop_attr(getret, &at);
                   3397:                return (0);
                   3398:        }
                   3399:        error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
                   3400:        if (!error)
                   3401:                error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
                   3402:        if (!error)
                   3403:                error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
                   3404:        if (!error)
                   3405:                error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc);
1.99    ! christos 3406:        getret = VOP_GETATTR(vp, &at, cred, lwp);
1.23      fvdl     3407:        vput(vp);
                   3408:        nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
                   3409:        nfsm_srvpostop_attr(getret, &at);
                   3410:        if (error)
                   3411:                return (0);
                   3412:        nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
                   3413:
                   3414:        pc->pc_linkmax = txdr_unsigned(linkmax);
                   3415:        pc->pc_namemax = txdr_unsigned(namemax);
                   3416:        pc->pc_notrunc = txdr_unsigned(notrunc);
                   3417:        pc->pc_chownrestricted = txdr_unsigned(chownres);
                   3418:
                   3419:        /*
                   3420:         * These should probably be supported by VOP_PATHCONF(), but
                   3421:         * until msdosfs is exportable (why would you want to?), the
                   3422:         * Unix defaults should be ok.
                   3423:         */
                   3424:        pc->pc_caseinsensitive = nfs_false;
                   3425:        pc->pc_casepreserving = nfs_true;
1.1       cgd      3426:        nfsm_srvdone;
                   3427: }
                   3428:
                   3429: /*
                   3430:  * Null operation, used by clients to ping server
                   3431:  */
                   3432: /* ARGSUSED */
1.22      christos 3433: int
1.99    ! christos 3434: nfsrv_null(nfsd, slp, lwp, mrq)
1.23      fvdl     3435:        struct nfsrv_descript *nfsd;
                   3436:        struct nfssvc_sock *slp;
1.99    ! christos 3437:        struct lwp *lwp;
1.23      fvdl     3438:        struct mbuf **mrq;
1.1       cgd      3439: {
1.23      fvdl     3440:        struct mbuf *mrep = nfsd->nd_mrep;
1.1       cgd      3441:        caddr_t bpos;
1.23      fvdl     3442:        int error = NFSERR_RETVOID, cache = 0;
1.1       cgd      3443:        struct mbuf *mb, *mreq;
1.15      mycroft  3444:        u_quad_t frev;
1.1       cgd      3445:
                   3446:        nfsm_reply(0);
1.23      fvdl     3447:        return (0);
1.1       cgd      3448: }
                   3449:
                   3450: /*
                   3451:  * No operation, used for obsolete procedures
                   3452:  */
                   3453: /* ARGSUSED */
1.22      christos 3454: int
1.99    ! christos 3455: nfsrv_noop(nfsd, slp, lwp, mrq)
1.23      fvdl     3456:        struct nfsrv_descript *nfsd;
                   3457:        struct nfssvc_sock *slp;
1.99    ! christos 3458:        struct lwp *lwp;
1.23      fvdl     3459:        struct mbuf **mrq;
1.1       cgd      3460: {
1.23      fvdl     3461:        struct mbuf *mrep = nfsd->nd_mrep;
1.1       cgd      3462:        caddr_t bpos;
1.22      christos 3463:        int error, cache = 0;
1.1       cgd      3464:        struct mbuf *mb, *mreq;
1.15      mycroft  3465:        u_quad_t frev;
1.1       cgd      3466:
1.15      mycroft  3467:        if (nfsd->nd_repstat)
                   3468:                error = nfsd->nd_repstat;
1.2       cgd      3469:        else
                   3470:                error = EPROCUNAVAIL;
1.1       cgd      3471:        nfsm_reply(0);
1.23      fvdl     3472:        return (0);
1.1       cgd      3473: }
                   3474:
                   3475: /*
                   3476:  * Perform access checking for vnodes obtained from file handles that would
                   3477:  * refer to files already opened by a Unix client. You cannot just use
                   3478:  * vn_writechk() and VOP_ACCESS() for two reasons.
1.15      mycroft  3479:  * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
1.27      fvdl     3480:  * 2 - The owner is to be given access irrespective of mode bits for some
                   3481:  *     operations, so that processes that chmod after opening a file don't
                   3482:  *     break. I don't like this because it opens a security hole, but since
                   3483:  *     the nfs server opens a security hole the size of a barn door anyhow,
                   3484:  *     what the heck.
1.31      fvdl     3485:  *
                   3486:  * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
                   3487:  * will return EPERM instead of EACCESS. EPERM is always an error.
1.1       cgd      3488:  */
1.22      christos 3489: int
1.99    ! christos 3490: nfsrv_access(vp, flags, cred, rdonly, lwp, override)
1.54      augustss 3491:        struct vnode *vp;
1.1       cgd      3492:        int flags;
1.54      augustss 3493:        struct ucred *cred;
1.15      mycroft  3494:        int rdonly;
1.99    ! christos 3495:        struct lwp *lwp;
1.1       cgd      3496: {
                   3497:        struct vattr vattr;
                   3498:        int error;
                   3499:        if (flags & VWRITE) {
1.15      mycroft  3500:                /* Just vn_writechk() changed to check rdonly */
1.1       cgd      3501:                /*
                   3502:                 * Disallow write attempts on read-only file systems;
                   3503:                 * unless the file is a socket or a block or character
                   3504:                 * device resident on the file system.
                   3505:                 */
1.15      mycroft  3506:                if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
1.1       cgd      3507:                        switch (vp->v_type) {
1.23      fvdl     3508:                        case VREG:
                   3509:                        case VDIR:
                   3510:                        case VLNK:
1.1       cgd      3511:                                return (EROFS);
1.23      fvdl     3512:                        default:
1.22      christos 3513:                                break;
1.1       cgd      3514:                        }
                   3515:                }
1.59      chs      3516:
1.1       cgd      3517:                /*
1.59      chs      3518:                 * If the vnode is in use as a process's text,
                   3519:                 * we can't allow writing.
1.1       cgd      3520:                 */
1.94      perry    3521:                if (vp->v_flag & VTEXT)
1.40      mrg      3522:                        return (ETXTBSY);
1.1       cgd      3523:        }
1.99    ! christos 3524:        error = VOP_GETATTR(vp, &vattr, cred, lwp);
1.23      fvdl     3525:        if (error)
1.1       cgd      3526:                return (error);
1.99    ! christos 3527:        error = VOP_ACCESS(vp, flags, cred, lwp);
1.27      fvdl     3528:        /*
                   3529:         * Allow certain operations for the owner (reads and writes
                   3530:         * on files that are already open).
                   3531:         */
1.31      fvdl     3532:        if (override && error == EACCES && cred->cr_uid == vattr.va_uid)
1.27      fvdl     3533:                error = 0;
                   3534:        return error;
1.1       cgd      3535: }

CVSweb <webmaster@jp.NetBSD.org>