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

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

CVSweb <webmaster@jp.NetBSD.org>