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

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

CVSweb <webmaster@jp.NetBSD.org>