Skip to content

Commit 94ca5c1

Browse files
committed
Merge tag 'nfs-for-4.20-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes from Trond Myklebust: "Highlights include: Stable fixes: - Don't exit the NFSv4 state manager without clearing NFS4CLNT_MANAGER_RUNNING Bugfixes: - Fix an Oops when destroying the RPCSEC_GSS credential cache - Fix an Oops during delegation callbacks - Ensure that the NFSv4 state manager exits the loop on SIGKILL - Fix a bogus get/put in generic_key_to_expire()" * tag 'nfs-for-4.20-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: NFSv4: Fix an Oops during delegation callbacks SUNRPC: Fix a bogus get/put in generic_key_to_expire() SUNRPC: Fix a Oops when destroying the RPCSEC_GSS credential cache NFSv4: Ensure that the state manager exits the loop on SIGKILL NFSv4: Don't exit the state manager without clearing NFS4CLNT_MANAGER_RUNNING
2 parents 5929a1f + e39d8a1 commit 94ca5c1

File tree

5 files changed

+60
-34
lines changed

5 files changed

+60
-34
lines changed

fs/nfs/callback_proc.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ __be32 nfs4_callback_getattr(void *argp, void *resp,
6666
out_iput:
6767
rcu_read_unlock();
6868
trace_nfs4_cb_getattr(cps->clp, &args->fh, inode, -ntohl(res->status));
69-
iput(inode);
69+
nfs_iput_and_deactive(inode);
7070
out:
7171
dprintk("%s: exit with status = %d\n", __func__, ntohl(res->status));
7272
return res->status;
@@ -108,7 +108,7 @@ __be32 nfs4_callback_recall(void *argp, void *resp,
108108
}
109109
trace_nfs4_cb_recall(cps->clp, &args->fh, inode,
110110
&args->stateid, -ntohl(res));
111-
iput(inode);
111+
nfs_iput_and_deactive(inode);
112112
out:
113113
dprintk("%s: exit with status = %d\n", __func__, ntohl(res));
114114
return res;

fs/nfs/delegation.c

+9-2
Original file line numberDiff line numberDiff line change
@@ -850,16 +850,23 @@ nfs_delegation_find_inode_server(struct nfs_server *server,
850850
const struct nfs_fh *fhandle)
851851
{
852852
struct nfs_delegation *delegation;
853-
struct inode *res = NULL;
853+
struct inode *freeme, *res = NULL;
854854

855855
list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
856856
spin_lock(&delegation->lock);
857857
if (delegation->inode != NULL &&
858858
nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
859-
res = igrab(delegation->inode);
859+
freeme = igrab(delegation->inode);
860+
if (freeme && nfs_sb_active(freeme->i_sb))
861+
res = freeme;
860862
spin_unlock(&delegation->lock);
861863
if (res != NULL)
862864
return res;
865+
if (freeme) {
866+
rcu_read_unlock();
867+
iput(freeme);
868+
rcu_read_lock();
869+
}
863870
return ERR_PTR(-EAGAIN);
864871
}
865872
spin_unlock(&delegation->lock);

fs/nfs/nfs4state.c

+6-4
Original file line numberDiff line numberDiff line change
@@ -2601,18 +2601,20 @@ static void nfs4_state_manager(struct nfs_client *clp)
26012601
nfs4_clear_state_manager_bit(clp);
26022602
/* Did we race with an attempt to give us more work? */
26032603
if (clp->cl_state == 0)
2604-
break;
2604+
return;
26052605
if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
2606-
break;
2607-
} while (refcount_read(&clp->cl_count) > 1);
2608-
return;
2606+
return;
2607+
} while (refcount_read(&clp->cl_count) > 1 && !signalled());
2608+
goto out_drain;
2609+
26092610
out_error:
26102611
if (strlen(section))
26112612
section_sep = ": ";
26122613
pr_warn_ratelimited("NFS: state manager%s%s failed on NFSv4 server %s"
26132614
" with error %d\n", section_sep, section,
26142615
clp->cl_hostname, -status);
26152616
ssleep(1);
2617+
out_drain:
26162618
nfs4_end_drain_session(clp);
26172619
nfs4_clear_state_manager_bit(clp);
26182620
}

net/sunrpc/auth_generic.c

