cf2645ac638682fa598f1ac006b3fa36e87dbbff
* Copyright (c) 1992 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Rick Macklem at The University of Guelph.
* %sccs.include.redist.c%
* @(#)nfs_nqlease.c 7.11 (Berkeley) %G%
* Cary G. Gray and David R. Cheriton, "Leases: An Efficient Fault-Tolerant
* Mechanism for Distributed File Cache Consistency",
* In Proc. of the Twelfth ACM Symposium on Operating Systems
* Principals, pg. 202-210, Litchfield Park, AZ, Dec. 1989.
* Michael N. Nelson, Brent B. Welch and John K. Ousterhout, "Caching
* in the Sprite Network File System", ACM TOCS 6(1),
* pages 134-154, February 1988.
* V. Srinivasan and Jeffrey C. Mogul, "Spritely NFS: Implementation and
* Performance of Cache-Consistency Protocols", Digital
* Equipment Corporation WRL Research Report 89/5, May 1989.
#include <sys/socketvar.h>
#include <nfs/nfsm_subs.h>
#include <nfs/xdr_subs.h>
#include <nfs/nfsmount.h>
* List head for the lease queue and other global data.
* At any time a lease is linked into a list ordered by increasing expiry time.
#define NQFHHASH(f) ((*((u_long *)(f)))&nqfheadhash)
union nqsrvthead nqthead
;
struct nqlease
**nqfhead
;
time_t nqnfsstarttime
= (time_t)0;
u_long nqnfs_prog
, nqnfs_vers
;
int nqsrv_clockskew
= NQ_CLOCKSKEW
;
int nqsrv_writeslack
= NQ_WRITESLACK
;
int nqsrv_maxlease
= NQ_MAXLEASE
;
int nqsrv_maxnumlease
= NQ_MAXNUMLEASE
;
void nqsrv_instimeq(), nqsrv_send_eviction(), nfs_sndunlock();
void nqsrv_unlocklease(), nqsrv_waitfor_expiry(), nfsrv_slpderef();
void nqsrv_addhost(), nqsrv_locklease(), nqnfs_serverd();
void nqnfs_clientlease();
struct mbuf
*nfsm_rpchead();
* Signifies which rpcs can have piggybacked lease requests
int nqnfs_piggy
[NFS_NPROCS
] = {
int nnnnnn
= sizeof (struct nqlease
);
int oooooo
= sizeof (struct nfsnode
);
extern nfstype nfs_type
[9];
extern struct nfssvc_sock
*nfs_udpsock
, *nfs_cltpsock
;
extern struct nfsd nfsd_head
;
* Get or check for a lease for "vp", based on NQL_CHECK flag.
* The rules are as follows:
* - if a current non-caching lease, reply non-caching
* - if a current lease for same host only, extend lease
* - if a read cachable lease and a read lease request
* add host to list any reply cachable
* - else { set non-cachable for read-write sharing }
* send eviction notice messages to all other hosts that have lease
* wait for lease termination { either by receiving vacated messages
* from all the other hosts or expiry
* modify lease to non-cachable
* - else if no current lease, issue new one
* - return boolean TRUE iff nam should be m_freem()'d
* NB: Since nqnfs_serverd() is called from a timer, any potential tsleep()
* in here must be framed by nqsrv_locklease() and nqsrv_unlocklease().
* nqsrv_locklease() is coded such that at least one of LC_LOCKED and
* LC_WANTED is set whenever a process is tsleeping in it. The exception
* is when a new lease is being allocated, since it is not in the timer
* queue yet. (Ditto for the splsoftclock() and splx(s) calls)
nqsrv_getlease(vp
, duration
, flags
, nd
, nam
, cachablep
, frev
, cred
)
register struct nqlease
*lp
, *lq
, **lpp
;
register struct nqhost
*lph
;
if (vp
->v_type
!= VREG
&& vp
->v_type
!= VDIR
&& vp
->v_type
!= VLNK
)
if (*duration
> nqsrv_maxlease
)
*duration
= nqsrv_maxlease
;
if (error
= VOP_GETATTR(vp
, &vattr
, cred
, nd
->nd_procp
))
*frev
= vattr
.va_filerev
;
if ((flags
& NQL_CHECK
) == 0)
nfsstats
.srvnqnfs_getleases
++;
if (tlp
== (struct nqlease
*)0) {
* Find the lease by searching the hash list.
fh
.fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
if (error
= VFS_VPTOFH(vp
, &fh
.fh_fid
)) {
lpp
= &nqfhead
[NQFHHASH(fh
.fh_fid
.fid_data
)];
for (lp
= *lpp
; lp
; lp
= lp
->lc_fhnext
)
if (fh
.fh_fsid
.val
[0] == lp
->lc_fsid
.val
[0] &&
fh
.fh_fsid
.val
[1] == lp
->lc_fsid
.val
[1] &&
!bcmp(fh
.fh_fid
.fid_data
, lp
->lc_fiddata
,
fh
.fh_fid
.fid_len
- sizeof (long))) {
if ((lp
->lc_flag
& LC_NONCACHABLE
) ||
(lp
->lc_morehosts
== (struct nqm
*)0 &&
nqsrv_cmpnam(nd
->nd_slp
, nam
, &lp
->lc_host
)))
if ((flags
& NQL_READ
) && (lp
->lc_flag
& LC_WRITE
)==0) {
if (nqsrv_cmpnam(nd
->nd_slp
, nam
, &lp
->lc_host
))
lph
= lp
->lc_morehosts
->lpm_hosts
;
lphp
= &lp
->lc_morehosts
->lpm_next
;
lphp
= &lp
->lc_morehosts
;
while (ok
&& (lph
->lph_flag
& LC_VALID
)) {
if (nqsrv_cmpnam(nd
->nd_slp
, nam
, lph
))
if (++i
== LC_MOREHOSTSIZ
) {
lph
= (*lphp
)->lpm_hosts
;
lphp
= &((*lphp
)->lpm_next
);
malloc(sizeof (struct nqm
),
bzero((caddr_t
)*lphp
, sizeof (struct nqm
));
lph
= (*lphp
)->lpm_hosts
;
nqsrv_addhost(lph
, nd
->nd_slp
, nam
);
lp
->lc_flag
|= LC_NONCACHABLE
;
nqsrv_send_eviction(vp
, lp
, nd
->nd_slp
, nam
, cred
);
nqsrv_waitfor_expiry(lp
);
* Update the lease and return
if ((flags
& NQL_CHECK
) == 0)
nqsrv_instimeq(lp
, *duration
);
if (lp
->lc_flag
& LC_NONCACHABLE
)
lp
->lc_flag
|= LC_WRITTEN
;
* The value of nqsrv_maxnumlease should be set generously, so that
* the following "printf" happens infrequently.
if (nfsstats
.srvnqnfs_leases
> nqsrv_maxnumlease
) {
printf("Nqnfs server, too many leases\n");
(void) tsleep((caddr_t
)&lbolt
, PSOCK
,
} while (nfsstats
.srvnqnfs_leases
> nqsrv_maxnumlease
);
MALLOC(lp
, struct nqlease
*, sizeof (struct nqlease
), M_NQLEASE
, M_WAITOK
);
bzero((caddr_t
)lp
, sizeof (struct nqlease
));
lp
->lc_flag
|= (LC_WRITE
| LC_WRITTEN
);
nqsrv_addhost(&lp
->lc_host
, nd
->nd_slp
, nam
);
lp
->lc_fsid
= fh
.fh_fsid
;
bcopy(fh
.fh_fid
.fid_data
, lp
->lc_fiddata
, fh
.fh_fid
.fid_len
- sizeof (long));
lq
->lc_fhprev
= &lp
->lc_fhnext
;
nqsrv_instimeq(lp
, *duration
);
if (++nfsstats
.srvnqnfs_leases
> nfsstats
.srvnqnfs_maxleases
)
nfsstats
.srvnqnfs_maxleases
= nfsstats
.srvnqnfs_leases
;
* Local lease check for server syscalls.
* Just set up args and let nqsrv_getlease() do the rest.
lease_check(vp
, p
, cred
, flag
)
nfsd
.nd_slp
= NQLOCALSLP
;
(void) nqsrv_getlease(vp
, &duration
, NQL_CHECK
| flag
, &nfsd
,
(struct mbuf
*)0, &cache
, &frev
, cred
);
* Add a host to an nqhost structure for a lease.
nqsrv_addhost(lph
, slp
, nam
)
register struct nqhost
*lph
;
register struct sockaddr_in
*saddr
;
lph
->lph_flag
|= (LC_VALID
| LC_LOCAL
);
else if (slp
== nfs_udpsock
) {
saddr
= mtod(nam
, struct sockaddr_in
*);
lph
->lph_flag
|= (LC_VALID
| LC_UDP
);
lph
->lph_inetaddr
= saddr
->sin_addr
.s_addr
;
lph
->lph_port
= saddr
->sin_port
;
} else if (slp
== nfs_cltpsock
) {
lph
->lph_nam
= m_copym(nam
, 0, M_COPYALL
, M_WAIT
);
lph
->lph_flag
|= (LC_VALID
| LC_CLTP
);
lph
->lph_flag
|= (LC_VALID
| LC_SREF
);
* Update the lease expiry time and position it in the timer queue correctly.
nqsrv_instimeq(lp
, duration
)
register struct nqlease
*lp
;
register struct nqlease
*tlp
;
newexpiry
= time
.tv_sec
+ duration
+ nqsrv_clockskew
;
if (lp
->lc_expiry
== newexpiry
)
lp
->lc_expiry
= newexpiry
;
* Find where in the queue it should be.
tlp
= nqthead
.th_chain
[1];
while (tlp
->lc_expiry
> newexpiry
&& tlp
!= (struct nqlease
*)&nqthead
)
if (tlp
== nqthead
.th_chain
[1])
NQSTORENOVRAM(newexpiry
);
* Compare the requesting host address with the lph entry in the lease.
* Return true iff it is the same.
* This is somewhat messy due to the union in the nqhost structure.
* The local host is indicated by the special value of NQLOCALSLP for slp.
nqsrv_cmpnam(slp
, nam
, lph
)
register struct nfssvc_sock
*slp
;
register struct nqhost
*lph
;
register struct sockaddr_in
*saddr
;
union nethostaddr lhaddr
;
if (lph
->lph_flag
& LC_LOCAL
)
if (slp
== nfs_udpsock
|| slp
== nfs_cltpsock
)
if (lph
->lph_flag
& LC_UDP
)
ret
= netaddr_match(AF_INET
, &lph
->lph_haddr
,
(union nethostaddr
*)0, addr
);
else if (lph
->lph_flag
& LC_CLTP
)
ret
= netaddr_match(AF_ISO
, &lph
->lph_claddr
,
(union nethostaddr
*)0, addr
);
if ((lph
->lph_slp
->ns_flag
& SLP_VALID
) == 0)
saddr
= mtod(lph
->lph_slp
->ns_nam
, struct sockaddr_in
*);
if (saddr
->sin_family
== AF_INET
)
lhaddr
.had_inetaddr
= saddr
->sin_addr
.s_addr
;
lhaddr
.had_nam
= lph
->lph_slp
->ns_nam
;
ret
= netaddr_match(saddr
->sin_family
, &lhaddr
,
(union nethostaddr
*)0, addr
);
* Send out eviction notice messages to all other hosts for the lease.
nqsrv_send_eviction(vp
, lp
, slp
, nam
, cred
)
register struct nqlease
*lp
;
register struct nqhost
*lph
= &lp
->lc_host
;
struct nqm
*lphnext
= lp
->lc_morehosts
;
struct mbuf
*mreq
, *mb
, *mb2
, *nam2
, *mheadend
;
struct sockaddr_in
*saddr
;
int len
= 1, ok
= 1, i
= 0;
while (ok
&& (lph
->lph_flag
& LC_VALID
)) {
if (nqsrv_cmpnam(slp
, nam
, lph
))
lph
->lph_flag
|= LC_VACATED
;
else if ((lph
->lph_flag
& (LC_LOCAL
| LC_VACATED
)) == 0) {
if (lph
->lph_flag
& LC_UDP
) {
MGET(nam2
, M_WAIT
, MT_SONAME
);
saddr
= mtod(nam2
, struct sockaddr_in
*);
nam2
->m_len
= saddr
->sin_len
=
sizeof (struct sockaddr_in
);
saddr
->sin_family
= AF_INET
;
saddr
->sin_addr
.s_addr
= lph
->lph_inetaddr
;
saddr
->sin_port
= lph
->lph_port
;
} else if (lph
->lph_flag
& LC_CLTP
) {
so
= nfs_cltpsock
->ns_so
;
} else if (lph
->lph_slp
->ns_flag
& SLP_VALID
) {
so
= lph
->lph_slp
->ns_so
;
if (so
->so_proto
->pr_flags
& PR_CONNREQUIRED
)
solockp
= &lph
->lph_slp
->ns_solock
;
nfsm_reqhead((struct vnode
*)0, NQNFSPROC_EVICTED
,
nfsm_build(cp
, caddr_t
, NFSX_FH
);
fhp
->fh_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
;
VFS_VPTOFH(vp
, &fhp
->fh_fid
);
if (siz
<= 0 || siz
> NFS_MAXPACKET
) {
printf("mbuf siz=%d\n",siz
);
panic("Bad nfs svc reply");
m
= nfsm_rpchead(cred
, TRUE
, NQNFSPROC_EVICTED
,
RPCAUTH_UNIX
, 5*NFSX_UNSIGNED
, (char *)0,
mreq
, siz
, &mheadend
, &xid
);
* For stream protocols, prepend a Sun RPC
if (sotype
== SOCK_STREAM
) {
M_PREPEND(m
, NFSX_UNSIGNED
, M_WAIT
);
*mtod(m
, u_long
*) = htonl(0x80000000 |
(m
->m_pkthdr
.len
- NFSX_UNSIGNED
));
if (((lph
->lph_flag
& (LC_UDP
| LC_CLTP
)) == 0 &&
(lph
->lph_slp
->ns_flag
& SLP_VALID
) == 0) ||
(solockp
&& (*solockp
& NFSMNT_SNDLOCK
)))
*solockp
|= NFSMNT_SNDLOCK
;
(void) nfs_send(so
, nam2
, m
,
if (lph
->lph_flag
& LC_UDP
)
lph
= lphnext
->lpm_hosts
;
lphnext
= lphnext
->lpm_next
;
* Wait for the lease to expire.
* This will occur when all clients have sent "vacated" messages to
* this server OR when it expires do to timeout.
register struct nqlease
*lp
;
register struct nqhost
*lph
;
if (time
.tv_sec
> lp
->lc_expiry
)
lphnext
= lp
->lc_morehosts
;
while (ok
&& (lph
->lph_flag
& LC_VALID
)) {
if ((lph
->lph_flag
& (LC_LOCAL
| LC_VACATED
)) == 0) {
lp
->lc_flag
|= LC_EXPIREDWANTED
;
(void) tsleep((caddr_t
)&lp
->lc_flag
, PSOCK
,
lph
= lphnext
->lpm_hosts
;
lphnext
= lphnext
->lpm_next
;
* Nqnfs server timer that maintains the server lease queue.
* Scan the lease queue for expired entries:
* - when one is found, wakeup anyone waiting for it
register struct nqlease
*lp
, *lq
;
register struct nqhost
*lph
;
struct nqm
*lphnext
, *olphnext
;
lp
= nqthead
.th_chain
[0];
while (lp
!= (struct nqlease
*)&nqthead
) {
if (lp
->lc_expiry
>= time
.tv_sec
)
nextlp
= lp
->lc_chain1
[0];
if (lp
->lc_flag
& LC_EXPIREDWANTED
) {
lp
->lc_flag
&= ~LC_EXPIREDWANTED
;
wakeup((caddr_t
)&lp
->lc_flag
);
} else if ((lp
->lc_flag
& (LC_LOCKED
| LC_WANTED
)) == 0) {
* Make a best effort at keeping a write caching lease long
* enough by not deleting it until it has been explicitly
* vacated or there have been no writes in the previous
* write_slack seconds since expiry and the nfsds are not
* all busy. The assumption is that if the nfsds are not
* all busy now (no queue of nfs requests), then the client
* would have been able to do at least one write to the
* file during the last write_slack seconds if it was still
* trying to push writes to the server.
if ((lp
->lc_flag
& (LC_WRITE
| LC_VACATED
)) == LC_WRITE
&&
((lp
->lc_flag
& LC_WRITTEN
) || nfsd_waiting
== 0)) {
lp
->lc_flag
&= ~LC_WRITTEN
;
nqsrv_instimeq(lp
, nqsrv_writeslack
);
lq
->lc_fhprev
= lp
->lc_fhprev
;
* This soft reference may no longer be valid, but
* no harm done. The worst case is if the vnode was
* recycled and has another valid lease reference,
* which is dereferenced prematurely.
lp
->lc_vp
->v_lease
= (struct nqlease
*)0;
lphnext
= lp
->lc_morehosts
;
olphnext
= (struct nqm
*)0;
while (ok
&& (lph
->lph_flag
& LC_VALID
)) {
if (lph
->lph_flag
& LC_CLTP
)
if (lph
->lph_flag
& LC_SREF
)
nfsrv_slpderef(lph
->lph_slp
);
free((caddr_t
)olphnext
, M_NQMHOST
);
olphnext
= (struct nqm
*)0;
lph
= lphnext
->lpm_hosts
;
lphnext
= lphnext
->lpm_next
;
FREE((caddr_t
)lp
, M_NQLEASE
);
free((caddr_t
)olphnext
, M_NQMHOST
);
nfsstats
.srvnqnfs_leases
--;
* Called from nfssvc_nfsd() for a getlease rpc request.
* Do the from/to xdr translation and call nqsrv_getlease() to
nqnfsrv_getlease(nfsd
, mrep
, md
, dpos
, cred
, nam
, mrq
)
register struct nfsv2_fattr
*fp
;
register struct vattr
*vap
= &va
;
struct mbuf
*mb
, *mb2
, *mreq
;
int flags
, rdonly
, cache
;
nfsm_dissect(tl
, u_long
*, 2*NFSX_UNSIGNED
);
flags
= fxdr_unsigned(int, *tl
++);
nfsd
->nd_duration
= fxdr_unsigned(int, *tl
);
if (error
= nfsrv_fhtovp(fhp
, TRUE
, &vp
, cred
, nfsd
->nd_slp
, nam
, &rdonly
))
if (rdonly
&& flags
== NQL_WRITE
) {
(void) nqsrv_getlease(vp
, &nfsd
->nd_duration
, flags
, nfsd
,
nam
, &cache
, &frev
, cred
);
error
= VOP_GETATTR(vp
, vap
, cred
, nfsd
->nd_procp
);
nfsm_reply(NFSX_NQFATTR
+ 4*NFSX_UNSIGNED
);
nfsm_build(tl
, u_long
*, 4*NFSX_UNSIGNED
);
*tl
++ = txdr_unsigned(cache
);
*tl
++ = txdr_unsigned(nfsd
->nd_duration
);
nfsm_build(fp
, struct nfsv2_fattr
*, NFSX_NQFATTR
);
* Called from nfssvc_nfsd() when a "vacated" message is received from a
* client. Find the entry and expire it.
nqnfsrv_vacated(nfsd
, mrep
, md
, dpos
, cred
, nam
, mrq
)
register struct nqlease
*lp
;
register struct nqhost
*lph
;
struct nqlease
*tlp
= (struct nqlease
*)0;
int error
= 0, i
, len
, ok
, rdonly
, gotit
= 0;
if (error
= nfsrv_fhtovp(fhp
, FALSE
, &vp
, cred
, nfsd
->nd_slp
, nam
, &rdonly
))
if (tlp
== (struct nqlease
*)0) {
* Find the lease by searching the hash list.
for (lp
= nqfhead
[NQFHHASH(fhp
->fh_fid
.fid_data
)]; lp
;
if (fhp
->fh_fsid
.val
[0] == lp
->lc_fsid
.val
[0] &&
fhp
->fh_fsid
.val
[1] == lp
->lc_fsid
.val
[1] &&
!bcmp(fhp
->fh_fid
.fid_data
, lp
->lc_fiddata
,
lphnext
= lp
->lc_morehosts
;
while (ok
&& (lph
->lph_flag
& LC_VALID
)) {
if (nqsrv_cmpnam(nfsd
->nd_slp
, nam
, lph
)) {
lph
->lph_flag
|= LC_VACATED
;
lph
= lphnext
->lpm_hosts
;
lphnext
= lphnext
->lpm_next
;
if ((lp
->lc_flag
& LC_EXPIREDWANTED
) && gotit
) {
lp
->lc_flag
&= ~LC_EXPIREDWANTED
;
wakeup((caddr_t
)&lp
->lc_flag
);
* Client get lease rpc function.
nqnfs_getlease(vp
, rwflag
, cred
, p
)
register struct vnode
*vp
;
register struct nfsnode
*np
, *tp
;
struct nfsmount
*nmp
= VFSTONFS(vp
->v_mount
);
struct mbuf
*mreq
, *mrep
, *md
, *mb
, *mb2
;
nfsstats
.rpccnt
[NQNFSPROC_GETLEASE
]++;
mb
= mreq
= nfsm_reqh(vp
, NQNFSPROC_GETLEASE
, NFSX_FH
+2*NFSX_UNSIGNED
,
nfsm_build(tl
, u_long
*, 2*NFSX_UNSIGNED
);
*tl
++ = txdr_unsigned(rwflag
);
*tl
= txdr_unsigned(nmp
->nm_leaseterm
);
nfsm_request(vp
, NQNFSPROC_GETLEASE
, p
, cred
);
nfsm_dissect(tl
, u_long
*, 4*NFSX_UNSIGNED
);
cachable
= fxdr_unsigned(int, *tl
++);
reqtime
+= fxdr_unsigned(int, *tl
++);
if (reqtime
> time
.tv_sec
) {
nqnfs_clientlease(nmp
, np
, rwflag
, cachable
, reqtime
, frev
);
nfsm_loadattr(vp
, (struct vattr
*)0);
* Client vacated message function.
register struct vnode
*vp
;
struct mbuf
*mreq
, *mb
, *mb2
, *mheadend
;
nmp
= VFSTONFS(vp
->v_mount
);
nfsstats
.rpccnt
[NQNFSPROC_VACATED
]++;
nfsm_reqhead(vp
, NQNFSPROC_VACATED
, NFSX_FH
);
m
= nfsm_rpchead(cred
, TRUE
, NQNFSPROC_VACATED
,
RPCAUTH_UNIX
, 5*NFSX_UNSIGNED
, (char *)0,
mreq
, i
, &mheadend
, &xid
);
if (nmp
->nm_sotype
== SOCK_STREAM
) {
M_PREPEND(m
, NFSX_UNSIGNED
, M_WAIT
);
*mtod(m
, u_long
*) = htonl(0x80000000 | (m
->m_pkthdr
.len
-
if (nmp
->nm_soflags
& PR_CONNREQUIRED
)
(void) nfs_sndlock(&nmp
->nm_flag
, (struct nfsreq
*)0);
(void) nfs_send(nmp
->nm_so
, nmp
->nm_nam
, m
, &myrep
);
if (nmp
->nm_soflags
& PR_CONNREQUIRED
)
nfs_sndunlock(&nmp
->nm_flag
);
* Called for client side callbacks
nqnfs_callback(nmp
, mrep
, md
, dpos
)
register struct vnode
*vp
;
if (error
= nfs_getreq(&nd
, FALSE
))
if (nd
.nd_procnum
!= NQNFSPROC_EVICTED
) {
if (error
= nfs_nget(nmp
->nm_mountp
, fhp
, &np
))
np
->n_flag
|= NQNFSEVICTED
;
if (np
->n_tprev
!= (struct nfsnode
*)nmp
) {
if (np
->n_tnext
== (struct nfsnode
*)nmp
)
nmp
->nm_tprev
= np
->n_tprev
;
np
->n_tnext
->n_tprev
= np
->n_tprev
;
np
->n_tprev
->n_tnext
= np
->n_tnext
;
np
->n_tnext
= nmp
->nm_tnext
;
np
->n_tprev
= (struct nfsnode
*)nmp
;
if (np
->n_tnext
== (struct nfsnode
*)nmp
)
np
->n_tnext
->n_tprev
= np
;
* Nqnfs client helper daemon. Runs once a second to expire leases.
* It also get authorization strings for "kerb" mounts.
* It must start at the beginning of the list again after any potential
* "sleep" since nfs_reclaim() called from vclean() can pull a node off
* the list asynchronously.
nqnfs_clientd(nmp
, cred
, ncd
, flag
, argp
, p
)
register struct nfsmount
*nmp
;
register struct nfsnode
*np
;
* First initialize some variables
nqnfs_prog
= txdr_unsigned(NQNFS_PROG
);
nqnfs_vers
= txdr_unsigned(NQNFS_VER1
);
* If an authorization string is being passed in, get it.
if ((flag
& NFSSVC_GOTAUTH
) &&
(nmp
->nm_flag
& (NFSMNT_WAITAUTH
| NFSMNT_DISMNT
)) == 0) {
if (nmp
->nm_flag
& NFSMNT_HASAUTH
)
if ((flag
& NFSSVC_AUTHINFAIL
) == 0) {
if (ncd
->ncd_authlen
<= RPCAUTH_MAXSIZ
&&
copyin(ncd
->ncd_authstr
, nmp
->nm_authstr
,
ncd
->ncd_authlen
) == 0) {
nmp
->nm_authtype
= ncd
->ncd_authtype
;
nmp
->nm_authlen
= ncd
->ncd_authlen
;
nmp
->nm_flag
|= NFSMNT_AUTHERR
;
nmp
->nm_flag
|= NFSMNT_AUTHERR
;
nmp
->nm_flag
|= NFSMNT_HASAUTH
;
wakeup((caddr_t
)&nmp
->nm_authlen
);
nmp
->nm_flag
|= NFSMNT_WAITAUTH
;
* Loop every second updating queue until there is a termination sig.
while ((nmp
->nm_flag
& NFSMNT_DISMNT
) == 0) {
if (nmp
->nm_flag
& NFSMNT_NQNFS
) {
while (np
!= (struct nfsnode
*)nmp
&&
(nmp
->nm_flag
& NFSMNT_DISMINPROG
) == 0) {
if (vp
->v_mount
->mnt_stat
.f_fsid
.val
[1] != MOUNT_NFS
) panic("trash2");
if (np
->n_expiry
< time
.tv_sec
) {
if (vp
->v_mount
->mnt_stat
.f_fsid
.val
[1] != MOUNT_NFS
) panic("trash3");
if (np
->n_tnext
== (struct nfsnode
*)nmp
)
nmp
->nm_tprev
= np
->n_tprev
;
np
->n_tnext
->n_tprev
= np
->n_tprev
;
if (np
->n_tprev
== (struct nfsnode
*)nmp
)
nmp
->nm_tnext
= np
->n_tnext
;
np
->n_tprev
->n_tnext
= np
->n_tnext
;
np
->n_tnext
= (struct nfsnode
*)0;
if ((np
->n_flag
& (NMODIFIED
| NQNFSEVICTED
))
np
->n_flag
&= ~NMODIFIED
;
if (np
->n_flag
& NQNFSEVICTED
) {
(void) vinvalbuf(vp
, TRUE
,
np
->n_flag
&= ~NQNFSEVICTED
;
(void) nqnfs_vacated(vp
, cred
);
(void) VOP_FSYNC(vp
, cred
,
} else if ((np
->n_expiry
- NQ_RENEWAL
) < time
.tv_sec
) {
if ((np
->n_flag
& (NQNFSWRITE
| NQNFSNONCACHE
))
== NQNFSWRITE
&& vp
->v_dirtyblkhd
&&
if (vp
->v_mount
->mnt_stat
.f_fsid
.val
[1] != MOUNT_NFS
) panic("trash4");
nqnfs_getlease(vp
, NQL_WRITE
, cred
, p
)==0)
* Get an authorization string, if required.
if ((nmp
->nm_flag
& (NFSMNT_WAITAUTH
| NFSMNT_DISMNT
| NFSMNT_HASAUTH
)) == 0) {
ncd
->ncd_authuid
= nmp
->nm_authuid
;
if (copyout((caddr_t
)ncd
, argp
, sizeof (*ncd
)))
nmp
->nm_flag
|= NFSMNT_WAITAUTH
;
* Wait a bit (no pun) and do it again.
if ((nmp
->nm_flag
& NFSMNT_DISMNT
) == 0 &&
(nmp
->nm_flag
& (NFSMNT_WAITAUTH
| NFSMNT_HASAUTH
))) {
error
= tsleep((caddr_t
)&nmp
->nm_authstr
, PSOCK
| PCATCH
,
if (error
== EINTR
|| error
== ERESTART
)
(void) dounmount(nmp
->nm_mountp
, MNT_NOFORCE
);
free((caddr_t
)nmp
, M_NFSMNT
);
if (error
== EWOULDBLOCK
)
* Adjust all timer queue expiry times when the time of day clock is changed.
* Called from the settimeofday() syscall.
register struct nqlease
*lp
;
register struct nfsnode
*np
;
nqnfsstarttime
+= deltat
;
lp
= nqthead
.th_chain
[0];
while (lp
!= (struct nqlease
*)&nqthead
) {
* Search the mount list for all nqnfs mounts and do their timer
if (mp
->mnt_stat
.f_fsid
.val
[1] == MOUNT_NFS
) {
if (nmp
->nm_flag
& NFSMNT_NQNFS
) {
while (np
!= (struct nfsnode
*)nmp
) {
while (lp
->lc_flag
& LC_LOCKED
) {
lp
->lc_flag
|= LC_WANTED
;
(void) tsleep((caddr_t
)lp
, PSOCK
, "nqlc", 0);
lp
->lc_flag
|= LC_LOCKED
;
lp
->lc_flag
&= ~LC_WANTED
;
lp
->lc_flag
&= ~LC_LOCKED
;
if (lp
->lc_flag
& LC_WANTED
)
nqnfs_clientlease(nmp
, np
, rwflag
, cachable
, expiry
, frev
)
register struct nfsmount
*nmp
;
register struct nfsnode
*np
;
register struct nfsnode
*tp
;
if (np
->n_tnext
== (struct nfsnode
*)nmp
)
nmp
->nm_tprev
= np
->n_tprev
;
np
->n_tnext
->n_tprev
= np
->n_tprev
;
if (np
->n_tprev
== (struct nfsnode
*)nmp
)
nmp
->nm_tnext
= np
->n_tnext
;
np
->n_tprev
->n_tnext
= np
->n_tnext
;
np
->n_flag
|= NQNFSWRITE
;
} else if (rwflag
== NQL_READ
)
np
->n_flag
&= ~NQNFSWRITE
;
np
->n_flag
|= NQNFSWRITE
;
np
->n_flag
&= ~NQNFSNONCACHE
;
np
->n_flag
|= NQNFSNONCACHE
;
while (tp
!= (struct nfsnode
*)nmp
&& tp
->n_expiry
> np
->n_expiry
)
if (tp
== (struct nfsnode
*)nmp
) {
np
->n_tnext
= nmp
->nm_tnext
;
np
->n_tnext
= tp
->n_tnext
;
if (np
->n_tnext
== (struct nfsnode
*)nmp
)
np
->n_tnext
->n_tprev
= np
;