[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.112

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

CVSweb <webmaster@jp.NetBSD.org>