+1-7
Original file line numberDiff line numberDiff line change
@@ -281,13 +281,7 @@ static bool generic_key_to_expire(struct rpc_cred *cred)
281281
{
282282
struct auth_cred *acred = &container_of(cred, struct generic_cred,
283283
gc_base)->acred;
284-
bool ret;
285-
286-
get_rpccred(cred);
287-
ret = test_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags);
288-
put_rpccred(cred);
289-
290-
return ret;
284+
return test_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags);
291285
}
292286

293287
static const struct rpc_credops generic_credops = {

net/sunrpc/auth_gss/auth_gss.c

+42-19
Original file line numberDiff line numberDiff line change
@@ -1239,36 +1239,59 @@ gss_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
12391239
return &gss_auth->rpc_auth;
12401240
}
12411241

1242+
static struct gss_cred *
1243+
gss_dup_cred(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
1244+
{
1245+
struct gss_cred *new;
1246+
1247+
/* Make a copy of the cred so that we can reference count it */
1248+
new = kzalloc(sizeof(*gss_cred), GFP_NOIO);
1249+
if (new) {
1250+
struct auth_cred acred = {
1251+
.uid = gss_cred->gc_base.cr_uid,
1252+
};
1253+
struct gss_cl_ctx *ctx =
1254+
rcu_dereference_protected(gss_cred->gc_ctx, 1);
1255+
1256+
rpcauth_init_cred(&new->gc_base, &acred,
1257+
&gss_auth->rpc_auth,
1258+
&gss_nullops);
1259+
new->gc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
1260+
new->gc_service = gss_cred->gc_service;
1261+
new->gc_principal = gss_cred->gc_principal;
1262+
kref_get(&gss_auth->kref);
1263+
rcu_assign_pointer(new->gc_ctx, ctx);
1264+
gss_get_ctx(ctx);
1265+
}
1266+
return new;
1267+
}
1268+
12421269
/*
1243-
* gss_destroying_context will cause the RPCSEC_GSS to send a NULL RPC call
1270+
* gss_send_destroy_context will cause the RPCSEC_GSS to send a NULL RPC call
12441271
* to the server with the GSS control procedure field set to
12451272
* RPC_GSS_PROC_DESTROY. This should normally cause the server to release
12461273
* all RPCSEC_GSS state associated with that context.
12471274
*/
1248-
static int
1249-
gss_destroying_context(struct rpc_cred *cred)
1275+
static void
1276+
gss_send_destroy_context(struct rpc_cred *cred)
12501277
{
12511278
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
12521279
struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth);
12531280
struct gss_cl_ctx *ctx = rcu_dereference_protected(gss_cred->gc_ctx, 1);
1281+
struct gss_cred *new;
12541282
struct rpc_task *task;
12551283

1256-
if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
1257-
return 0;
1258-
1259-
ctx->gc_proc = RPC_GSS_PROC_DESTROY;
1260-
cred->cr_ops = &gss_nullops;
1261-
1262-
/* Take a reference to ensure the cred will be destroyed either
1263-
* by the RPC call or by the put_rpccred() below */
1264-
get_rpccred(cred);
1284+
new = gss_dup_cred(gss_auth, gss_cred);
1285+
if (new) {
1286+
ctx->gc_proc = RPC_GSS_PROC_DESTROY;
12651287

1266-
task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC|RPC_TASK_SOFT);
1267-
if (!IS_ERR(task))
1268-
rpc_put_task(task);
1288+
task = rpc_call_null(gss_auth->client, &new->gc_base,
1289+
RPC_TASK_ASYNC|RPC_TASK_SOFT);
1290+
if (!IS_ERR(task))
1291+
rpc_put_task(task);
12691292

1270-
put_rpccred(cred);
1271-
return 1;
1293+
put_rpccred(&new->gc_base);
1294+
}
12721295
}
12731296

12741297
/* gss_destroy_cred (and gss_free_ctx) are used to clean up after failure
@@ -1330,8 +1353,8 @@ static void
13301353
gss_destroy_cred(struct rpc_cred *cred)
13311354
{
13321355

1333-
if (gss_destroying_context(cred))
1334-
return;
1356+
if (test_and_clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0)
1357+
gss_send_destroy_context(cred);
13351358
gss_destroy_nullcred(cred);
13361359
}
13371360

0 commit comments

Comments
 (0)