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 '6.2-rc4-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:

- important fix for packet signature calculation error

- three fixes to correct DFS deadlock, and DFS refresh problem

- remove an unused DFS function, and duplicate tcon refresh code

- DFS cache lookup fix

- uninitialized rc fix

* tag '6.2-rc4-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
cifs: remove unused function
cifs: do not include page data when checking signature
cifs: fix return of uninitialized rc in dfs_cache_update_tgthint()
cifs: handle cache lookup errors different than -ENOENT
cifs: remove duplicate code in __refresh_tcon()
cifs: don't take exclusive lock for updating target hints
cifs: avoid re-lookups in dfs_cache_find()
cifs: fix potential deadlock in cache_refresh_path()

+104 -155
+95 -146
fs/cifs/dfs_cache.c
··· 269 269 list_for_each_entry(t, &ce->tlist, list) { 270 270 seq_printf(m, " %s%s\n", 271 271 t->name, 272 - ce->tgthint == t ? " (target hint)" : ""); 272 + READ_ONCE(ce->tgthint) == t ? " (target hint)" : ""); 273 273 } 274 274 } 275 275 } ··· 321 321 cifs_dbg(FYI, "target list:\n"); 322 322 list_for_each_entry(t, &ce->tlist, list) { 323 323 cifs_dbg(FYI, " %s%s\n", t->name, 324 - ce->tgthint == t ? " (target hint)" : ""); 324 + READ_ONCE(ce->tgthint) == t ? " (target hint)" : ""); 325 325 } 326 326 } 327 327 ··· 427 427 /* Return target hint of a DFS cache entry */ 428 428 static inline char *get_tgt_name(const struct cache_entry *ce) 429 429 { 430 - struct cache_dfs_tgt *t = ce->tgthint; 430 + struct cache_dfs_tgt *t = READ_ONCE(ce->tgthint); 431 431 432 432 return t ? t->name : ERR_PTR(-ENOENT); 433 433 } ··· 470 470 static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs, 471 471 struct cache_entry *ce, const char *tgthint) 472 472 { 473 + struct cache_dfs_tgt *target; 473 474 int i; 474 475 475 476 ce->ttl = max_t(int, refs[0].ttl, CACHE_MIN_TTL); ··· 497 496 ce->numtgts++; 498 497 } 499 498 500 - ce->tgthint = list_first_entry_or_null(&ce->tlist, 501 - struct cache_dfs_tgt, list); 499 + target = list_first_entry_or_null(&ce->tlist, struct cache_dfs_tgt, 500 + list); 501 + WRITE_ONCE(ce->tgthint, target); 502 502 503 503 return 0; 504 504 } ··· 560 558 } 561 559 562 560 /* Add a new DFS cache entry */ 563 - static int add_cache_entry_locked(struct dfs_info3_param *refs, int numrefs) 561 + static struct cache_entry *add_cache_entry_locked(struct dfs_info3_param *refs, 562 + int numrefs) 564 563 { 565 564 int rc; 566 565 struct cache_entry *ce; ··· 576 573 577 574 rc = cache_entry_hash(refs[0].path_name, strlen(refs[0].path_name), &hash); 578 575 if (rc) 579 - return rc; 576 + return ERR_PTR(rc); 580 577 581 578 ce = alloc_cache_entry(refs, numrefs); 582 579 if (IS_ERR(ce)) 583 - return PTR_ERR(ce); 580 + return ce; 584 581 585 582 spin_lock(&cache_ttl_lock); 586 583 if (!cache_ttl) { ··· 597 594 598 595 atomic_inc(&cache_count); 599 596 600 - return 0; 597 + return ce; 601 598 } 602 599 603 600 /* Check if two DFS paths are equal. @s1 and @s2 are expected to be in @cache_cp's charset */ ··· 644 641 * 645 642 * Use whole path components in the match. Must be called with htable_rw_lock held. 646 643 * 644 + * Return cached entry if successful. 647 645 * Return ERR_PTR(-ENOENT) if the entry is not found. 646 + * Return error ptr otherwise. 648 647 */ 649 648 static struct cache_entry *lookup_cache_entry(const char *path) 650 649 { ··· 716 711 static int update_cache_entry_locked(struct cache_entry *ce, const struct dfs_info3_param *refs, 717 712 int numrefs) 718 713 { 714 + struct cache_dfs_tgt *target; 715 + char *th = NULL; 719 716 int rc; 720 - char *s, *th = NULL; 721 717 722 718 WARN_ON(!rwsem_is_locked(&htable_rw_lock)); 723 719 724 - if (ce->tgthint) { 725 - s = ce->tgthint->name; 726 - th = kstrdup(s, GFP_ATOMIC); 720 + target = READ_ONCE(ce->tgthint); 721 + if (target) { 722 + th = kstrdup(target->name, GFP_ATOMIC); 727 723 if (!th) 728 724 return -ENOMEM; 729 725 } ··· 773 767 * 774 768 * For interlinks, cifs_mount() and expand_dfs_referral() are supposed to 775 769 * handle them properly. 770 + * 771 + * On success, return entry with acquired lock for reading, otherwise error ptr. 776 772 */ 777 - static int cache_refresh_path(const unsigned int xid, struct cifs_ses *ses, const char *path) 773 + static struct cache_entry *cache_refresh_path(const unsigned int xid, 774 + struct cifs_ses *ses, 775 + const char *path, 776 + bool force_refresh) 778 777 { 779 - int rc; 780 - struct cache_entry *ce; 781 778 struct dfs_info3_param *refs = NULL; 779 + struct cache_entry *ce; 782 780 int numrefs = 0; 783 - bool newent = false; 781 + int rc; 784 782 785 783 cifs_dbg(FYI, "%s: search path: %s\n", __func__, path); 786 784 787 - down_write(&htable_rw_lock); 785 + down_read(&htable_rw_lock); 788 786 789 787 ce = lookup_cache_entry(path); 790 788 if (!IS_ERR(ce)) { 791 - if (!cache_entry_expired(ce)) { 792 - dump_ce(ce); 793 - up_write(&htable_rw_lock); 794 - return 0; 795 - } 796 - } else { 797 - newent = true; 789 + if (!force_refresh && !cache_entry_expired(ce)) 790 + return ce; 791 + } else if (PTR_ERR(ce) != -ENOENT) { 792 + up_read(&htable_rw_lock); 793 + return ce; 798 794 } 799 795 800 796 /* 801 - * Either the entry was not found, or it is expired. 797 + * Unlock shared access as we don't want to hold any locks while getting 798 + * a new referral. The @ses used for performing the I/O could be 799 + * reconnecting and it acquires @htable_rw_lock to look up the dfs cache 800 + * in order to failover -- if necessary. 801 + */ 802 + up_read(&htable_rw_lock); 803 + 804 + /* 805 + * Either the entry was not found, or it is expired, or it is a forced 806 + * refresh. 802 807 * Request a new DFS referral in order to create or update a cache entry. 803 808 */ 804 809 rc = get_dfs_referral(xid, ses, path, &refs, &numrefs); 805 - if (rc) 806 - goto out_unlock; 810 + if (rc) { 811 + ce = ERR_PTR(rc); 812 + goto out; 813 + } 807 814 808 815 dump_refs(refs, numrefs); 809 816 810 - if (!newent) { 811 - rc = update_cache_entry_locked(ce, refs, numrefs); 812 - goto out_unlock; 817 + down_write(&htable_rw_lock); 818 + /* Re-check as another task might have it added or refreshed already */ 819 + ce = lookup_cache_entry(path); 820 + if (!IS_ERR(ce)) { 821 + if (force_refresh || cache_entry_expired(ce)) { 822 + rc = update_cache_entry_locked(ce, refs, numrefs); 823 + if (rc) 824 + ce = ERR_PTR(rc); 825 + } 826 + } else if (PTR_ERR(ce) == -ENOENT) { 827 + ce = add_cache_entry_locked(refs, numrefs); 813 828 } 814 829 815 - rc = add_cache_entry_locked(refs, numrefs); 830 + if (IS_ERR(ce)) { 831 + up_write(&htable_rw_lock); 832 + goto out; 833 + } 816 834 817 - out_unlock: 818 - up_write(&htable_rw_lock); 835 + downgrade_write(&htable_rw_lock); 836 + out: 819 837 free_dfs_info_array(refs, numrefs); 820 - return rc; 838 + return ce; 821 839 } 822 840 823 841 /* ··· 908 878 } 909 879 it->it_path_consumed = t->path_consumed; 910 880 911 - if (ce->tgthint == t) 881 + if (READ_ONCE(ce->tgthint) == t) 912 882 list_add(&it->it_list, head); 913 883 else 914 884 list_add_tail(&it->it_list, head); ··· 961 931 if (IS_ERR(npath)) 962 932 return PTR_ERR(npath); 963 933 964 - rc = cache_refresh_path(xid, ses, npath); 965 - if (rc) 966 - goto out_free_path; 967 - 968 - down_read(&htable_rw_lock); 969 - 970 - ce = lookup_cache_entry(npath); 934 + ce = cache_refresh_path(xid, ses, npath, false); 971 935 if (IS_ERR(ce)) { 972 - up_read(&htable_rw_lock); 973 936 rc = PTR_ERR(ce); 974 937 goto out_free_path; 975 938 } ··· 1026 1003 } 1027 1004 1028 1005 /** 1029 - * dfs_cache_update_tgthint - update target hint of a DFS cache entry 1030 - * 1031 - * If it doesn't find the cache entry, then it will get a DFS referral for @path 1032 - * and create a new entry. 1033 - * 1034 - * In case the cache entry exists but expired, it will get a DFS referral 1035 - * for @path and then update the respective cache entry. 1036 - * 1037 - * @xid: syscall id 1038 - * @ses: smb session 1039 - * @cp: codepage 1040 - * @remap: type of character remapping for paths 1041 - * @path: path to lookup in DFS referral cache 1042 - * @it: DFS target iterator 1043 - * 1044 - * Return zero if the target hint was updated successfully, otherwise non-zero. 1045 - */ 1046 - int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses, 1047 - const struct nls_table *cp, int remap, const char *path, 1048 - const struct dfs_cache_tgt_iterator *it) 1049 - { 1050 - int rc; 1051 - const char *npath; 1052 - struct cache_entry *ce; 1053 - struct cache_dfs_tgt *t; 1054 - 1055 - npath = dfs_cache_canonical_path(path, cp, remap); 1056 - if (IS_ERR(npath)) 1057 - return PTR_ERR(npath); 1058 - 1059 - cifs_dbg(FYI, "%s: update target hint - path: %s\n", __func__, npath); 1060 - 1061 - rc = cache_refresh_path(xid, ses, npath); 1062 - if (rc) 1063 - goto out_free_path; 1064 - 1065 - down_write(&htable_rw_lock); 1066 - 1067 - ce = lookup_cache_entry(npath); 1068 - if (IS_ERR(ce)) { 1069 - rc = PTR_ERR(ce); 1070 - goto out_unlock; 1071 - } 1072 - 1073 - t = ce->tgthint; 1074 - 1075 - if (likely(!strcasecmp(it->it_name, t->name))) 1076 - goto out_unlock; 1077 - 1078 - list_for_each_entry(t, &ce->tlist, list) { 1079 - if (!strcasecmp(t->name, it->it_name)) { 1080 - ce->tgthint = t; 1081 - cifs_dbg(FYI, "%s: new target hint: %s\n", __func__, 1082 - it->it_name); 1083 - break; 1084 - } 1085 - } 1086 - 1087 - out_unlock: 1088 - up_write(&htable_rw_lock); 1089 - out_free_path: 1090 - kfree(npath); 1091 - return rc; 1092 - } 1093 - 1094 - /** 1095 1006 * dfs_cache_noreq_update_tgthint - update target hint of a DFS cache entry 1096 1007 * without sending any requests to the currently connected server. 1097 1008 * ··· 1049 1092 1050 1093 cifs_dbg(FYI, "%s: path: %s\n", __func__, path); 1051 1094 1052 - if (!down_write_trylock(&htable_rw_lock)) 1053 - return; 1095 + down_read(&htable_rw_lock); 1054 1096 1055 1097 ce = lookup_cache_entry(path); 1056 1098 if (IS_ERR(ce)) 1057 1099 goto out_unlock; 1058 1100 1059 - t = ce->tgthint; 1101 + t = READ_ONCE(ce->tgthint); 1060 1102 1061 1103 if (unlikely(!strcasecmp(it->it_name, t->name))) 1062 1104 goto out_unlock; 1063 1105 1064 1106 list_for_each_entry(t, &ce->tlist, list) { 1065 1107 if (!strcasecmp(t->name, it->it_name)) { 1066 - ce->tgthint = t; 1108 + WRITE_ONCE(ce->tgthint, t); 1067 1109 cifs_dbg(FYI, "%s: new target hint: %s\n", __func__, 1068 1110 it->it_name); 1069 1111 break; ··· 1070 1114 } 1071 1115 1072 1116 out_unlock: 1073 - up_write(&htable_rw_lock); 1117 + up_read(&htable_rw_lock); 1074 1118 } 1075 1119 1076 1120 /** ··· 1276 1320 * Mark dfs tcon for reconnecting when the currently connected tcon does not match any of the new 1277 1321 * target shares in @refs. 1278 1322 */ 1279 - static void mark_for_reconnect_if_needed(struct cifs_tcon *tcon, struct dfs_cache_tgt_list *tl, 1280 - const struct dfs_info3_param *refs, int numrefs) 1323 + static void mark_for_reconnect_if_needed(struct TCP_Server_Info *server, 1324 + struct dfs_cache_tgt_list *old_tl, 1325 + struct dfs_cache_tgt_list *new_tl) 1281 1326 { 1282 - struct dfs_cache_tgt_iterator *it; 1283 - int i; 1327 + struct dfs_cache_tgt_iterator *oit, *nit; 1284 1328 1285 - for (it = dfs_cache_get_tgt_iterator(tl); it; it = dfs_cache_get_next_tgt(tl, it)) { 1286 - for (i = 0; i < numrefs; i++) { 1287 - if (target_share_equal(tcon->ses->server, dfs_cache_get_tgt_name(it), 1288 - refs[i].node_name)) 1329 + for (oit = dfs_cache_get_tgt_iterator(old_tl); oit; 1330 + oit = dfs_cache_get_next_tgt(old_tl, oit)) { 1331 + for (nit = dfs_cache_get_tgt_iterator(new_tl); nit; 1332 + nit = dfs_cache_get_next_tgt(new_tl, nit)) { 1333 + if (target_share_equal(server, 1334 + dfs_cache_get_tgt_name(oit), 1335 + dfs_cache_get_tgt_name(nit))) 1289 1336 return; 1290 1337 } 1291 1338 } 1292 1339 1293 1340 cifs_dbg(FYI, "%s: no cached or matched targets. mark dfs share for reconnect.\n", __func__); 1294 - cifs_signal_cifsd_for_reconnect(tcon->ses->server, true); 1341 + cifs_signal_cifsd_for_reconnect(server, true); 1295 1342 } 1296 1343 1297 1344 /* Refresh dfs referral of tcon and mark it for reconnect if needed */ 1298 1345 static int __refresh_tcon(const char *path, struct cifs_tcon *tcon, bool force_refresh) 1299 1346 { 1300 - struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl); 1347 + struct dfs_cache_tgt_list old_tl = DFS_CACHE_TGT_LIST_INIT(old_tl); 1348 + struct dfs_cache_tgt_list new_tl = DFS_CACHE_TGT_LIST_INIT(new_tl); 1301 1349 struct cifs_ses *ses = CIFS_DFS_ROOT_SES(tcon->ses); 1302 1350 struct cifs_tcon *ipc = ses->tcon_ipc; 1303 - struct dfs_info3_param *refs = NULL; 1304 1351 bool needs_refresh = false; 1305 1352 struct cache_entry *ce; 1306 1353 unsigned int xid; 1307 - int numrefs = 0; 1308 1354 int rc = 0; 1309 1355 1310 1356 xid = get_xid(); ··· 1315 1357 ce = lookup_cache_entry(path); 1316 1358 needs_refresh = force_refresh || IS_ERR(ce) || cache_entry_expired(ce); 1317 1359 if (!IS_ERR(ce)) { 1318 - rc = get_targets(ce, &tl); 1319 - if (rc) 1320 - cifs_dbg(FYI, "%s: could not get dfs targets: %d\n", __func__, rc); 1360 + rc = get_targets(ce, &old_tl); 1361 + cifs_dbg(FYI, "%s: get_targets: %d\n", __func__, rc); 1321 1362 } 1322 1363 up_read(&htable_rw_lock); 1323 1364 ··· 1333 1376 } 1334 1377 spin_unlock(&ipc->tc_lock); 1335 1378 1336 - rc = get_dfs_referral(xid, ses, path, &refs, &numrefs); 1337 - if (!rc) { 1338 - /* Create or update a cache entry with the new referral */ 1339 - dump_refs(refs, numrefs); 1340 - 1341 - down_write(&htable_rw_lock); 1342 - ce = lookup_cache_entry(path); 1343 - if (IS_ERR(ce)) 1344 - add_cache_entry_locked(refs, numrefs); 1345 - else if (force_refresh || cache_entry_expired(ce)) 1346 - update_cache_entry_locked(ce, refs, numrefs); 1347 - up_write(&htable_rw_lock); 1348 - 1349 - mark_for_reconnect_if_needed(tcon, &tl, refs, numrefs); 1379 + ce = cache_refresh_path(xid, ses, path, true); 1380 + if (!IS_ERR(ce)) { 1381 + rc = get_targets(ce, &new_tl); 1382 + up_read(&htable_rw_lock); 1383 + cifs_dbg(FYI, "%s: get_targets: %d\n", __func__, rc); 1384 + mark_for_reconnect_if_needed(tcon->ses->server, &old_tl, &new_tl); 1350 1385 } 1351 1386 1352 1387 out: 1353 1388 free_xid(xid); 1354 - dfs_cache_free_tgts(&tl); 1355 - free_dfs_info_array(refs, numrefs); 1389 + dfs_cache_free_tgts(&old_tl); 1390 + dfs_cache_free_tgts(&new_tl); 1356 1391 return rc; 1357 1392 } 1358 1393
-3
fs/cifs/dfs_cache.h
··· 35 35 struct dfs_cache_tgt_list *tgt_list); 36 36 int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref, 37 37 struct dfs_cache_tgt_list *tgt_list); 38 - int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses, 39 - const struct nls_table *cp, int remap, const char *path, 40 - const struct dfs_cache_tgt_iterator *it); 41 38 void dfs_cache_noreq_update_tgthint(const char *path, const struct dfs_cache_tgt_iterator *it); 42 39 int dfs_cache_get_tgt_referral(const char *path, const struct dfs_cache_tgt_iterator *it, 43 40 struct dfs_info3_param *ref);
+9 -6
fs/cifs/smb2pdu.c
··· 4163 4163 (struct smb2_hdr *)rdata->iov[0].iov_base; 4164 4164 struct cifs_credits credits = { .value = 0, .instance = 0 }; 4165 4165 struct smb_rqst rqst = { .rq_iov = &rdata->iov[1], 4166 - .rq_nvec = 1, 4167 - .rq_pages = rdata->pages, 4168 - .rq_offset = rdata->page_offset, 4169 - .rq_npages = rdata->nr_pages, 4170 - .rq_pagesz = rdata->pagesz, 4171 - .rq_tailsz = rdata->tailsz }; 4166 + .rq_nvec = 1, }; 4167 + 4168 + if (rdata->got_bytes) { 4169 + rqst.rq_pages = rdata->pages; 4170 + rqst.rq_offset = rdata->page_offset; 4171 + rqst.rq_npages = rdata->nr_pages; 4172 + rqst.rq_pagesz = rdata->pagesz; 4173 + rqst.rq_tailsz = rdata->tailsz; 4174 + } 4172 4175 4173 4176 WARN_ONCE(rdata->server != mid->server, 4174 4177 "rdata server %p != mid server %p",