From 4a9c979c0f41d9e7e8cd7b33a3c706a672b5a8f7 Mon Sep 17 00:00:00 2001 From: Rick Macklem Date: Fri, 23 Apr 2010 00:12:23 +0000 Subject: [PATCH] MFC: r206688 The experimental NFS client was not filling in recovery credentials for opens done locally in the client when a delegation for the file was held. This could cause the client to crash in crsetgroups() when recovering from a server crash/reboot. This patch fills in the recovery credentials for this case, in order to avoid the client crash. Also, add KASSERT()s to the credential copy functions, to catch any other cases where the credentials aren't filled in correctly. --- sys/fs/nfs/nfs_commonport.c | 2 ++ sys/fs/nfs/nfsclstate.h | 1 + sys/fs/nfsclient/nfs_clport.c | 2 ++ sys/fs/nfsclient/nfs_clrpcops.c | 8 +++++++- sys/fs/nfsclient/nfs_clstate.c | 9 +++++++-- 5 files changed, 19 insertions(+), 3 deletions(-) diff --git a/sys/fs/nfs/nfs_commonport.c b/sys/fs/nfs/nfs_commonport.c index 56ccf1b85ee4..7bc204e080c3 100644 --- a/sys/fs/nfs/nfs_commonport.c +++ b/sys/fs/nfs/nfs_commonport.c @@ -225,6 +225,8 @@ void newnfs_copycred(struct nfscred *nfscr, struct ucred *cr) { + KASSERT(nfscr->nfsc_ngroups >= 0, + ("newnfs_copycred: negative nfsc_ngroups")); cr->cr_uid = nfscr->nfsc_uid; crsetgroups(cr, nfscr->nfsc_ngroups, nfscr->nfsc_groups); } diff --git a/sys/fs/nfs/nfsclstate.h b/sys/fs/nfs/nfsclstate.h index 10747af5a643..edd479cf2cee 100644 --- a/sys/fs/nfs/nfsclstate.h +++ b/sys/fs/nfs/nfsclstate.h @@ -140,6 +140,7 @@ struct nfsclopen { #define NFSCLOPEN_OK 0 #define NFSCLOPEN_DOOPEN 1 #define NFSCLOPEN_DOOPENDOWNGRADE 2 +#define NFSCLOPEN_SETCRED 3 struct nfscllockowner { LIST_ENTRY(nfscllockowner) nfsl_list; diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c index e81c3bf805b8..f39666db68ec 100644 --- a/sys/fs/nfsclient/nfs_clport.c +++ b/sys/fs/nfsclient/nfs_clport.c @@ -978,6 +978,8 @@ newnfs_copyincred(struct ucred *cr, struct nfscred *nfscr) { int i; + KASSERT(cr->cr_ngroups >= 0, + ("newnfs_copyincred: negative cr_ngroups")); nfscr->nfsc_uid = cr->cr_uid; nfscr->nfsc_ngroups = MIN(cr->cr_ngroups, NFS_MAXGRPS + 1); for (i = 0; i < nfscr->nfsc_ngroups; i++) diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index 88e177912847..9b7b8dfa67e2 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -280,7 +280,13 @@ else printf(" fhl=0\n"); error = EIO; } newnfs_copyincred(cred, &op->nfso_cred); - } + } else if (ret == NFSCLOPEN_SETCRED) + /* + * This is a new local open on a delegation. It needs + * to have credentials so that an open can be done + * against the server during recovery. + */ + newnfs_copyincred(cred, &op->nfso_cred); /* * nfso_opencnt is the count of how many VOP_OPEN()s have diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c index 568c5de640af..08150a7228e7 100644 --- a/sys/fs/nfsclient/nfs_clstate.c +++ b/sys/fs/nfsclient/nfs_clstate.c @@ -274,8 +274,13 @@ nfscl_open(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t amode, int usedeleg, *owpp = owp; if (opp != NULL) *opp = op; - if (retp != NULL) - *retp = NFSCLOPEN_OK; + if (retp != NULL) { + if (nfhp != NULL && dp != NULL && nop == NULL) + /* new local open on delegation */ + *retp = NFSCLOPEN_SETCRED; + else + *retp = NFSCLOPEN_OK; + } /* * Now, check the mode on the open and return the appropriate