Annotation of kernel/bsd/nfs/nfs_nqlease.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
                     26: /*
                     27:  * Copyright (c) 1992, 1993
                     28:  *     The Regents of the University of California.  All rights reserved.
                     29:  *
                     30:  * This code is derived from software contributed to Berkeley by
                     31:  * Rick Macklem at The University of Guelph.
                     32:  *
                     33:  * Redistribution and use in source and binary forms, with or without
                     34:  * modification, are permitted provided that the following conditions
                     35:  * are met:
                     36:  * 1. Redistributions of source code must retain the above copyright
                     37:  *    notice, this list of conditions and the following disclaimer.
                     38:  * 2. Redistributions in binary form must reproduce the above copyright
                     39:  *    notice, this list of conditions and the following disclaimer in the
                     40:  *    documentation and/or other materials provided with the distribution.
                     41:  * 3. All advertising materials mentioning features or use of this software
                     42:  *    must display the following acknowledgement:
                     43:  *     This product includes software developed by the University of
                     44:  *     California, Berkeley and its contributors.
                     45:  * 4. Neither the name of the University nor the names of its contributors
                     46:  *    may be used to endorse or promote products derived from this software
                     47:  *    without specific prior written permission.
                     48:  *
                     49:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     50:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     51:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     52:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     53:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     54:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     55:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     56:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     57:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     58:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     59:  * SUCH DAMAGE.
                     60:  *
                     61:  *     @(#)nfs_nqlease.c       8.9 (Berkeley) 5/20/95
                     62:  * FreeBSD-Id: nfs_nqlease.c,v 1.32 1997/11/07 08:53:23 phk Exp $
                     63:  */
                     64: 
                     65: 
                     66: /*
                     67:  * References:
                     68:  *     Cary G. Gray and David R. Cheriton, "Leases: An Efficient Fault-Tolerant
                     69:  *             Mechanism for Distributed File Cache Consistency",
                     70:  *             In Proc. of the Twelfth ACM Symposium on Operating Systems
                     71:  *             Principals, pg. 202-210, Litchfield Park, AZ, Dec. 1989.
                     72:  *     Michael N. Nelson, Brent B. Welch and John K. Ousterhout, "Caching
                     73:  *             in the Sprite Network File System", ACM TOCS 6(1),
                     74:  *             pages 134-154, February 1988.
                     75:  *     V. Srinivasan and Jeffrey C. Mogul, "Spritely NFS: Implementation and
                     76:  *             Performance of Cache-Consistency Protocols", Digital
                     77:  *             Equipment Corporation WRL Research Report 89/5, May 1989.
                     78:  */
                     79: #include <sys/param.h>
                     80: #include <sys/vnode.h>
                     81: #include <sys/mount.h>
                     82: #include <sys/kernel.h>
                     83: #include <sys/proc.h>
                     84: #include <sys/systm.h>
                     85: #include <sys/malloc.h>
                     86: #include <sys/mbuf.h>
                     87: #include <sys/socket.h>
                     88: #include <sys/socketvar.h>
                     89: #include <sys/protosw.h>
                     90: #include <machine/spl.h>
                     91: 
                     92: #include <netinet/in.h>
                     93: #include <nfs/rpcv2.h>
                     94: #include <nfs/nfsproto.h>
                     95: #include <nfs/nfs.h>
                     96: #include <nfs/nfsm_subs.h>
                     97: #include <nfs/xdr_subs.h>
                     98: #include <nfs/nqnfs.h>
                     99: #include <nfs/nfsnode.h>
                    100: #include <nfs/nfsmount.h>
                    101: 
                    102: time_t nqnfsstarttime = (time_t)0;
                    103: int nqsrv_clockskew = NQ_CLOCKSKEW;
                    104: int nqsrv_writeslack = NQ_WRITESLACK;
                    105: int nqsrv_maxlease = NQ_MAXLEASE;
                    106: static int nqsrv_maxnumlease = NQ_MAXNUMLEASE;
                    107: 
                    108: struct vop_lease_args;
                    109: 
                    110: static int     nqsrv_cmpnam __P((struct nfssvc_sock *, struct mbuf *,
                    111:                        struct nqhost *));
                    112: extern void    nqnfs_lease_updatetime __P((int deltat));
                    113: static int     nqnfs_vacated __P((struct vnode *vp, struct ucred *cred));
                    114: static void    nqsrv_addhost __P((struct nqhost *lph, struct nfssvc_sock *slp,
                    115:                                   struct mbuf *nam));
                    116: static void    nqsrv_instimeq __P((struct nqlease *lp, u_long duration));
                    117: static void    nqsrv_locklease __P((struct nqlease *lp));
                    118: static void    nqsrv_send_eviction __P((struct vnode *vp, struct nqlease *lp,
                    119:                                         struct nfssvc_sock *slp,
                    120:                                         struct mbuf *nam, struct ucred *cred));
                    121: static void    nqsrv_unlocklease __P((struct nqlease *lp));
                    122: static void    nqsrv_waitfor_expiry __P((struct nqlease *lp));
                    123: 
                    124: /*
                    125:  * Signifies which rpcs can have piggybacked lease requests
                    126:  */
                    127: int nqnfs_piggy[NFS_NPROCS] = {
                    128:        0,
                    129:        0,
                    130:        ND_WRITE,
                    131:        ND_READ,
                    132:        0,
                    133:        ND_READ,
                    134:        ND_READ,
                    135:        ND_WRITE,
                    136:        0,
                    137:        0,
                    138:        0,
                    139:        0,
                    140:        0,
                    141:        0,
                    142:        0,
                    143:        0,
                    144:        ND_READ,
                    145:        ND_READ,
                    146:        0,
                    147:        0,
                    148:        0,
                    149:        0,
                    150:        0,
                    151:        0,
                    152:        0,
                    153:        0,
                    154: };
                    155: 
                    156: extern nfstype nfsv2_type[9];
                    157: extern nfstype nfsv3_type[9];
                    158: extern struct nfssvc_sock *nfs_udpsock, *nfs_cltpsock;
                    159: extern int nfsd_waiting;
                    160: extern struct nfsstats nfsstats;
                    161: extern int nfs_mount_type;
                    162: 
                    163: #define TRUE   1
                    164: #define        FALSE   0
                    165: 
                    166: #ifndef NFS_NOSERVER 
                    167: /*
                    168:  * Get or check for a lease for "vp", based on ND_CHECK flag.
                    169:  * The rules are as follows:
                    170:  * - if a current non-caching lease, reply non-caching
                    171:  * - if a current lease for same host only, extend lease
                    172:  * - if a read cachable lease and a read lease request
                    173:  *     add host to list any reply cachable
                    174:  * - else { set non-cachable for read-write sharing }
                    175:  *     send eviction notice messages to all other hosts that have lease
                    176:  *     wait for lease termination { either by receiving vacated messages
                    177:  *                                     from all the other hosts or expiry
                    178:  *                                     via. timeout }
                    179:  *     modify lease to non-cachable
                    180:  * - else if no current lease, issue new one
                    181:  * - reply
                    182:  * - return boolean TRUE iff nam should be m_freem()'d
                    183:  * NB: Since nqnfs_serverd() is called from a timer, any potential tsleep()
                    184:  *     in here must be framed by nqsrv_locklease() and nqsrv_unlocklease().
                    185:  *     nqsrv_locklease() is coded such that at least one of LC_LOCKED and
                    186:  *     LC_WANTED is set whenever a process is tsleeping in it. The exception
                    187:  *     is when a new lease is being allocated, since it is not in the timer
                    188:  *     queue yet. (Ditto for the splsoftclock() and splx(s) calls)
                    189:  */
                    190: int
                    191: nqsrv_getlease(vp, duration, flags, slp, procp, nam, cachablep, frev, cred)
                    192:        struct vnode *vp;
                    193:        u_long *duration;
                    194:        int flags;
                    195:        struct nfssvc_sock *slp;
                    196:        struct proc *procp;
                    197:        struct mbuf *nam;
                    198:        int *cachablep;
                    199:        u_quad_t *frev;
                    200:        struct ucred *cred;
                    201: {
                    202:        register struct nqlease *lp;
                    203:        register struct nqfhhashhead *lpp = 0;
                    204:        register struct nqhost *lph = 0;
                    205:        struct nqlease *tlp;
                    206:        struct nqm **lphp;
                    207:        struct vattr vattr;
                    208:        fhandle_t fh;
                    209:        int i, ok, error, s;
                    210: 
                    211:        if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
                    212:                return (0);
                    213:        if (*duration > nqsrv_maxlease)
                    214:                *duration = nqsrv_maxlease;
                    215:        error = VOP_GETATTR(vp, &vattr, cred, procp);
                    216:        if (error)
                    217:                return (error);
                    218:        *frev = vattr.va_filerev;
                    219:        s = splsoftclock();
                    220:        tlp = vp->v_lease;
                    221:        if ((flags & ND_CHECK) == 0)
                    222:                nfsstats.srvnqnfs_getleases++;
                    223:        if (tlp == (struct nqlease *)0) {
                    224: 
                    225:                /*
                    226:                 * Find the lease by searching the hash list.
                    227:                 */
                    228:                fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
                    229:                error = VFS_VPTOFH(vp, &fh.fh_fid);
                    230:                if (error) {
                    231:                        splx(s);
                    232:                        return (error);
                    233:                }
                    234:                lpp = NQFHHASH(fh.fh_fid.fid_data);
                    235:                for (lp = lpp->lh_first; lp != 0; lp = lp->lc_hash.le_next)
                    236:                        if (fh.fh_fsid.val[0] == lp->lc_fsid.val[0] &&
                    237:                            fh.fh_fsid.val[1] == lp->lc_fsid.val[1] &&
                    238:                            !bcmp(fh.fh_fid.fid_data, lp->lc_fiddata,
                    239:                                  fh.fh_fid.fid_len - sizeof (long))) {
                    240:                                /* Found it */
                    241:                                lp->lc_vp = vp;
                    242:                                vp->v_lease = lp;
                    243:                                tlp = lp;
                    244:                                break;
                    245:                        }
                    246:        } else
                    247:                lp = tlp;
                    248:        if (lp) {
                    249:                if ((lp->lc_flag & LC_NONCACHABLE) ||
                    250:                    (lp->lc_morehosts == (struct nqm *)0 &&
                    251:                     nqsrv_cmpnam(slp, nam, &lp->lc_host)))
                    252:                        goto doreply;
                    253:                if ((flags & ND_READ) && (lp->lc_flag & LC_WRITE) == 0) {
                    254:                        if (flags & ND_CHECK)
                    255:                                goto doreply;
                    256:                        if (nqsrv_cmpnam(slp, nam, &lp->lc_host))
                    257:                                goto doreply;
                    258:                        i = 0;
                    259:                        if (lp->lc_morehosts) {
                    260:                                lph = lp->lc_morehosts->lpm_hosts;
                    261:                                lphp = &lp->lc_morehosts->lpm_next;
                    262:                                ok = 1;
                    263:                        } else {
                    264:                                lphp = &lp->lc_morehosts;
                    265:                                ok = 0;
                    266:                        }
                    267:                        while (ok && (lph->lph_flag & LC_VALID)) {
                    268:                                if (nqsrv_cmpnam(slp, nam, lph))
                    269:                                        goto doreply;
                    270:                                if (++i == LC_MOREHOSTSIZ) {
                    271:                                        i = 0;
                    272:                                        if (*lphp) {
                    273:                                                lph = (*lphp)->lpm_hosts;
                    274:                                                lphp = &((*lphp)->lpm_next);
                    275:                                        } else
                    276:                                                ok = 0;
                    277:                                } else
                    278:                                        lph++;
                    279:                        }
                    280:                        nqsrv_locklease(lp);
                    281:                        if (!ok) {
                    282:                                MALLOC_ZONE(*lphp, struct nqm *,
                    283:                                                sizeof(struct nqm),
                    284:                                                        M_NQMHOST, M_WAITOK);
                    285:                                bzero((caddr_t)*lphp, sizeof (struct nqm));
                    286:                                lph = (*lphp)->lpm_hosts;
                    287:                        }
                    288:                        nqsrv_addhost(lph, slp, nam);
                    289:                        nqsrv_unlocklease(lp);
                    290:                } else {
                    291:                        lp->lc_flag |= LC_NONCACHABLE;
                    292:                        nqsrv_locklease(lp);
                    293:                        nqsrv_send_eviction(vp, lp, slp, nam, cred);
                    294:                        nqsrv_waitfor_expiry(lp);
                    295:                        nqsrv_unlocklease(lp);
                    296:                }
                    297: doreply:
                    298:                /*
                    299:                 * Update the lease and return
                    300:                 */
                    301:                if ((flags & ND_CHECK) == 0)
                    302:                        nqsrv_instimeq(lp, *duration);
                    303:                if (lp->lc_flag & LC_NONCACHABLE)
                    304:                        *cachablep = 0;
                    305:                else {
                    306:                        *cachablep = 1;
                    307:                        if (flags & ND_WRITE)
                    308:                                lp->lc_flag |= LC_WRITTEN;
                    309:                }
                    310:                splx(s);
                    311:                return (0);
                    312:        }
                    313:        splx(s);
                    314:        if (flags & ND_CHECK)
                    315:                return (0);
                    316: 
                    317:        /*
                    318:         * Allocate new lease
                    319:         * The value of nqsrv_maxnumlease should be set generously, so that
                    320:         * the following "printf" happens infrequently.
                    321:         */
                    322:        if (nfsstats.srvnqnfs_leases > nqsrv_maxnumlease) {
                    323:                printf("Nqnfs server, too many leases\n");
                    324:                do {
                    325:                        (void) tsleep((caddr_t)&lbolt, PSOCK,
                    326:                                        "nqsrvnuml", 0);
                    327:                } while (nfsstats.srvnqnfs_leases > nqsrv_maxnumlease);
                    328:        }
                    329:        MALLOC_ZONE(lp, struct nqlease *,
                    330:                        sizeof (struct nqlease), M_NQLEASE, M_WAITOK);
                    331:        bzero((caddr_t)lp, sizeof (struct nqlease));
                    332:        if (flags & ND_WRITE)
                    333:                lp->lc_flag |= (LC_WRITE | LC_WRITTEN);
                    334:        nqsrv_addhost(&lp->lc_host, slp, nam);
                    335:        lp->lc_vp = vp;
                    336:        lp->lc_fsid = fh.fh_fsid;
                    337:        bcopy(fh.fh_fid.fid_data, lp->lc_fiddata,
                    338:                fh.fh_fid.fid_len - sizeof (long));
                    339:        if(!lpp)
                    340:                panic("nfs_nqlease.c: Phoney lpp");
                    341:        LIST_INSERT_HEAD(lpp, lp, lc_hash);
                    342:        vp->v_lease = lp;
                    343:        s = splsoftclock();
                    344:        nqsrv_instimeq(lp, *duration);
                    345:        splx(s);
                    346:        *cachablep = 1;
                    347:        if (++nfsstats.srvnqnfs_leases > nfsstats.srvnqnfs_maxleases)
                    348:                nfsstats.srvnqnfs_maxleases = nfsstats.srvnqnfs_leases;
                    349:        return (0);
                    350: }
                    351: 
                    352: /*
                    353:  * Local lease check for server syscalls.
                    354:  * Just set up args and let nqsrv_getlease() do the rest.
                    355:  * nqnfs_vop_lease_check() is the VOP_LEASE() form of the same routine.
                    356:  * Ifdef'd code in nfsnode.h renames these routines to whatever a particular
                    357:  * OS needs.
                    358:  */
                    359: void
                    360: nqnfs_lease_check(vp, p, cred, flag)
                    361:        struct vnode *vp;
                    362:        struct proc *p;
                    363:        struct ucred *cred;
                    364:        int flag;
                    365: {
                    366:        u_long duration = 0;
                    367:        int cache;
                    368:        u_quad_t frev;
                    369: 
                    370:        (void) nqsrv_getlease(vp, &duration, ND_CHECK | flag, NQLOCALSLP,
                    371:                p, (struct mbuf *)0, &cache, &frev, cred);
                    372: }
                    373: 
                    374: int
                    375: nqnfs_vop_lease_check(ap)
                    376:        struct vop_lease_args /* {
                    377:                struct vnode *a_vp;
                    378:                struct proc *a_p;
                    379:                struct ucred *a_cred;
                    380:                int a_flag;
                    381:        } */ *ap;
                    382: {
                    383:        u_long duration = 0;
                    384:        int cache;
                    385:        u_quad_t frev;
                    386: 
                    387:        (void) nqsrv_getlease(ap->a_vp, &duration, ND_CHECK | ap->a_flag,
                    388:            NQLOCALSLP, ap->a_p, (struct mbuf *)0, &cache, &frev, ap->a_cred);
                    389:        return (0);
                    390: }
                    391: 
                    392: #endif /* NFS_NOSERVER */
                    393: 
                    394: /*
                    395:  * Add a host to an nqhost structure for a lease.
                    396:  */
                    397: static void
                    398: nqsrv_addhost(lph, slp, nam)
                    399:        register struct nqhost *lph;
                    400:        struct nfssvc_sock *slp;
                    401:        struct mbuf *nam;
                    402: {
                    403:        register struct sockaddr_in *saddr;
                    404: 
                    405:        if (slp == NQLOCALSLP)
                    406:                lph->lph_flag |= (LC_VALID | LC_LOCAL);
                    407:        else if (slp == nfs_udpsock) {
                    408:                saddr = mtod(nam, struct sockaddr_in *);
                    409:                lph->lph_flag |= (LC_VALID | LC_UDP);
                    410:                lph->lph_inetaddr = saddr->sin_addr.s_addr;
                    411:                lph->lph_port = saddr->sin_port;
                    412:        } else if (slp == nfs_cltpsock) {
                    413:                lph->lph_nam = m_copym(nam, 0, M_COPYALL, M_WAIT);
                    414:                lph->lph_flag |= (LC_VALID | LC_CLTP);
                    415:        } else {
                    416:                lph->lph_flag |= (LC_VALID | LC_SREF);
                    417:                lph->lph_slp = slp;
                    418:                slp->ns_sref++;
                    419:        }
                    420: }
                    421: 
                    422: /*
                    423:  * Update the lease expiry time and position it in the timer queue correctly.
                    424:  */
                    425: static void
                    426: nqsrv_instimeq(lp, duration)
                    427:        register struct nqlease *lp;
                    428:        u_long duration;
                    429: {
                    430:        register struct nqlease *tlp;
                    431:        time_t newexpiry;
                    432: 
                    433:        newexpiry = time.tv_sec + duration + nqsrv_clockskew;
                    434:        if (lp->lc_expiry == newexpiry)
                    435:                return;
                    436:        if (lp->lc_timer.cqe_next != 0) {
                    437:                CIRCLEQ_REMOVE(&nqtimerhead, lp, lc_timer);
                    438:        }
                    439:        lp->lc_expiry = newexpiry;
                    440: 
                    441:        /*
                    442:         * Find where in the queue it should be.
                    443:         */
                    444:        tlp = nqtimerhead.cqh_last;
                    445:        while (tlp != (void *)&nqtimerhead && tlp->lc_expiry > newexpiry)
                    446:                tlp = tlp->lc_timer.cqe_prev;
                    447: #ifdef HASNVRAM
                    448:        if (tlp == nqtimerhead.cqh_last)
                    449:                NQSTORENOVRAM(newexpiry);
                    450: #endif /* HASNVRAM */
                    451:        if (tlp == (void *)&nqtimerhead) {
                    452:                CIRCLEQ_INSERT_HEAD(&nqtimerhead, lp, lc_timer);
                    453:        } else {
                    454:                CIRCLEQ_INSERT_AFTER(&nqtimerhead, tlp, lp, lc_timer);
                    455:        }
                    456: }
                    457: 
                    458: /*
                    459:  * Compare the requesting host address with the lph entry in the lease.
                    460:  * Return true iff it is the same.
                    461:  * This is somewhat messy due to the union in the nqhost structure.
                    462:  * The local host is indicated by the special value of NQLOCALSLP for slp.
                    463:  */
                    464: static int
                    465: nqsrv_cmpnam(slp, nam, lph)
                    466:        register struct nfssvc_sock *slp;
                    467:        struct mbuf *nam;
                    468:        register struct nqhost *lph;
                    469: {
                    470:        register struct sockaddr_in *saddr;
                    471:        struct mbuf *addr;
                    472:        union nethostaddr lhaddr;
                    473:        int ret;
                    474: 
                    475:        if (slp == NQLOCALSLP) {
                    476:                if (lph->lph_flag & LC_LOCAL)
                    477:                        return (1);
                    478:                else
                    479:                        return (0);
                    480:        }
                    481:        if (slp == nfs_udpsock || slp == nfs_cltpsock)
                    482:                addr = nam;
                    483:        else
                    484:                addr = slp->ns_nam;
                    485:        if (lph->lph_flag & LC_UDP)
                    486:                ret = netaddr_match(AF_INET, &lph->lph_haddr, addr);
                    487:        else if (lph->lph_flag & LC_CLTP)
                    488:                ret = netaddr_match(AF_ISO, &lph->lph_claddr, addr);
                    489:        else {
                    490:                if ((lph->lph_slp->ns_flag & SLP_VALID) == 0)
                    491:                        return (0);
                    492:                saddr = mtod(lph->lph_slp->ns_nam, struct sockaddr_in *);
                    493:                if (saddr->sin_family == AF_INET)
                    494:                        lhaddr.had_inetaddr = saddr->sin_addr.s_addr;
                    495:                else
                    496:                        lhaddr.had_nam = lph->lph_slp->ns_nam;
                    497:                ret = netaddr_match(saddr->sin_family, &lhaddr, addr);
                    498:        }
                    499:        return (ret);
                    500: }
                    501: 
                    502: /*
                    503:  * Send out eviction notice messages to all other hosts for the lease.
                    504:  */
                    505: static void
                    506: nqsrv_send_eviction(vp, lp, slp, nam, cred)
                    507:        struct vnode *vp;
                    508:        register struct nqlease *lp;
                    509:        struct nfssvc_sock *slp;
                    510:        struct mbuf *nam;
                    511:        struct ucred *cred;
                    512: {
                    513:        register struct nqhost *lph = &lp->lc_host;
                    514:        register struct mbuf *m;
                    515:        register int siz;
                    516:        struct nqm *lphnext = lp->lc_morehosts;
                    517:        struct mbuf *mreq, *mb, *mb2, *mheadend;
                    518:        struct socket *so;
                    519:        struct mbuf *nam2;
                    520:        struct sockaddr_in *saddr;
                    521:        nfsfh_t nfh;
                    522:        fhandle_t *fhp;
                    523:        caddr_t bpos, cp;
                    524:        u_long xid, *tl;
                    525:        int len = 1, ok = 1, i = 0;
                    526:        int sotype, *solockp;
                    527: 
                    528:        while (ok && (lph->lph_flag & LC_VALID)) {
                    529:                if (nqsrv_cmpnam(slp, nam, lph))
                    530:                        lph->lph_flag |= LC_VACATED;
                    531:                else if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) {
                    532:                        if (lph->lph_flag & LC_UDP) {
                    533:                                MGET(nam2, M_WAIT, MT_SONAME);
                    534:                                saddr = mtod(nam2, struct sockaddr_in *);
                    535:                                nam2->m_len = saddr->sin_len =
                    536:                                        sizeof (struct sockaddr_in);
                    537:                                saddr->sin_family = AF_INET;
                    538:                                saddr->sin_addr.s_addr = lph->lph_inetaddr;
                    539:                                saddr->sin_port = lph->lph_port;
                    540:                                so = nfs_udpsock->ns_so;
                    541:                        } else if (lph->lph_flag & LC_CLTP) {
                    542:                                nam2 = lph->lph_nam;
                    543:                                so = nfs_cltpsock->ns_so;
                    544:                        } else if (lph->lph_slp->ns_flag & SLP_VALID) {
                    545:                                nam2 = (struct mbuf *)0;
                    546:                                so = lph->lph_slp->ns_so;
                    547:                        } else
                    548:                                goto nextone;
                    549:                        sotype = so->so_type;
                    550:                        if (so->so_proto->pr_flags & PR_CONNREQUIRED)
                    551:                                solockp = &lph->lph_slp->ns_solock;
                    552:                        else
                    553:                                solockp = (int *)0;
                    554:                        nfsm_reqhead((struct vnode *)0, NQNFSPROC_EVICTED,
                    555:                                NFSX_V3FH + NFSX_UNSIGNED);
                    556:                        fhp = &nfh.fh_generic;
                    557:                        bzero((caddr_t)fhp, sizeof(nfh));
                    558:                        fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
                    559:                        VFS_VPTOFH(vp, &fhp->fh_fid);
                    560:                        nfsm_srvfhtom(fhp, 1);
                    561:                        m = mreq;
                    562:                        siz = 0;
                    563:                        while (m) {
                    564:                                siz += m->m_len;
                    565:                                m = m->m_next;
                    566:                        }
                    567:                        if (siz <= 0 || siz > NFS_MAXPACKET) {
                    568:                                printf("mbuf siz=%d\n",siz);
                    569:                                panic("Bad nfs svc reply");
                    570:                        }
                    571:                        m = nfsm_rpchead(cred, (NFSMNT_NFSV3 | NFSMNT_NQNFS),
                    572:                                NQNFSPROC_EVICTED,
                    573:                                RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0,
                    574:                                0, (char *)NULL, mreq, siz, &mheadend, &xid);
                    575:                        /*
                    576:                         * For stream protocols, prepend a Sun RPC
                    577:                         * Record Mark.
                    578:                         */
                    579:                        if (sotype == SOCK_STREAM) {
                    580:                                M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
                    581:                                *mtod(m, u_long *) = htonl(0x80000000 |
                    582:                                        (m->m_pkthdr.len - NFSX_UNSIGNED));
                    583:                        }
                    584:                        if (((lph->lph_flag & (LC_UDP | LC_CLTP)) == 0 &&
                    585:                            (lph->lph_slp->ns_flag & SLP_VALID) == 0) ||
                    586:                            (solockp && (*solockp & NFSMNT_SNDLOCK)))
                    587:                                m_freem(m);
                    588:                        else {
                    589:                                if (solockp)
                    590:                                        *solockp |= NFSMNT_SNDLOCK;
                    591:                                (void) nfs_send(so, nam2, m,
                    592:                                                (struct nfsreq *)0);
                    593:                                if (solockp)
                    594:                                        nfs_sndunlock(solockp);
                    595:                        }
                    596:                        if (lph->lph_flag & LC_UDP)
                    597:                                MFREE(nam2, m);
                    598:                }
                    599: nextone:
                    600:                if (++i == len) {
                    601:                        if (lphnext) {
                    602:                                i = 0;
                    603:                                len = LC_MOREHOSTSIZ;
                    604:                                lph = lphnext->lpm_hosts;
                    605:                                lphnext = lphnext->lpm_next;
                    606:                        } else
                    607:                                ok = 0;
                    608:                } else
                    609:                        lph++;
                    610:        }
                    611: }
                    612: 
                    613: /*
                    614:  * Wait for the lease to expire.
                    615:  * This will occur when all clients have sent "vacated" messages to
                    616:  * this server OR when it expires do to timeout.
                    617:  */
                    618: static void
                    619: nqsrv_waitfor_expiry(lp)
                    620:        register struct nqlease *lp;
                    621: {
                    622:        register struct nqhost *lph;
                    623:        register int i;
                    624:        struct nqm *lphnext;
                    625:        int len, ok;
                    626: 
                    627: tryagain:
                    628:        if (time.tv_sec > lp->lc_expiry)
                    629:                return;
                    630:        lph = &lp->lc_host;
                    631:        lphnext = lp->lc_morehosts;
                    632:        len = 1;
                    633:        i = 0;
                    634:        ok = 1;
                    635:        while (ok && (lph->lph_flag & LC_VALID)) {
                    636:                if ((lph->lph_flag & (LC_LOCAL | LC_VACATED)) == 0) {
                    637:                        lp->lc_flag |= LC_EXPIREDWANTED;
                    638:                        (void) tsleep((caddr_t)&lp->lc_flag, PSOCK,
                    639:                                        "nqexp", 0);
                    640:                        goto tryagain;
                    641:                }
                    642:                if (++i == len) {
                    643:                        if (lphnext) {
                    644:                                i = 0;
                    645:                                len = LC_MOREHOSTSIZ;
                    646:                                lph = lphnext->lpm_hosts;
                    647:                                lphnext = lphnext->lpm_next;
                    648:                        } else
                    649:                                ok = 0;
                    650:                } else
                    651:                        lph++;
                    652:        }
                    653: }
                    654: 
                    655: #ifndef NFS_NOSERVER
                    656: 
                    657: /*
                    658:  * Nqnfs server timer that maintains the server lease queue.
                    659:  * Scan the lease queue for expired entries:
                    660:  * - when one is found, wakeup anyone waiting for it
                    661:  *   else dequeue and free
                    662:  */
                    663: void
                    664: nqnfs_serverd()
                    665: {
                    666:        register struct nqlease *lp;
                    667:        register struct nqhost *lph;
                    668:        struct nqlease *nextlp;
                    669:        struct nqm *lphnext, *olphnext;
                    670:        struct mbuf *n;
                    671:        int i, len, ok;
                    672: 
                    673:        for (lp = nqtimerhead.cqh_first; lp != (void *)&nqtimerhead;
                    674:            lp = nextlp) {
                    675:                if (lp->lc_expiry >= time.tv_sec)
                    676:                        break;
                    677:                nextlp = lp->lc_timer.cqe_next;
                    678:                if (lp->lc_flag & LC_EXPIREDWANTED) {
                    679:                        lp->lc_flag &= ~LC_EXPIREDWANTED;
                    680:                        wakeup((caddr_t)&lp->lc_flag);
                    681:                } else if ((lp->lc_flag & (LC_LOCKED | LC_WANTED)) == 0) {
                    682:                    /*
                    683:                     * Make a best effort at keeping a write caching lease long
                    684:                     * enough by not deleting it until it has been explicitly
                    685:                     * vacated or there have been no writes in the previous
                    686:                     * write_slack seconds since expiry and the nfsds are not
                    687:                     * all busy. The assumption is that if the nfsds are not
                    688:                     * all busy now (no queue of nfs requests), then the client
                    689:                     * would have been able to do at least one write to the
                    690:                     * file during the last write_slack seconds if it was still
                    691:                     * trying to push writes to the server.
                    692:                     */
                    693:                    if ((lp->lc_flag & (LC_WRITE | LC_VACATED)) == LC_WRITE &&
                    694:                        ((lp->lc_flag & LC_WRITTEN) || nfsd_waiting == 0)) {
                    695:                        lp->lc_flag &= ~LC_WRITTEN;
                    696:                        nqsrv_instimeq(lp, nqsrv_writeslack);
                    697:                    } else {
                    698:                        CIRCLEQ_REMOVE(&nqtimerhead, lp, lc_timer);
                    699:                        LIST_REMOVE(lp, lc_hash);
                    700:                        /*
                    701:                         * This soft reference may no longer be valid, but
                    702:                         * no harm done. The worst case is if the vnode was
                    703:                         * recycled and has another valid lease reference,
                    704:                         * which is dereferenced prematurely.
                    705:                         */
                    706:                        lp->lc_vp->v_lease = (struct nqlease *)0;
                    707:                        lph = &lp->lc_host;
                    708:                        lphnext = lp->lc_morehosts;
                    709:                        olphnext = (struct nqm *)0;
                    710:                        len = 1;
                    711:                        i = 0;
                    712:                        ok = 1;
                    713:                        while (ok && (lph->lph_flag & LC_VALID)) {
                    714:                                if (lph->lph_flag & LC_CLTP)
                    715:                                        MFREE(lph->lph_nam, n);
                    716:                                if (lph->lph_flag & LC_SREF)
                    717:                                        nfsrv_slpderef(lph->lph_slp);
                    718:                                if (++i == len) {
                    719:                                        if (olphnext) {
                    720:                                                _FREE_ZONE((caddr_t)olphnext,
                    721:                                                        sizeof (struct nqm),
                    722:                                                                M_NQMHOST);
                    723:                                                olphnext = (struct nqm *)0;
                    724:                                        }
                    725:                                        if (lphnext) {
                    726:                                                olphnext = lphnext;
                    727:                                                i = 0;
                    728:                                                len = LC_MOREHOSTSIZ;
                    729:                                                lph = lphnext->lpm_hosts;
                    730:                                                lphnext = lphnext->lpm_next;
                    731:                                        } else
                    732:                                                ok = 0;
                    733:                                } else
                    734:                                        lph++;
                    735:                        }
                    736:                        FREE_ZONE((caddr_t)lp,
                    737:                                        sizeof (struct nqlease), M_NQLEASE);
                    738:                        if (olphnext)
                    739:                                _FREE_ZONE((caddr_t)olphnext,
                    740:                                        sizeof (struct nqm), M_NQMHOST);
                    741:                        nfsstats.srvnqnfs_leases--;
                    742:                    }
                    743:                }
                    744:        }
                    745: }
                    746: 
                    747: /*
                    748:  * Called from nfssvc_nfsd() for a getlease rpc request.
                    749:  * Do the from/to xdr translation and call nqsrv_getlease() to
                    750:  * do the real work.
                    751:  */
                    752: int
                    753: nqnfsrv_getlease(nfsd, slp, procp, mrq)
                    754:        struct nfsrv_descript *nfsd;
                    755:        struct nfssvc_sock *slp;
                    756:        struct proc *procp;
                    757:        struct mbuf **mrq;
                    758: {
                    759:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                    760:        struct mbuf *nam = nfsd->nd_nam;
                    761:        caddr_t dpos = nfsd->nd_dpos;
                    762:        struct ucred *cred = &nfsd->nd_cr;
                    763:        register struct nfs_fattr *fp;
                    764:        struct vattr va;
                    765:        register struct vattr *vap = &va;
                    766:        struct vnode *vp;
                    767:        nfsfh_t nfh;
                    768:        fhandle_t *fhp;
                    769:        register u_long *tl;
                    770:        register long t1;
                    771:        u_quad_t frev;
                    772:        caddr_t bpos;
                    773:        int error = 0;
                    774:        char *cp2;
                    775:        struct mbuf *mb, *mb2, *mreq;
                    776:        int flags, rdonly, cache;
                    777: 
                    778:        fhp = &nfh.fh_generic;
                    779:        nfsm_srvmtofh(fhp);
                    780:        nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
                    781:        flags = fxdr_unsigned(int, *tl++);
                    782:        nfsd->nd_duration = fxdr_unsigned(int, *tl);
                    783:        error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
                    784:                (nfsd->nd_flag & ND_KERBAUTH), TRUE);
                    785:        if (error)
                    786:                nfsm_reply(0);
                    787:        if (rdonly && flags == ND_WRITE) {
                    788:                error = EROFS;
                    789:                vput(vp);
                    790:                nfsm_reply(0);
                    791:        }
                    792:        (void) nqsrv_getlease(vp, &nfsd->nd_duration, flags, slp, procp,
                    793:                nam, &cache, &frev, cred);
                    794:        error = VOP_GETATTR(vp, vap, cred, procp);
                    795:        vput(vp);
                    796:        nfsm_reply(NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
                    797:        nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
                    798:        *tl++ = txdr_unsigned(cache);
                    799:        *tl++ = txdr_unsigned(nfsd->nd_duration);
                    800:        txdr_hyper(&frev, tl);
                    801:        nfsm_build(fp, struct nfs_fattr *, NFSX_V3FATTR);
                    802:        nfsm_srvfillattr(vap, fp);
                    803:        nfsm_srvdone;
                    804: }
                    805: 
                    806: /*
                    807:  * Called from nfssvc_nfsd() when a "vacated" message is received from a
                    808:  * client. Find the entry and expire it.
                    809:  */
                    810: int
                    811: nqnfsrv_vacated(nfsd, slp, procp, mrq)
                    812:        struct nfsrv_descript *nfsd;
                    813:        struct nfssvc_sock *slp;
                    814:        struct proc *procp;
                    815:        struct mbuf **mrq;
                    816: {
                    817:        struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
                    818:        struct mbuf *nam = nfsd->nd_nam;
                    819:        caddr_t dpos = nfsd->nd_dpos;
                    820:        register struct nqlease *lp;
                    821:        register struct nqhost *lph;
                    822:        struct nqlease *tlp = (struct nqlease *)0;
                    823:        nfsfh_t nfh;
                    824:        fhandle_t *fhp;
                    825:        register u_long *tl;
                    826:        register long t1;
                    827:        struct nqm *lphnext;
                    828:        struct mbuf *mreq, *mb;
                    829:        int error = 0, i, len, ok, gotit = 0, cache = 0;
                    830:        char *cp2, *bpos;
                    831:        u_quad_t frev;
                    832: 
                    833:        fhp = &nfh.fh_generic;
                    834:        nfsm_srvmtofh(fhp);
                    835:        m_freem(mrep);
                    836:        /*
                    837:         * Find the lease by searching the hash list.
                    838:         */
                    839:        for (lp = NQFHHASH(fhp->fh_fid.fid_data)->lh_first; lp != 0;
                    840:            lp = lp->lc_hash.le_next)
                    841:                if (fhp->fh_fsid.val[0] == lp->lc_fsid.val[0] &&
                    842:                    fhp->fh_fsid.val[1] == lp->lc_fsid.val[1] &&
                    843:                    !bcmp(fhp->fh_fid.fid_data, lp->lc_fiddata,
                    844:                          MAXFIDSZ)) {
                    845:                        /* Found it */
                    846:                        tlp = lp;
                    847:                        break;
                    848:                }
                    849:        if (tlp) {
                    850:                lp = tlp;
                    851:                len = 1;
                    852:                i = 0;
                    853:                lph = &lp->lc_host;
                    854:                lphnext = lp->lc_morehosts;
                    855:                ok = 1;
                    856:                while (ok && (lph->lph_flag & LC_VALID)) {
                    857:                        if (nqsrv_cmpnam(slp, nam, lph)) {
                    858:                                lph->lph_flag |= LC_VACATED;
                    859:                                gotit++;
                    860:                                break;
                    861:                        }
                    862:                        if (++i == len) {
                    863:                                if (lphnext) {
                    864:                                        len = LC_MOREHOSTSIZ;
                    865:                                        i = 0;
                    866:                                        lph = lphnext->lpm_hosts;
                    867:                                        lphnext = lphnext->lpm_next;
                    868:                                } else
                    869:                                        ok = 0;
                    870:                        } else
                    871:                                lph++;
                    872:                }
                    873:                if ((lp->lc_flag & LC_EXPIREDWANTED) && gotit) {
                    874:                        lp->lc_flag &= ~LC_EXPIREDWANTED;
                    875:                        wakeup((caddr_t)&lp->lc_flag);
                    876:                }
                    877: nfsmout:
                    878:                return (EPERM);
                    879:        }
                    880:        return (EPERM);
                    881: }
                    882: 
                    883: #endif /* NFS_NOSERVER */
                    884: 
                    885: /*
                    886:  * Client get lease rpc function.
                    887:  */
                    888: int
                    889: nqnfs_getlease(vp, rwflag, cred, p)
                    890:        register struct vnode *vp;
                    891:        int rwflag;
                    892:        struct ucred *cred;
                    893:        struct proc *p;
                    894: {
                    895:        register u_long *tl;
                    896:        register caddr_t cp;
                    897:        register long t1, t2;
                    898:        register struct nfsnode *np;
                    899:        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
                    900:        caddr_t bpos, dpos, cp2;
                    901:        time_t reqtime;
                    902:        int error = 0;
                    903:        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
                    904:        int cachable;
                    905:        u_quad_t frev;
                    906: 
                    907:        nfsstats.rpccnt[NQNFSPROC_GETLEASE]++;
                    908:        mb = mreq = nfsm_reqh(vp, NQNFSPROC_GETLEASE, NFSX_V3FH+2*NFSX_UNSIGNED,
                    909:                 &bpos);
                    910:        nfsm_fhtom(vp, 1);
                    911:        nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
                    912:        *tl++ = txdr_unsigned(rwflag);
                    913:        *tl = txdr_unsigned(nmp->nm_leaseterm);
                    914:        reqtime = time.tv_sec;
                    915:        nfsm_request(vp, NQNFSPROC_GETLEASE, p, cred);
                    916:        np = VTONFS(vp);
                    917:        nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
                    918:        cachable = fxdr_unsigned(int, *tl++);
                    919:        reqtime += fxdr_unsigned(int, *tl++);
                    920:        if (reqtime > time.tv_sec) {
                    921:                fxdr_hyper(tl, &frev);
                    922:                nqnfs_clientlease(nmp, np, rwflag, cachable, reqtime, frev);
                    923:                nfsm_loadattr(vp, (struct vattr *)0);
                    924:        } else
                    925:                error = NQNFS_EXPIRED;
                    926:        nfsm_reqdone;
                    927:        return (error);
                    928: }
                    929: 
                    930: /*
                    931:  * Client vacated message function.
                    932:  */
                    933: static int
                    934: nqnfs_vacated(vp, cred)
                    935:        register struct vnode *vp;
                    936:        struct ucred *cred;
                    937: {
                    938:        register caddr_t cp;
                    939:        register struct mbuf *m;
                    940:        register int i;
                    941:        register u_long *tl;
                    942:        register long t2;
                    943:        caddr_t bpos;
                    944:        u_long xid;
                    945:        int error = 0;
                    946:        struct mbuf *mreq, *mb, *mb2, *mheadend;
                    947:        struct nfsmount *nmp;
                    948:        struct nfsreq myrep;
                    949: 
                    950:        nmp = VFSTONFS(vp->v_mount);
                    951:        nfsstats.rpccnt[NQNFSPROC_VACATED]++;
                    952:        nfsm_reqhead(vp, NQNFSPROC_VACATED, NFSX_FH(1));
                    953:        nfsm_fhtom(vp, 1);
                    954:        m = mreq;
                    955:        i = 0;
                    956:        while (m) {
                    957:                i += m->m_len;
                    958:                m = m->m_next;
                    959:        }
                    960:        m = nfsm_rpchead(cred, nmp->nm_flag, NQNFSPROC_VACATED,
                    961:                RPCAUTH_UNIX, 5 * NFSX_UNSIGNED, (char *)0,
                    962:                0, (char *)NULL, mreq, i, &mheadend, &xid);
                    963:        if (nmp->nm_sotype == SOCK_STREAM) {
                    964:                M_PREPEND(m, NFSX_UNSIGNED, M_WAIT);
                    965:                *mtod(m, u_long *) = htonl(0x80000000 | (m->m_pkthdr.len -
                    966:                        NFSX_UNSIGNED));
                    967:        }
                    968:        myrep.r_flags = 0;
                    969:        myrep.r_nmp = nmp;
                    970:        if (nmp->nm_soflags & PR_CONNREQUIRED)
                    971:                (void) nfs_sndlock(&nmp->nm_flag, (struct nfsreq *)0);
                    972:        (void) nfs_send(nmp->nm_so, nmp->nm_nam, m, &myrep);
                    973:        if (nmp->nm_soflags & PR_CONNREQUIRED)
                    974:                nfs_sndunlock(&nmp->nm_flag);
                    975: nfsmout:
                    976:        return (error);
                    977: }
                    978: 
                    979: #ifndef NFS_NOSERVER 
                    980: 
                    981: /*
                    982:  * Called for client side callbacks
                    983:  */
                    984: int
                    985: nqnfs_callback(nmp, mrep, md, dpos)
                    986:        struct nfsmount *nmp;
                    987:        struct mbuf *mrep, *md;
                    988:        caddr_t dpos;
                    989: {
                    990:        register struct vnode *vp;
                    991:        register u_long *tl;
                    992:        register long t1;
                    993:        nfsfh_t nfh;
                    994:        fhandle_t *fhp;
                    995:        struct nfsnode *np;
                    996:        struct nfsd tnfsd;
                    997:        struct nfssvc_sock *slp;
                    998:        struct nfsrv_descript ndesc;
                    999:        register struct nfsrv_descript *nfsd = &ndesc;
                   1000:        struct mbuf **mrq = (struct mbuf **)0, *mb, *mreq;
                   1001:        int error = 0, cache = 0;
                   1002:        char *cp2, *bpos;
                   1003:        u_quad_t frev;
                   1004: 
                   1005: #ifndef nolint
                   1006:        slp = NULL;
                   1007: #endif
                   1008:        nfsd->nd_mrep = mrep;
                   1009:        nfsd->nd_md = md;
                   1010:        nfsd->nd_dpos = dpos;
                   1011:        error = nfs_getreq(nfsd, &tnfsd, FALSE);
                   1012:        if (error)
                   1013:                return (error);
                   1014:        md = nfsd->nd_md;
                   1015:        dpos = nfsd->nd_dpos;
                   1016:        if (nfsd->nd_procnum != NQNFSPROC_EVICTED) {
                   1017:                m_freem(mrep);
                   1018:                return (EPERM);
                   1019:        }
                   1020:        fhp = &nfh.fh_generic;
                   1021:        nfsm_srvmtofh(fhp);
                   1022:        m_freem(mrep);
                   1023:        error = nfs_nget(nmp->nm_mountp, (nfsfh_t *)fhp, NFSX_V3FH, &np);
                   1024:        if (error)
                   1025:                return (error);
                   1026:        vp = NFSTOV(np);
                   1027:        if (np->n_timer.cqe_next != 0) {
                   1028:                np->n_expiry = 0;
                   1029:                np->n_flag |= NQNFSEVICTED;
                   1030:                if (nmp->nm_timerhead.cqh_first != np) {
                   1031:                        CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
                   1032:                        CIRCLEQ_INSERT_HEAD(&nmp->nm_timerhead, np, n_timer);
                   1033:                }
                   1034:        }
                   1035:        vput(vp);
                   1036:        nfsm_srvdone;
                   1037: }
                   1038: 
                   1039: 
                   1040: /*
                   1041:  * Nqnfs client helper daemon. Runs once a second to expire leases.
                   1042:  * It also get authorization strings for "kerb" mounts.
                   1043:  * It must start at the beginning of the list again after any potential
                   1044:  * "sleep" since nfs_reclaim() called from vclean() can pull a node off
                   1045:  * the list asynchronously.
                   1046:  */
                   1047: int
                   1048: nqnfs_clientd(nmp, cred, ncd, flag, argp, p)
                   1049:        register struct nfsmount *nmp;
                   1050:        struct ucred *cred;
                   1051:        struct nfsd_cargs *ncd;
                   1052:        int flag;
                   1053:        caddr_t argp;
                   1054:        struct proc *p;
                   1055: {
                   1056:        register struct nfsnode *np;
                   1057:        struct vnode *vp;
                   1058:        struct nfsreq myrep;
                   1059:        struct nfsuid *nuidp, *nnuidp;
                   1060:        int error = 0, vpid;
                   1061:        register struct nfsreq *rp;
                   1062: 
                   1063:        /*
                   1064:         * First initialize some variables
                   1065:         */
                   1066: 
                   1067:        /*
                   1068:         * If an authorization string is being passed in, get it.
                   1069:         */
                   1070:        if ((flag & NFSSVC_GOTAUTH) &&
                   1071:            (nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_DISMNT)) == 0) {
                   1072:            if (nmp->nm_flag & NFSMNT_HASAUTH)
                   1073:                panic("cld kerb");
                   1074:            if ((flag & NFSSVC_AUTHINFAIL) == 0) {
                   1075:                if (ncd->ncd_authlen <= nmp->nm_authlen &&
                   1076:                    ncd->ncd_verflen <= nmp->nm_verflen &&
                   1077:                    !copyin(ncd->ncd_authstr,nmp->nm_authstr,ncd->ncd_authlen)&&
                   1078:                    !copyin(ncd->ncd_verfstr,nmp->nm_verfstr,ncd->ncd_verflen)){
                   1079:                    nmp->nm_authtype = ncd->ncd_authtype;
                   1080:                    nmp->nm_authlen = ncd->ncd_authlen;
                   1081:                    nmp->nm_verflen = ncd->ncd_verflen;
                   1082: #if NFSKERB
                   1083:                    nmp->nm_key = ncd->ncd_key;
                   1084: #endif
                   1085:                } else
                   1086:                    nmp->nm_flag |= NFSMNT_AUTHERR;
                   1087:            } else
                   1088:                nmp->nm_flag |= NFSMNT_AUTHERR;
                   1089:            nmp->nm_flag |= NFSMNT_HASAUTH;
                   1090:            wakeup((caddr_t)&nmp->nm_authlen);
                   1091:        } else
                   1092:            nmp->nm_flag |= NFSMNT_WAITAUTH;
                   1093: 
                   1094:        /*
                   1095:         * Loop every second updating queue until there is a termination sig.
                   1096:         */
                   1097:        while ((nmp->nm_flag & NFSMNT_DISMNT) == 0) {
                   1098:            if (nmp->nm_flag & NFSMNT_NQNFS) {
                   1099:                /*
                   1100:                 * If there are no outstanding requests (and therefore no
                   1101:                 * processes in nfs_reply) and there is data in the receive
                   1102:                 * queue, poke for callbacks.
                   1103:                 */
                   1104:                if (nfs_reqq.tqh_first == 0 && nmp->nm_so &&
                   1105:                    nmp->nm_so->so_rcv.sb_cc > 0) {
                   1106:                    myrep.r_flags = R_GETONEREP;
                   1107:                    myrep.r_nmp = nmp;
                   1108:                    myrep.r_mrep = (struct mbuf *)0;
                   1109:                    myrep.r_procp = (struct proc *)0;
                   1110:                    (void) nfs_reply(&myrep);
                   1111:                }
                   1112: 
                   1113:                /*
                   1114:                 * Loop through the leases, updating as required.
                   1115:                 */
                   1116:                np = nmp->nm_timerhead.cqh_first;
                   1117:                while (np != (void *)&nmp->nm_timerhead &&
                   1118:                       (nmp->nm_flag & NFSMNT_DISMINPROG) == 0) {
                   1119:                        vp = NFSTOV(np);
                   1120:                        vpid = vp->v_id;
                   1121:                        if (np->n_expiry < time.tv_sec) {
                   1122:                           if (vget(vp, LK_EXCLUSIVE, p) == 0) {
                   1123:                             nmp->nm_inprog = vp;
                   1124:                             if (vpid == vp->v_id) {
                   1125:                                CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
                   1126:                                np->n_timer.cqe_next = 0;
                   1127:                                if (np->n_flag & (NMODIFIED | NQNFSEVICTED)) {
                   1128:                                        if (np->n_flag & NQNFSEVICTED) {
                   1129:                                                if (vp->v_type == VDIR)
                   1130:                                                        nfs_invaldir(vp);
                   1131:                                                cache_purge(vp);
                   1132:                                                (void) nfs_vinvalbuf(vp,
                   1133:                                                       V_SAVE, cred, p, 0);
                   1134:                                                np->n_flag &= ~NQNFSEVICTED;
                   1135:                                                (void) nqnfs_vacated(vp, cred);
                   1136:                                        } else if (vp->v_type == VREG) {
                   1137:                                                (void) VOP_FSYNC(vp, cred,
                   1138:                                                    MNT_WAIT, p);
                   1139:                                                np->n_flag &= ~NMODIFIED;
                   1140:                                        }
                   1141:                                }
                   1142:                              }
                   1143:                              vrele(vp);
                   1144:                              nmp->nm_inprog = NULLVP;
                   1145:                            }
                   1146:                        } else if ((np->n_expiry - NQ_RENEWAL) < time.tv_sec) {
                   1147:                            if ((np->n_flag & (NQNFSWRITE | NQNFSNONCACHE))
                   1148:                                 == NQNFSWRITE && vp->v_dirtyblkhd.lh_first &&
                   1149:                                 vget(vp, LK_EXCLUSIVE, p) == 0) {
                   1150:                                 nmp->nm_inprog = vp;
                   1151:                                 if (vpid == vp->v_id &&
                   1152:                                     nqnfs_getlease(vp, ND_WRITE, cred, p)==0)
                   1153:                                        np->n_brev = np->n_lrev;
                   1154:                                 vrele(vp);
                   1155:                                 nmp->nm_inprog = NULLVP;
                   1156:                            }
                   1157:                        } else
                   1158:                                break;
                   1159:                        if (np == nmp->nm_timerhead.cqh_first)
                   1160:                                break;
                   1161:                        np = nmp->nm_timerhead.cqh_first;
                   1162:                }
                   1163:            }
                   1164: 
                   1165:            /*
                   1166:             * Get an authorization string, if required.
                   1167:             */
                   1168:            if ((nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_DISMNT | NFSMNT_HASAUTH)) == 0) {
                   1169:                ncd->ncd_authuid = nmp->nm_authuid;
                   1170:                if (copyout((caddr_t)ncd, argp, sizeof (struct nfsd_cargs)))
                   1171:                        nmp->nm_flag |= NFSMNT_WAITAUTH;
                   1172:                else
                   1173:                        return (ENEEDAUTH);
                   1174:            }
                   1175: 
                   1176:            /*
                   1177:             * Wait a bit (no pun) and do it again.
                   1178:             */
                   1179:            if ((nmp->nm_flag & NFSMNT_DISMNT) == 0 &&
                   1180:                (nmp->nm_flag & (NFSMNT_WAITAUTH | NFSMNT_HASAUTH))) {
                   1181:                    error = tsleep((caddr_t)&nmp->nm_authstr, PSOCK | PCATCH,
                   1182:                        "nqnfstimr", hz / 3);
                   1183:                    if (error == EINTR || error == ERESTART)
                   1184:                        (void) dounmount(nmp->nm_mountp, 0, p);
                   1185:            }
                   1186:        }
                   1187: 
                   1188:        /*
                   1189:         * Finally, we can free up the mount structure.
                   1190:         */
                   1191:        for (nuidp = nmp->nm_uidlruhead.tqh_first; nuidp != 0; nuidp = nnuidp) {
                   1192:                nnuidp = nuidp->nu_lru.tqe_next;
                   1193:                LIST_REMOVE(nuidp, nu_hash);
                   1194:                TAILQ_REMOVE(&nmp->nm_uidlruhead, nuidp, nu_lru);
                   1195:                _FREE_ZONE((caddr_t)nuidp, sizeof (struct nfsuid), M_NFSUID);
                   1196:        }
                   1197:        /*
                   1198:         * Loop through outstanding request list and remove dangling
                   1199:         * references to defunct nfsmount struct
                   1200:         */
                   1201:        for (rp = nfs_reqq.tqh_first; rp; rp = rp->r_chain.tqe_next)
                   1202:                if (rp->r_nmp == nmp)
                   1203:                        rp->r_nmp = (struct nfsmount *)0;
                   1204:        _FREE_ZONE((caddr_t)nmp, sizeof (struct nfsmount), M_NFSMNT);
                   1205:        if (error == EWOULDBLOCK)
                   1206:                error = 0;
                   1207:        return (error);
                   1208: }
                   1209: 
                   1210: #endif /* NFS_NOSERVER */
                   1211: 
                   1212: /*
                   1213:  * Adjust all timer queue expiry times when the time of day clock is changed.
                   1214:  * Called from the settimeofday() syscall.
                   1215:  */
                   1216: void
                   1217: nqnfs_lease_updatetime(deltat)
                   1218:        register int deltat;
                   1219: {
                   1220:        struct proc *p = current_proc();        /* XXX */
                   1221:        struct nqlease *lp;
                   1222:        struct nfsnode *np;
                   1223:        struct mount *mp, *nxtmp;
                   1224:        struct nfsmount *nmp;
                   1225:        int s;
                   1226: 
                   1227:        if (nqnfsstarttime != 0)
                   1228:                nqnfsstarttime += deltat;
                   1229:        s = splsoftclock();
                   1230:        for (lp = nqtimerhead.cqh_first; lp != (void *)&nqtimerhead;
                   1231:            lp = lp->lc_timer.cqe_next)
                   1232:                lp->lc_expiry += deltat;
                   1233:        splx(s);
                   1234: 
                   1235:        /*
                   1236:         * Search the mount list for all nqnfs mounts and do their timer
                   1237:         * queues.
                   1238:         */
                   1239:        simple_lock(&mountlist_slock);
                   1240:        for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nxtmp) {
                   1241:                if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
                   1242:                        nxtmp = mp->mnt_list.cqe_next;
                   1243:                        continue;
                   1244:                }
                   1245:                if (mp->mnt_stat.f_type == nfs_mount_type) {
                   1246:                        nmp = VFSTONFS(mp);
                   1247:                        if (nmp->nm_flag & NFSMNT_NQNFS) {
                   1248:                                for (np = nmp->nm_timerhead.cqh_first;
                   1249:                                    np != (void *)&nmp->nm_timerhead;
                   1250:                                    np = np->n_timer.cqe_next) {
                   1251:                                        np->n_expiry += deltat;
                   1252:                                }
                   1253:                        }
                   1254:                }
                   1255:                simple_lock(&mountlist_slock);
                   1256:                nxtmp = mp->mnt_list.cqe_next;
                   1257:                vfs_unbusy(mp, p);
                   1258:        }
                   1259:        simple_unlock(&mountlist_slock);
                   1260: }
                   1261: 
                   1262: /*
                   1263:  * Lock a server lease.
                   1264:  */
                   1265: static void
                   1266: nqsrv_locklease(lp)
                   1267:        struct nqlease *lp;
                   1268: {
                   1269: 
                   1270:        while (lp->lc_flag & LC_LOCKED) {
                   1271:                lp->lc_flag |= LC_WANTED;
                   1272:                (void) tsleep((caddr_t)lp, PSOCK, "nqlc", 0);
                   1273:        }
                   1274:        lp->lc_flag |= LC_LOCKED;
                   1275:        lp->lc_flag &= ~LC_WANTED;
                   1276: }
                   1277: 
                   1278: /*
                   1279:  * Unlock a server lease.
                   1280:  */
                   1281: static void
                   1282: nqsrv_unlocklease(lp)
                   1283:        struct nqlease *lp;
                   1284: {
                   1285: 
                   1286:        lp->lc_flag &= ~LC_LOCKED;
                   1287:        if (lp->lc_flag & LC_WANTED)
                   1288:                wakeup((caddr_t)lp);
                   1289: }
                   1290: 
                   1291: /*
                   1292:  * Update a client lease.
                   1293:  */
                   1294: void
                   1295: nqnfs_clientlease(nmp, np, rwflag, cachable, expiry, frev)
                   1296:        register struct nfsmount *nmp;
                   1297:        register struct nfsnode *np;
                   1298:        int rwflag, cachable;
                   1299:        time_t expiry;
                   1300:        u_quad_t frev;
                   1301: {
                   1302:        register struct nfsnode *tp;
                   1303: 
                   1304:        if (np->n_timer.cqe_next != 0) {
                   1305:                CIRCLEQ_REMOVE(&nmp->nm_timerhead, np, n_timer);
                   1306:                if (rwflag == ND_WRITE)
                   1307:                        np->n_flag |= NQNFSWRITE;
                   1308:        } else if (rwflag == ND_READ)
                   1309:                np->n_flag &= ~NQNFSWRITE;
                   1310:        else
                   1311:                np->n_flag |= NQNFSWRITE;
                   1312:        if (cachable)
                   1313:                np->n_flag &= ~NQNFSNONCACHE;
                   1314:        else
                   1315:                np->n_flag |= NQNFSNONCACHE;
                   1316:        np->n_expiry = expiry;
                   1317:        np->n_lrev = frev;
                   1318:        tp = nmp->nm_timerhead.cqh_last;
                   1319:        while (tp != (void *)&nmp->nm_timerhead && tp->n_expiry > np->n_expiry)
                   1320:                tp = tp->n_timer.cqe_prev;
                   1321:        if (tp == (void *)&nmp->nm_timerhead) {
                   1322:                CIRCLEQ_INSERT_HEAD(&nmp->nm_timerhead, np, n_timer);
                   1323:        } else {
                   1324:                CIRCLEQ_INSERT_AFTER(&nmp->nm_timerhead, tp, np, n_timer);
                   1325:        }
                   1326: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.