nfscl: Add a LayoutError RPC for NFSv4.2 pNFS mounts

If a pNFS server's DS runs out of disk space, it replies
NFSERR_NOSPC to the client doing writing.  For the Linux
client, it then sends a LayoutError RPC to the MDS server to
tell it about the error.  This patch adds the same to the
FreeBSD NFSv4.2 pNFS client, to maintain Linux compatible
behaviour, particlularily for non-FreeBSD pNFS servers.

(cherry picked from commit 44744f7538)
This commit is contained in:
Rick Macklem 2021-11-11 15:43:58 -08:00
parent 354988ca3f
commit 6e8e261f0d
4 changed files with 84 additions and 6 deletions

View file

@ -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
};
/*

View file

@ -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;

View file

@ -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 */

View file

@ -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)