Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+60 -34
+2 -2
fs/nfs/callback_proc.c
··· 66 66 out_iput: 67 67 rcu_read_unlock(); 68 68 trace_nfs4_cb_getattr(cps->clp, &args->fh, inode, -ntohl(res->status)); 69 - iput(inode); 69 + nfs_iput_and_deactive(inode); 70 70 out: 71 71 dprintk("%s: exit with status = %d\n", __func__, ntohl(res->status)); 72 72 return res->status; ··· 108 108 } 109 109 trace_nfs4_cb_recall(cps->clp, &args->fh, inode, 110 110 &args->stateid, -ntohl(res)); 111 - iput(inode); 111 + nfs_iput_and_deactive(inode); 112 112 out: 113 113 dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); 114 114 return res;
+9 -2
fs/nfs/delegation.c
··· 850 850 const struct nfs_fh *fhandle) 851 851 { 852 852 struct nfs_delegation *delegation; 853 - struct inode *res = NULL; 853 + struct inode *freeme, *res = NULL; 854 854 855 855 list_for_each_entry_rcu(delegation, &server->delegations, super_list) { 856 856 spin_lock(&delegation->lock); 857 857 if (delegation->inode != NULL && 858 858 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; 860 862 spin_unlock(&delegation->lock); 861 863 if (res != NULL) 862 864 return res; 865 + if (freeme) { 866 + rcu_read_unlock(); 867 + iput(freeme); 868 + rcu_read_lock(); 869 + } 863 870 return ERR_PTR(-EAGAIN); 864 871 } 865 872 spin_unlock(&delegation->lock);
+6 -4
fs/nfs/nfs4state.c
··· 2601 2601 nfs4_clear_state_manager_bit(clp); 2602 2602 /* Did we race with an attempt to give us more work? */ 2603 2603 if (clp->cl_state == 0) 2604 - break; 2604 + return; 2605 2605 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 + 2609 2610 out_error: 2610 2611 if (strlen(section)) 2611 2612 section_sep = ": "; ··· 2614 2613 " with error %d\n", section_sep, section, 2615 2614 clp->cl_hostname, -status); 2616 2615 ssleep(1); 2616 + out_drain: 2617 2617 nfs4_end_drain_session(clp); 2618 2618 nfs4_clear_state_manager_bit(clp); 2619 2619 }
+1 -7
net/sunrpc/auth_generic.c
··· 281 281 { 282 282 struct auth_cred *acred = &container_of(cred, struct generic_cred, 283 283 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); 291 285 } 292 286 293 287 static const struct rpc_credops generic_credops = {
+42 -19
net/sunrpc/auth_gss/auth_gss.c
··· 1239 1239 return &gss_auth->rpc_auth; 1240 1240 } 1241 1241 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 + 1242 1269 /* 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 1244 1271 * to the server with the GSS control procedure field set to 1245 1272 * RPC_GSS_PROC_DESTROY. This should normally cause the server to release 1246 1273 * all RPCSEC_GSS state associated with that context. 1247 1274 */ 1248 - static int 1249 - gss_destroying_context(struct rpc_cred *cred) 1275 + static void 1276 + gss_send_destroy_context(struct rpc_cred *cred) 1250 1277 { 1251 1278 struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); 1252 1279 struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); 1253 1280 struct gss_cl_ctx *ctx = rcu_dereference_protected(gss_cred->gc_ctx, 1); 1281 + struct gss_cred *new; 1254 1282 struct rpc_task *task; 1255 1283 1256 - if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) 1257 - return 0; 1284 + new = gss_dup_cred(gss_auth, gss_cred); 1285 + if (new) { 1286 + ctx->gc_proc = RPC_GSS_PROC_DESTROY; 1258 1287 1259 - ctx->gc_proc = RPC_GSS_PROC_DESTROY; 1260 - cred->cr_ops = &gss_nullops; 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); 1261 1292 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); 1265 - 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); 1269 - 1270 - put_rpccred(cred); 1271 - return 1; 1293 + put_rpccred(&new->gc_base); 1294 + } 1272 1295 } 1273 1296 1274 1297 /* gss_destroy_cred (and gss_free_ctx) are used to clean up after failure ··· 1353 1330 gss_destroy_cred(struct rpc_cred *cred) 1354 1331 { 1355 1332 1356 - if (gss_destroying_context(cred)) 1357 - return; 1333 + if (test_and_clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0) 1334 + gss_send_destroy_context(cred); 1358 1335 gss_destroy_nullcred(cred); 1359 1336 } 1360 1337