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-5.6-2' of git://git.linux-nfs.org/projects/anna/linux-nfs

Pull NFS client bugfixes from Anna Schumaker:
"The only stable fix this time is the DMA scatter-gather list bug fixed
by Chuck.

The rest fix up races and refcounting issues that have been found
during testing.

Stable fix:
- fix DMA scatter-gather list mapping imbalance

The rest:
- fix directory verifier races
- fix races between open and dentry revalidation
- fix revalidation of dentries with delegations
- fix "cachethis" setting for writes
- fix delegation and delegation cred pinning"

* tag 'nfs-for-5.6-2' of git://git.linux-nfs.org/projects/anna/linux-nfs:
NFSv4: Ensure the delegation cred is pinned when we call delegreturn
NFSv4: Ensure the delegation is pinned in nfs_do_return_delegation()
NFSv4.1 make cachethis=no for writes
xprtrdma: Fix DMA scatter-gather list mapping imbalance
NFSv4: Fix revalidation of dentries with delegations
NFSv4: Fix races between open and dentry revalidation
NFS: Fix up directory verifier races

+188 -50
+40 -10
fs/nfs/delegation.c
··· 42 42 if (!test_and_set_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) { 43 43 delegation->stateid.type = NFS4_INVALID_STATEID_TYPE; 44 44 atomic_long_dec(&nfs_active_delegations); 45 + if (!test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) 46 + nfs_clear_verifier_delegated(delegation->inode); 45 47 } 48 + } 49 + 50 + static struct nfs_delegation *nfs_get_delegation(struct nfs_delegation *delegation) 51 + { 52 + refcount_inc(&delegation->refcount); 53 + return delegation; 54 + } 55 + 56 + static void nfs_put_delegation(struct nfs_delegation *delegation) 57 + { 58 + if (refcount_dec_and_test(&delegation->refcount)) 59 + __nfs_free_delegation(delegation); 46 60 } 47 61 48 62 static void nfs_free_delegation(struct nfs_delegation *delegation) 49 63 { 50 64 nfs_mark_delegation_revoked(delegation); 51 - __nfs_free_delegation(delegation); 65 + nfs_put_delegation(delegation); 52 66 } 53 67 54 68 /** ··· 255 241 256 242 static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync) 257 243 { 244 + const struct cred *cred; 258 245 int res = 0; 259 246 260 - if (!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) 261 - res = nfs4_proc_delegreturn(inode, 262 - delegation->cred, 247 + if (!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) { 248 + spin_lock(&delegation->lock); 249 + cred = get_cred(delegation->cred); 250 + spin_unlock(&delegation->lock); 251 + res = nfs4_proc_delegreturn(inode, cred, 263 252 &delegation->stateid, 264 253 issync); 254 + put_cred(cred); 255 + } 265 256 return res; 266 257 } 267 258 ··· 292 273 if (delegation == NULL) 293 274 goto out; 294 275 spin_lock(&delegation->lock); 295 - if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) 296 - ret = delegation; 276 + if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) { 277 + /* Refcount matched in nfs_end_delegation_return() */ 278 + ret = nfs_get_delegation(delegation); 279 + } 297 280 spin_unlock(&delegation->lock); 281 + if (ret) 282 + nfs_clear_verifier_delegated(&nfsi->vfs_inode); 298 283 out: 299 284 return ret; 300 285 } ··· 416 393 if (delegation == NULL) 417 394 return -ENOMEM; 418 395 nfs4_stateid_copy(&delegation->stateid, stateid); 396 + refcount_set(&delegation->refcount, 1); 419 397 delegation->type = type; 420 398 delegation->pagemod_limit = pagemod_limit; 421 399 delegation->change_attr = inode_peek_iversion_raw(inode); ··· 516 492 517 493 err = nfs_do_return_delegation(inode, delegation, issync); 518 494 out: 495 + /* Refcount matched in nfs_start_delegation_return_locked() */ 496 + nfs_put_delegation(delegation); 519 497 return err; 520 498 } 521 499 ··· 712 686 list_empty(&NFS_I(inode)->open_files) && 713 687 !test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) { 714 688 clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags); 715 - ret = delegation; 689 + /* Refcount matched in nfs_end_delegation_return() */ 690 + ret = nfs_get_delegation(delegation); 716 691 } 717 692 spin_unlock(&delegation->lock); 693 + if (ret) 694 + nfs_clear_verifier_delegated(inode); 718 695 } 719 696 out: 720 697 rcu_read_unlock(); ··· 1117 1088 delegation = nfs_start_delegation_return_locked(NFS_I(inode)); 1118 1089 rcu_read_unlock(); 1119 1090 if (delegation != NULL) { 1120 - delegation = nfs_detach_delegation(NFS_I(inode), 1121 - delegation, server); 1122 - if (delegation != NULL) 1091 + if (nfs_detach_delegation(NFS_I(inode), delegation, 1092 + server) != NULL) 1123 1093 nfs_free_delegation(delegation); 1094 + /* Match nfs_start_delegation_return_locked */ 1095 + nfs_put_delegation(delegation); 1124 1096 } 1125 1097 iput(inode); 1126 1098 nfs_sb_deactive(server->super);
+1
fs/nfs/delegation.h
··· 22 22 unsigned long pagemod_limit; 23 23 __u64 change_attr; 24 24 unsigned long flags; 25 + refcount_t refcount; 25 26 spinlock_t lock; 26 27 struct rcu_head rcu; 27 28 };
+116 -10
fs/nfs/dir.c
··· 155 155 loff_t current_index; 156 156 decode_dirent_t decode; 157 157 158 + unsigned long dir_verifier; 158 159 unsigned long timestamp; 159 160 unsigned long gencount; 160 161 unsigned int cache_entry_index; ··· 354 353 again: 355 354 timestamp = jiffies; 356 355 gencount = nfs_inc_attr_generation_counter(); 356 + desc->dir_verifier = nfs_save_change_attribute(inode); 357 357 error = NFS_PROTO(inode)->readdir(file_dentry(file), cred, entry->cookie, pages, 358 358 NFS_SERVER(inode)->dtsize, desc->plus); 359 359 if (error < 0) { ··· 457 455 } 458 456 459 457 static 460 - void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) 458 + void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry, 459 + unsigned long dir_verifier) 461 460 { 462 461 struct qstr filename = QSTR_INIT(entry->name, entry->len); 463 462 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); 464 463 struct dentry *dentry; 465 464 struct dentry *alias; 466 - struct inode *dir = d_inode(parent); 467 465 struct inode *inode; 468 466 int status; 469 467 ··· 502 500 if (nfs_same_file(dentry, entry)) { 503 501 if (!entry->fh->size) 504 502 goto out; 505 - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); 503 + nfs_set_verifier(dentry, dir_verifier); 506 504 status = nfs_refresh_inode(d_inode(dentry), entry->fattr); 507 505 if (!status) 508 506 nfs_setsecurity(d_inode(dentry), entry->fattr, entry->label); ··· 528 526 dput(dentry); 529 527 dentry = alias; 530 528 } 531 - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); 529 + nfs_set_verifier(dentry, dir_verifier); 532 530 out: 533 531 dput(dentry); 534 532 } ··· 566 564 count++; 567 565 568 566 if (desc->plus) 569 - nfs_prime_dcache(file_dentry(desc->file), entry); 567 + nfs_prime_dcache(file_dentry(desc->file), entry, 568 + desc->dir_verifier); 570 569 571 570 status = nfs_readdir_add_to_array(entry, page); 572 571 if (status != 0) ··· 986 983 * full lookup on all child dentries of 'dir' whenever a change occurs 987 984 * on the server that might have invalidated our dcache. 988 985 * 986 + * Note that we reserve bit '0' as a tag to let us know when a dentry 987 + * was revalidated while holding a delegation on its inode. 988 + * 989 989 * The caller should be holding dir->i_lock 990 990 */ 991 991 void nfs_force_lookup_revalidate(struct inode *dir) 992 992 { 993 - NFS_I(dir)->cache_change_attribute++; 993 + NFS_I(dir)->cache_change_attribute += 2; 994 994 } 995 995 EXPORT_SYMBOL_GPL(nfs_force_lookup_revalidate); 996 + 997 + /** 998 + * nfs_verify_change_attribute - Detects NFS remote directory changes 999 + * @dir: pointer to parent directory inode 1000 + * @verf: previously saved change attribute 1001 + * 1002 + * Return "false" if the verifiers doesn't match the change attribute. 1003 + * This would usually indicate that the directory contents have changed on 1004 + * the server, and that any dentries need revalidating. 1005 + */ 1006 + static bool nfs_verify_change_attribute(struct inode *dir, unsigned long verf) 1007 + { 1008 + return (verf & ~1UL) == nfs_save_change_attribute(dir); 1009 + } 1010 + 1011 + static void nfs_set_verifier_delegated(unsigned long *verf) 1012 + { 1013 + *verf |= 1UL; 1014 + } 1015 + 1016 + #if IS_ENABLED(CONFIG_NFS_V4) 1017 + static void nfs_unset_verifier_delegated(unsigned long *verf) 1018 + { 1019 + *verf &= ~1UL; 1020 + } 1021 + #endif /* IS_ENABLED(CONFIG_NFS_V4) */ 1022 + 1023 + static bool nfs_test_verifier_delegated(unsigned long verf) 1024 + { 1025 + return verf & 1; 1026 + } 1027 + 1028 + static bool nfs_verifier_is_delegated(struct dentry *dentry) 1029 + { 1030 + return nfs_test_verifier_delegated(dentry->d_time); 1031 + } 1032 + 1033 + static void nfs_set_verifier_locked(struct dentry *dentry, unsigned long verf) 1034 + { 1035 + struct inode *inode = d_inode(dentry); 1036 + 1037 + if (!nfs_verifier_is_delegated(dentry) && 1038 + !nfs_verify_change_attribute(d_inode(dentry->d_parent), verf)) 1039 + goto out; 1040 + if (inode && NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) 1041 + nfs_set_verifier_delegated(&verf); 1042 + out: 1043 + dentry->d_time = verf; 1044 + } 1045 + 1046 + /** 1047 + * nfs_set_verifier - save a parent directory verifier in the dentry 1048 + * @dentry: pointer to dentry 1049 + * @verf: verifier to save 1050 + * 1051 + * Saves the parent directory verifier in @dentry. If the inode has 1052 + * a delegation, we also tag the dentry as having been revalidated 1053 + * while holding a delegation so that we know we don't have to 1054 + * look it up again after a directory change. 1055 + */ 1056 + void nfs_set_verifier(struct dentry *dentry, unsigned long verf) 1057 + { 1058 + 1059 + spin_lock(&dentry->d_lock); 1060 + nfs_set_verifier_locked(dentry, verf); 1061 + spin_unlock(&dentry->d_lock); 1062 + } 1063 + EXPORT_SYMBOL_GPL(nfs_set_verifier); 1064 + 1065 + #if IS_ENABLED(CONFIG_NFS_V4) 1066 + /** 1067 + * nfs_clear_verifier_delegated - clear the dir verifier delegation tag 1068 + * @inode: pointer to inode 1069 + * 1070 + * Iterates through the dentries in the inode alias list and clears 1071 + * the tag used to indicate that the dentry has been revalidated 1072 + * while holding a delegation. 1073 + * This function is intended for use when the delegation is being 1074 + * returned or revoked. 1075 + */ 1076 + void nfs_clear_verifier_delegated(struct inode *inode) 1077 + { 1078 + struct dentry *alias; 1079 + 1080 + if (!inode) 1081 + return; 1082 + spin_lock(&inode->i_lock); 1083 + hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { 1084 + spin_lock(&alias->d_lock); 1085 + nfs_unset_verifier_delegated(&alias->d_time); 1086 + spin_unlock(&alias->d_lock); 1087 + } 1088 + spin_unlock(&inode->i_lock); 1089 + } 1090 + EXPORT_SYMBOL_GPL(nfs_clear_verifier_delegated); 1091 + #endif /* IS_ENABLED(CONFIG_NFS_V4) */ 996 1092 997 1093 /* 998 1094 * A check for whether or not the parent directory has changed. ··· 1261 1159 struct nfs_fh *fhandle; 1262 1160 struct nfs_fattr *fattr; 1263 1161 struct nfs4_label *label; 1162 + unsigned long dir_verifier; 1264 1163 int ret; 1265 1164 1266 1165 ret = -ENOMEM; ··· 1271 1168 if (fhandle == NULL || fattr == NULL || IS_ERR(label)) 1272 1169 goto out; 1273 1170 1171 + dir_verifier = nfs_save_change_attribute(dir); 1274 1172 ret = NFS_PROTO(dir)->lookup(dir, dentry, fhandle, fattr, label); 1275 1173 if (ret < 0) { 1276 1174 switch (ret) { ··· 1292 1188 goto out; 1293 1189 1294 1190 nfs_setsecurity(inode, fattr, label); 1295 - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); 1191 + nfs_set_verifier(dentry, dir_verifier); 1296 1192 1297 1193 /* set a readdirplus hint that we had a cache miss */ 1298 1194 nfs_force_use_readdirplus(dir); ··· 1334 1230 goto out_bad; 1335 1231 } 1336 1232 1337 - if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ)) 1233 + if (nfs_verifier_is_delegated(dentry)) 1338 1234 return nfs_lookup_revalidate_delegated(dir, dentry, inode); 1339 1235 1340 1236 /* Force a full look up iff the parent directory has changed */ ··· 1519 1415 struct nfs_fh *fhandle = NULL; 1520 1416 struct nfs_fattr *fattr = NULL; 1521 1417 struct nfs4_label *label = NULL; 1418 + unsigned long dir_verifier; 1522 1419 int error; 1523 1420 1524 1421 dfprintk(VFS, "NFS: lookup(%pd2)\n", dentry); ··· 1545 1440 if (IS_ERR(label)) 1546 1441 goto out; 1547 1442 1443 + dir_verifier = nfs_save_change_attribute(dir); 1548 1444 trace_nfs_lookup_enter(dir, dentry, flags); 1549 1445 error = NFS_PROTO(dir)->lookup(dir, dentry, fhandle, fattr, label); 1550 1446 if (error == -ENOENT) ··· 1569 1463 goto out_label; 1570 1464 dentry = res; 1571 1465 } 1572 - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); 1466 + nfs_set_verifier(dentry, dir_verifier); 1573 1467 out_label: 1574 1468 trace_nfs_lookup_exit(dir, dentry, flags, error); 1575 1469 nfs4_label_free(label); ··· 1774 1668 if (inode == NULL) 1775 1669 goto full_reval; 1776 1670 1777 - if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ)) 1671 + if (nfs_verifier_is_delegated(dentry)) 1778 1672 return nfs_lookup_revalidate_delegated(dir, dentry, inode); 1779 1673 1780 1674 /* NFS only supports OPEN on regular files */
+1
fs/nfs/inode.c
··· 2114 2114 init_rwsem(&nfsi->rmdir_sem); 2115 2115 mutex_init(&nfsi->commit_mutex); 2116 2116 nfs4_init_once(nfsi); 2117 + nfsi->cache_change_attribute = 0; 2117 2118 } 2118 2119 2119 2120 static int __init nfs_init_inodecache(void)
-1
fs/nfs/nfs4file.c
··· 87 87 if (inode != d_inode(dentry)) 88 88 goto out_drop; 89 89 90 - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); 91 90 nfs_file_set_open_context(filp, ctx); 92 91 nfs_fscache_open_file(inode, filp); 93 92 err = 0;
+17 -3
fs/nfs/nfs4proc.c
··· 2974 2974 struct dentry *dentry; 2975 2975 struct nfs4_state *state; 2976 2976 fmode_t acc_mode = _nfs4_ctx_to_accessmode(ctx); 2977 + struct inode *dir = d_inode(opendata->dir); 2978 + unsigned long dir_verifier; 2977 2979 unsigned int seq; 2978 2980 int ret; 2979 2981 2980 2982 seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); 2983 + dir_verifier = nfs_save_change_attribute(dir); 2981 2984 2982 2985 ret = _nfs4_proc_open(opendata, ctx); 2983 2986 if (ret != 0) ··· 3008 3005 dput(ctx->dentry); 3009 3006 ctx->dentry = dentry = alias; 3010 3007 } 3011 - nfs_set_verifier(dentry, 3012 - nfs_save_change_attribute(d_inode(opendata->dir))); 3008 + } 3009 + 3010 + switch(opendata->o_arg.claim) { 3011 + default: 3012 + break; 3013 + case NFS4_OPEN_CLAIM_NULL: 3014 + case NFS4_OPEN_CLAIM_DELEGATE_CUR: 3015 + case NFS4_OPEN_CLAIM_DELEGATE_PREV: 3016 + if (!opendata->rpc_done) 3017 + break; 3018 + if (opendata->o_res.delegation_type != 0) 3019 + dir_verifier = nfs_save_change_attribute(dir); 3020 + nfs_set_verifier(dentry, dir_verifier); 3013 3021 } 3014 3022 3015 3023 /* Parse layoutget results before we check for access */ ··· 5336 5322 hdr->timestamp = jiffies; 5337 5323 5338 5324 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE]; 5339 - nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 1, 0); 5325 + nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 0, 0); 5340 5326 nfs4_state_protect_write(server->nfs_client, clnt, msg, hdr); 5341 5327 } 5342 5328
+6 -20
include/linux/nfs_fs.h
··· 337 337 return NFS_SERVER(inode)->caps & cap; 338 338 } 339 339 340 - static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) 341 - { 342 - dentry->d_time = verf; 343 - } 344 - 345 340 /** 346 341 * nfs_save_change_attribute - Returns the inode attribute change cookie 347 342 * @dir - pointer to parent directory inode 348 - * The "change attribute" is updated every time we finish an operation 349 - * that will result in a metadata change on the server. 343 + * The "cache change attribute" is updated when we need to revalidate 344 + * our dentry cache after a directory was seen to change on the server. 350 345 */ 351 346 static inline unsigned long nfs_save_change_attribute(struct inode *dir) 352 347 { 353 348 return NFS_I(dir)->cache_change_attribute; 354 - } 355 - 356 - /** 357 - * nfs_verify_change_attribute - Detects NFS remote directory changes 358 - * @dir - pointer to parent directory inode 359 - * @chattr - previously saved change attribute 360 - * Return "false" if the verifiers doesn't match the change attribute. 361 - * This would usually indicate that the directory contents have changed on 362 - * the server, and that any dentries need revalidating. 363 - */ 364 - static inline int nfs_verify_change_attribute(struct inode *dir, unsigned long chattr) 365 - { 366 - return chattr == NFS_I(dir)->cache_change_attribute; 367 349 } 368 350 369 351 /* ··· 477 495 extern const struct dentry_operations nfs_dentry_operations; 478 496 479 497 extern void nfs_force_lookup_revalidate(struct inode *dir); 498 + extern void nfs_set_verifier(struct dentry * dentry, unsigned long verf); 499 + #if IS_ENABLED(CONFIG_NFS_V4) 500 + extern void nfs_clear_verifier_delegated(struct inode *inode); 501 + #endif /* IS_ENABLED(CONFIG_NFS_V4) */ 480 502 extern struct dentry *nfs_add_or_obtain(struct dentry *dentry, 481 503 struct nfs_fh *fh, struct nfs_fattr *fattr, 482 504 struct nfs4_label *label);
+7 -6
net/sunrpc/xprtrdma/frwr_ops.c
··· 288 288 { 289 289 struct rpcrdma_ia *ia = &r_xprt->rx_ia; 290 290 struct ib_reg_wr *reg_wr; 291 + int i, n, dma_nents; 291 292 struct ib_mr *ibmr; 292 - int i, n; 293 293 u8 key; 294 294 295 295 if (nsegs > ia->ri_max_frwr_depth) ··· 313 313 break; 314 314 } 315 315 mr->mr_dir = rpcrdma_data_dir(writing); 316 + mr->mr_nents = i; 316 317 317 - mr->mr_nents = 318 - ib_dma_map_sg(ia->ri_id->device, mr->mr_sg, i, mr->mr_dir); 319 - if (!mr->mr_nents) 318 + dma_nents = ib_dma_map_sg(ia->ri_id->device, mr->mr_sg, mr->mr_nents, 319 + mr->mr_dir); 320 + if (!dma_nents) 320 321 goto out_dmamap_err; 321 322 322 323 ibmr = mr->frwr.fr_mr; 323 - n = ib_map_mr_sg(ibmr, mr->mr_sg, mr->mr_nents, NULL, PAGE_SIZE); 324 - if (unlikely(n != mr->mr_nents)) 324 + n = ib_map_mr_sg(ibmr, mr->mr_sg, dma_nents, NULL, PAGE_SIZE); 325 + if (n != dma_nents) 325 326 goto out_mapmr_err; 326 327 327 328 ibmr->iova &= 0x00000000ffffffff;