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

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

unix.superglobalmegacorp.com

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