diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c index 144b2e215496..58d517b0b13d 100644 --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -215,7 +215,7 @@ static struct nfsrv_lughash *nfsgroupnamehash; static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 1, 0 }; + 1, 0, 0, 1, 0, 0, 0, 0 }; /* local functions */ static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep); @@ -299,6 +299,9 @@ static struct { { NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, }, { NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, }, { NFSV4OP_BINDCONNTOSESS, 1, "BindConSess", 11, }, + { NFSV4OP_LOOKUP, 5, "LookupOpen", 10, }, + { NFSV4OP_DEALLOCATE, 2, "Deallocate", 10, }, + { NFSV4OP_LAYOUTERROR, 1, "LayoutError", 11, }, }; /* @@ -307,7 +310,8 @@ static struct { static int nfs_bigrequest[NFSV42_NPROCS] = { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0 }; /* diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h index cb82666ab397..5dcce15f7f64 100644 --- a/sys/fs/nfs/nfsport.h +++ b/sys/fs/nfs/nfsport.h @@ -415,10 +415,19 @@ /* BindConnectionToSession, done by the krpc for a new connection. */ #define NFSPROC_BINDCONNTOSESS 65 +/* Do a Lookup+Open for "oneopenown". */ +#define NFSPROC_LOOKUPOPEN 66 + +/* Do an NFSv4.2 Deallocate. */ +#define NFSPROC_DEALLOCATE 67 + +/* Do an NFSv4.2 LayoutError. */ +#define NFSPROC_LAYOUTERROR 68 + /* * Must be defined as one higher than the last NFSv4.2 Proc# above. */ -#define NFSV42_NPROCS 66 +#define NFSV42_NPROCS 69 #endif /* NFS_V3NPROCS */ @@ -447,7 +456,7 @@ struct nfsstatsv1 { uint64_t readlink_bios; uint64_t biocache_readdirs; uint64_t readdir_bios; - uint64_t rpccnt[NFSV42_NPROCS + 14]; + uint64_t rpccnt[NFSV42_NPROCS + 11]; uint64_t rpcretries; uint64_t srvrpccnt[NFSV42_NOPS + NFSV4OP_FAKENOPS + 15]; uint64_t reserved_0; @@ -512,7 +521,7 @@ struct nfsstatsov1 { uint64_t readlink_bios; uint64_t biocache_readdirs; uint64_t readdir_bios; - uint64_t rpccnt[NFSV42_NPROCS + 3]; + uint64_t rpccnt[NFSV42_NPROCS]; uint64_t rpcretries; uint64_t srvrpccnt[NFSV42_PURENOPS + NFSV4OP_FAKENOPS]; uint64_t reserved_0; diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h index 13e146154805..968cc6a41cc3 100644 --- a/sys/fs/nfs/nfsproto.h +++ b/sys/fs/nfs/nfsproto.h @@ -396,10 +396,19 @@ /* BindConnectionToSession, done by the krpc for a new connection. */ #define NFSPROC_BINDCONNTOSESS 65 +/* Do a Lookup+Open for "oneopenown". */ +#define NFSPROC_LOOKUPOPEN 66 + +/* Do an NFSv4.2 Deallocate. */ +#define NFSPROC_DEALLOCATE 67 + +/* Do an NFSv4.2 LayoutError. */ +#define NFSPROC_LAYOUTERROR 68 + /* * Must be defined as one higher than the last NFSv4.2 Proc# above. */ -#define NFSV42_NPROCS 66 +#define NFSV42_NPROCS 69 #endif /* NFS_V3NPROCS */ diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index 6489569f8acf..b616cd729ab1 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -147,6 +147,9 @@ static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *, u_int32_t, struct ucred *, NFSPROC_T *, int); static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *, struct acl *, nfsv4stateid_t *, void *); +static int nfsrpc_layouterror(struct nfsmount *, uint8_t *, int, uint64_t, + uint64_t, nfsv4stateid_t *, struct ucred *, NFSPROC_T *, uint32_t, + uint32_t, char *); static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int, uint32_t, uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **, struct ucred *, NFSPROC_T *); @@ -5459,6 +5462,44 @@ nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, return (error); } +/* + * Do the NFSv4.2 LayoutError. + */ +static int +nfsrpc_layouterror(struct nfsmount *nmp, uint8_t *fh, int fhlen, uint64_t offset, + uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, + uint32_t stat, uint32_t op, char *devid) +{ + uint32_t *tl; + struct nfsrv_descript nfsd, *nd = &nfsd; + int error; + + nfscl_reqstart(nd, NFSPROC_LAYOUTERROR, nmp, fh, fhlen, NULL, NULL, + 0, 0); + NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + + NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); + txdr_hyper(offset, tl); tl += 2; + txdr_hyper(len, tl); tl += 2; + *tl++ = txdr_unsigned(stateidp->seqid); + *tl++ = stateidp->other[0]; + *tl++ = stateidp->other[1]; + *tl++ = stateidp->other[2]; + *tl++ = txdr_unsigned(1); + NFSBCOPY(devid, tl, NFSX_V4DEVICEID); + tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); + *tl++ = txdr_unsigned(stat); + *tl = txdr_unsigned(op); + nd->nd_flag |= ND_USEGSSNAME; + error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, + NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); + if (error != 0) + return (error); + if (nd->nd_repstat != 0) + error = nd->nd_repstat; + m_freem(nd->nd_mrep); + return (error); +} + /* * Acquire a layout and devinfo, if possible. The caller must have acquired * a reference count on the nfsclclient structure before calling this. @@ -5798,6 +5839,7 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, size_t iovlen = 0; off_t offs = 0; ssize_t resid = 0; + uint32_t op; if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || (np->n_flag & NNOLAYOUT) != 0) @@ -5977,6 +6019,20 @@ nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, NFSLOCKMNT(nmp); nmp->nm_state |= NFSSTA_OPENMODE; NFSUNLOCKMNT(nmp); + } else if ((error == NFSERR_NOSPC || + error == NFSERR_IO || error == NFSERR_NXIO) && + nmp->nm_minorvers == NFSV42_MINORVERSION) { + if (docommit != 0) + op = NFSV4OP_COMMIT; + else if (rwaccess == NFSV4OPEN_ACCESSREAD) + op = NFSV4OP_READ; + else + op = NFSV4OP_WRITE; + nfsrpc_layouterror(nmp, np->n_fhp->nfh_fh, + np->n_fhp->nfh_len, off, xfer, + &layp->nfsly_stateid, newcred, p, error, op, + dip->nfsdi_deviceid); + error = EIO; } else error = EIO; if (error == 0)