diff options
Diffstat (limited to 'sys/fs/nfs/nfs_commonsubs.c')
-rw-r--r-- | sys/fs/nfs/nfs_commonsubs.c | 110 |
1 files changed, 84 insertions, 26 deletions
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c index 5c50dfd..b94091c 100644 --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -1733,6 +1733,23 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, } attrsum += NFSX_HYPER; break; + case NFSATTRBIT_SUPPATTREXCLCREAT: + retnotsup = 0; + error = nfsrv_getattrbits(nd, &retattrbits, + &cnt, &retnotsup); + if (error) + goto nfsmout; + if (compare && !(*retcmpp)) { + NFSSETSUPP_ATTRBIT(&checkattrbits); + NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits); + NFSCLRBIT_ATTRBIT(&checkattrbits, + NFSATTRBIT_TIMEACCESSSET); + if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) + || retnotsup) + *retcmpp = NFSERR_NOTSAME; + } + attrsum += cnt; + break; default: printf("EEK! nfsv4_loadattr unknown attr=%d\n", bitpos); @@ -2469,6 +2486,12 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, txdr_hyper(uquad, tl); retnum += NFSX_HYPER; break; + case NFSATTRBIT_SUPPATTREXCLCREAT: + NFSSETSUPP_ATTRBIT(&attrbits); + NFSCLRNOTSETABLE_ATTRBIT(&attrbits); + NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET); + retnum += nfsrv_putattrbit(nd, &attrbits); + break; default: printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); }; @@ -3663,6 +3686,9 @@ nfsmout: /* * Handle an NFSv4.1 Sequence request for the session. + * If reply != NULL, use it to return the cached reply, as required. + * The client gets a cached reply via this call for callbacks, however the + * server gets a cached reply via the nfsv4_seqsess_cachereply() call. */ int nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, @@ -3671,7 +3697,8 @@ nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, int error; error = 0; - *reply = NULL; + if (reply != NULL) + *reply = NULL; if (slotid > maxslot) return (NFSERR_BADSLOT); if (seqid == slots[slotid].nfssl_seq) { @@ -3679,13 +3706,18 @@ nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, if (slots[slotid].nfssl_inprog != 0) error = NFSERR_DELAY; else if (slots[slotid].nfssl_reply != NULL) { - *reply = slots[slotid].nfssl_reply; - slots[slotid].nfssl_reply = NULL; + if (reply != NULL) { + *reply = slots[slotid].nfssl_reply; + slots[slotid].nfssl_reply = NULL; + } slots[slotid].nfssl_inprog = 1; + error = NFSERR_REPLYFROMCACHE; } else - error = NFSERR_SEQMISORDERED; + /* No reply cached, so just do it. */ + slots[slotid].nfssl_inprog = 1; } else if ((slots[slotid].nfssl_seq + 1) == seqid) { - m_freem(slots[slotid].nfssl_reply); + if (slots[slotid].nfssl_reply != NULL) + m_freem(slots[slotid].nfssl_reply); slots[slotid].nfssl_reply = NULL; slots[slotid].nfssl_inprog = 1; slots[slotid].nfssl_seq++; @@ -3696,12 +3728,22 @@ nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, /* * Cache this reply for the slot. + * Use the "rep" argument to return the cached reply if repstat is set to + * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value. */ void -nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, struct mbuf *rep) +nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat, + struct mbuf **rep) { - slots[slotid].nfssl_reply = rep; + if (repstat == NFSERR_REPLYFROMCACHE) { + *rep = slots[slotid].nfssl_reply; + slots[slotid].nfssl_reply = NULL; + } else { + if (slots[slotid].nfssl_reply != NULL) + m_freem(slots[slotid].nfssl_reply); + slots[slotid].nfssl_reply = *rep; + } slots[slotid].nfssl_inprog = 0; } @@ -3713,9 +3755,36 @@ nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd, struct nfsclsession *sep, int dont_replycache) { uint32_t *tl, slotseq = 0; + int error, maxslot, slotpos; + uint8_t sessionid[NFSX_V4SESSIONID]; + + error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq, + sessionid); + if (error != 0) + return; + KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot")); + + /* Build the Sequence arguments. */ + NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); + bcopy(sessionid, tl, NFSX_V4SESSIONID); + tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; + nd->nd_slotseq = tl; + *tl++ = txdr_unsigned(slotseq); + *tl++ = txdr_unsigned(slotpos); + *tl++ = txdr_unsigned(maxslot); + if (dont_replycache == 0) + *tl = newnfs_true; + else + *tl = newnfs_false; + nd->nd_flag |= ND_HASSEQUENCE; +} + +int +nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep, + int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid) +{ int i, maxslot, slotpos; uint64_t bitval; - uint8_t sessionid[NFSX_V4SESSIONID]; /* Find an unused slot. */ slotpos = -1; @@ -3728,7 +3797,7 @@ nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd, slotpos = i; sep->nfsess_slots |= bitval; sep->nfsess_slotseq[i]++; - slotseq = sep->nfsess_slotseq[i]; + *slotseqp = sep->nfsess_slotseq[i]; break; } bitval <<= 1; @@ -3739,10 +3808,11 @@ nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd, * This RPC attempt will fail when it calls * newnfs_request(). */ - if ((nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) + if (nmp != NULL && + (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { mtx_unlock(&sep->nfsess_mtx); - return; + return (ESTALE); } /* Wake up once/sec, to check for a forced dismount. */ (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx, @@ -3758,21 +3828,9 @@ nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd, } bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID); mtx_unlock(&sep->nfsess_mtx); - KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot")); - - /* Build the Sequence arguments. */ - NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); - bcopy(sessionid, tl, NFSX_V4SESSIONID); - tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; - nd->nd_slotseq = tl; - *tl++ = txdr_unsigned(slotseq); - *tl++ = txdr_unsigned(slotpos); - *tl++ = txdr_unsigned(maxslot); - if (dont_replycache == 0) - *tl = newnfs_true; - else - *tl = newnfs_false; - nd->nd_flag |= ND_HASSEQUENCE; + *slotposp = slotpos; + *maxslotp = maxslot; + return (0); } /* |