Pull ceph updates from Ilya Dryomov: "A wide variety of mostly CephFS fixes and cleanups, split between changes that address edge cases (Sam, Xiubo, Matthew), efficiency improvements (Max) and AI-assisted hardening (Michael, Jeremy). One thing that stands out is Alex's change to how CephFS behaves in NEARFULL scenarios: the long-standing "make all writes synchronous" behavior has become opt-in. It was always somewhat controversial and doesn't make much sense for modern deployments; the new default is to continue normal operation (i.e. buffer writes as MDS allows, etc). The behavior in case the cluster reaches any FULL state remains the same as before" * tag 'ceph-for-7.3-rc1' of https://github.com/ceph/ceph-client: (32 commits) ceph: force a cap message when a deferred revoke can't be acked immediately libceph: reject buckets with mismatched CRUSH ids ceph: reject export_targets ranks >= CEPH_MAX_MDS in mdsmap decode ceph: fix leaked inode reference on writeback abort at umount libceph: remove ceph_put_page_vector() libceph: validate banner payload length ceph: make nearfull sync writes opt-in ceph: do not repeat ceph_trim_dentries() if no progress possible ceph: drop mdsc->mutex before decoding the MDS reply ceph: fix UAF in check_new_map() on session freed during unlock ceph: fix UAF in __kick_flushing_caps() on cf entry freed during unlock ceph: pass inode pointer around instead of reloading it ceph: mark cap remove with RB_CLEAR_NODE() instead of setting ci=NULL ceph: add helper function ceph_cap_is_removed() ceph: make __ceph_remove_cap() static ceph: cap delegated inode count in ceph_parse_deleg_inos() ceph: bound num_export_targets array for mds info v2/v3 ceph: bound MDSCapAuth path and fs_name decode in handle_session() ceph: bound xattr value length in __build_xattrs() ceph: bound copied dentry name length in NFS export get_name ...
Unified · Split
| @@ -194,6 +194,12 @@ Mount Options · 193 unmodified lines | |||
| 194 | copies. Currently, it's only used in copy_file_range, which will revert | 194 | copies. Currently, it's only used in copy_file_range, which will revert |
| 195 | to the default VFS implementation if this option is used. | 195 | to the default VFS implementation if this option is used. |
| 196 | 196 | ||
| 197 | nearfull_sync | ||
| 198 | Force written data to stable storage when the cluster or file data pool is | ||
| 199 | marked NEARFULL. This restores the legacy client-side backpressure | ||
| 200 | behavior. By default, CephFS writes are not forced synchronous solely | ||
| 201 | because of NEARFULL. | ||
| 202 | |||
| 197 | recover_session=<no|clean> | 203 | recover_session=<no|clean> |
| 198 | Set auto reconnect mode in the case where the client is blocklisted. The | 204 | Set auto reconnect mode in the case where the client is blocklisted. The |
| 199 | available modes are "no" and "clean". The default is "no". | 205 | available modes are "no" and "clean". The default is "no". |
| @@ -255,9 +255,12 @@ static void finish_netfs_read(struct ceph_osd_request *req) · 254 unmodified lines | |||
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | if (osd_data->type == CEPH_OSD_DATA_TYPE_PAGES) { | 257 | if (osd_data->type == CEPH_OSD_DATA_TYPE_PAGES) { |
| 258 | ceph_put_page_vector(osd_data->pages, | 258 | int num_pages = calc_pages_for(osd_data->alignment, |
| 259 | calc_pages_for(osd_data->alignment, | 259 | osd_data->length); |
| 260 | osd_data->length), false); | 260 | |
| 261 | for (int i = 0; i < num_pages; i++) | ||
| 262 | put_page(osd_data->pages[i]); | ||
| 263 | kvfree(osd_data->pages); | ||
| 261 | } | 264 | } |
| 262 | if (err > 0) { | 265 | if (err > 0) { |
| 263 | ceph_subvolume_metrics_record_io(fsc->mdsc, ceph_inode(inode), | 266 | ceph_subvolume_metrics_record_io(fsc->mdsc, ceph_inode(inode), |
| @@ -1426,6 +1429,16 @@ void ceph_shift_unused_folios_left(struct folio_batch *fbatch) · 1162 unmodified lines | |||
| 1426 | fbatch->nr = n; | 1429 | fbatch->nr = n; |
| 1427 | } | 1430 | } |
| 1428 | 1431 | ||
| 1432 | static void ceph_undo_wrbuffer_claim(struct inode *inode, struct folio *folio) | ||
| 1433 | { | ||
| 1434 | struct ceph_snap_context *snapc = folio_detach_private(folio); | ||
| 1435 | |||
| 1436 | if (!snapc) | ||
| 1437 | return; | ||
| 1438 | ceph_put_wrbuffer_cap_refs(ceph_inode(inode), 1, snapc); | ||
| 1439 | ceph_put_snap_context(snapc); | ||
| 1440 | } | ||
| 1441 | |||
| 1429 | static | 1442 | static |
| 1430 | int ceph_submit_write(struct address_space *mapping, | 1443 | int ceph_submit_write(struct address_space *mapping, |
| 1431 | struct writeback_control *wbc, | 1444 | struct writeback_control *wbc, |
| @@ -1489,6 +1502,7 @@ new_request: · 57 unmodified lines | |||
| 1489 | if (!page) | 1502 | if (!page) |
| 1490 | continue; | 1503 | continue; |
| 1491 | 1504 | ||
| 1505 | ceph_undo_wrbuffer_claim(inode, page_folio(page)); | ||
| 1492 | redirty_page_for_writepage(wbc, page); | 1506 | redirty_page_for_writepage(wbc, page); |
| 1493 | unlock_page(page); | 1507 | unlock_page(page); |
| 1494 | } | 1508 | } |
| @@ -2464,7 +2478,7 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci, · 969 unmodified lines | |||
| 2464 | } | 2478 | } |
| 2465 | 2479 | ||
| 2466 | rd_req = ceph_osdc_alloc_request(&fsc->client->osdc, NULL, | 2480 | rd_req = ceph_osdc_alloc_request(&fsc->client->osdc, NULL, |
| 2467 | 1, false, GFP_NOFS); | 2481 | 1, false, GFP_KERNEL); |
| 2468 | if (!rd_req) { | 2482 | if (!rd_req) { |
| 2469 | err = -ENOMEM; | 2483 | err = -ENOMEM; |
| 2470 | goto out_unlock; | 2484 | goto out_unlock; |
| @@ -2477,12 +2491,12 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci, · 6 unmodified lines | |||
| 2477 | rd_req->r_base_oloc.pool_ns = ceph_get_string(pool_ns); | 2491 | rd_req->r_base_oloc.pool_ns = ceph_get_string(pool_ns); |
| 2478 | ceph_oid_printf(&rd_req->r_base_oid, "%llx.00000000", ci->i_vino.ino); | 2492 | ceph_oid_printf(&rd_req->r_base_oid, "%llx.00000000", ci->i_vino.ino); |
| 2479 | 2493 | ||
| 2480 | err = ceph_osdc_alloc_messages(rd_req, GFP_NOFS); | 2494 | err = ceph_osdc_alloc_messages(rd_req, GFP_KERNEL); |
| 2481 | if (err) | 2495 | if (err) |
| 2482 | goto out_unlock; | 2496 | goto out_unlock; |
| 2483 | 2497 | ||
| 2484 | wr_req = ceph_osdc_alloc_request(&fsc->client->osdc, NULL, | 2498 | wr_req = ceph_osdc_alloc_request(&fsc->client->osdc, NULL, |
| 2485 | 1, false, GFP_NOFS); | 2499 | 1, false, GFP_KERNEL); |
| 2486 | if (!wr_req) { | 2500 | if (!wr_req) { |
| 2487 | err = -ENOMEM; | 2501 | err = -ENOMEM; |
| 2488 | goto out_unlock; | 2502 | goto out_unlock; |
| @@ -2493,7 +2507,7 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci, · 4 unmodified lines | |||
| 2493 | ceph_oloc_copy(&wr_req->r_base_oloc, &rd_req->r_base_oloc); | 2507 | ceph_oloc_copy(&wr_req->r_base_oloc, &rd_req->r_base_oloc); |
| 2494 | ceph_oid_copy(&wr_req->r_base_oid, &rd_req->r_base_oid); | 2508 | ceph_oid_copy(&wr_req->r_base_oid, &rd_req->r_base_oid); |
| 2495 | 2509 | ||
| 2496 | err = ceph_osdc_alloc_messages(wr_req, GFP_NOFS); | 2510 | err = ceph_osdc_alloc_messages(wr_req, GFP_KERNEL); |
| 2497 | if (err) | 2511 | if (err) |
| 2498 | goto out_unlock; | 2512 | goto out_unlock; |
| 2499 | 2513 | ||
| @@ -2532,7 +2546,7 @@ static int __ceph_pool_perm_get(struct ceph_inode_info *ci, · 32 unmodified lines | |||
| 2532 | } | 2546 | } |
| 2533 | 2547 | ||
| 2534 | pool_ns_len = pool_ns ? pool_ns->len : 0; | 2548 | pool_ns_len = pool_ns ? pool_ns->len : 0; |
| 2535 | perm = kmalloc_flex(*perm, pool_ns, pool_ns_len + 1, GFP_NOFS); | 2549 | perm = kmalloc_flex(*perm, pool_ns, pool_ns_len + 1, GFP_KERNEL); |
| 2536 | if (!perm) { | 2550 | if (!perm) { |
| 2537 | err = -ENOMEM; | 2551 | err = -ENOMEM; |
| 2538 | goto out_unlock; | 2552 | goto out_unlock; |
| @@ -785,9 +785,9 @@ void ceph_add_cap(struct inode *inode, · 784 unmodified lines | |||
| 785 | * generation of the MDS session (i.e. has not gone 'stale' due to | 785 | * generation of the MDS session (i.e. has not gone 'stale' due to |
| 786 | * us losing touch with the mds). | 786 | * us losing touch with the mds). |
| 787 | */ | 787 | */ |
| 788 | static int __cap_is_valid(struct ceph_cap *cap) | 788 | static int __cap_is_valid(struct ceph_inode_info *ci, struct ceph_cap *cap) |
| 789 | { | 789 | { |
| 790 | struct inode *inode = &cap->ci->netfs.inode; | 790 | struct inode *inode = &ci->netfs.inode; |
| 791 | struct ceph_client *cl = cap->session->s_mdsc->fsc->client; | 791 | struct ceph_client *cl = cap->session->s_mdsc->fsc->client; |
| 792 | unsigned long ttl; | 792 | unsigned long ttl; |
| 793 | u32 gen; | 793 | u32 gen; |
| @@ -822,7 +822,7 @@ int __ceph_caps_issued(struct ceph_inode_info *ci, int *implemented) · 28 unmodified lines | |||
| 822 | *implemented = 0; | 822 | *implemented = 0; |
| 823 | for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { | 823 | for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { |
| 824 | cap = rb_entry(p, struct ceph_cap, ci_node); | 824 | cap = rb_entry(p, struct ceph_cap, ci_node); |
| 825 | if (!__cap_is_valid(cap)) | 825 | if (!__cap_is_valid(ci, cap)) |
| 826 | continue; | 826 | continue; |
| 827 | doutc(cl, "%p %llx.%llx cap %p issued %s\n", inode, | 827 | doutc(cl, "%p %llx.%llx cap %p issued %s\n", inode, |
| 828 | ceph_vinop(inode), cap, ceph_cap_string(cap->issued)); | 828 | ceph_vinop(inode), cap, ceph_cap_string(cap->issued)); |
| @@ -855,7 +855,7 @@ int __ceph_caps_issued_other(struct ceph_inode_info *ci, struct ceph_cap *ocap) · 26 unmodified lines | |||
| 855 | cap = rb_entry(p, struct ceph_cap, ci_node); | 855 | cap = rb_entry(p, struct ceph_cap, ci_node); |
| 856 | if (cap == ocap) | 856 | if (cap == ocap) |
| 857 | continue; | 857 | continue; |
| 858 | if (!__cap_is_valid(cap)) | 858 | if (!__cap_is_valid(ci, cap)) |
| 859 | continue; | 859 | continue; |
| 860 | have |= cap->issued; | 860 | have |= cap->issued; |
| 861 | } | 861 | } |
| @@ -866,11 +866,19 @@ int __ceph_caps_issued_other(struct ceph_inode_info *ci, struct ceph_cap *ocap) · 4 unmodified lines | |||
| 866 | * Move a cap to the end of the LRU (oldest caps at list head, newest | 866 | * Move a cap to the end of the LRU (oldest caps at list head, newest |
| 867 | * at list tail). | 867 | * at list tail). |
| 868 | */ | 868 | */ |
| 869 | static void __touch_cap(struct ceph_cap *cap) | 869 | static void __touch_cap(struct ceph_inode_info *ci, struct ceph_cap *cap) |
| 870 | { | 870 | { |
| 871 | struct inode *inode = &cap->ci->netfs.inode; | 871 | struct inode *inode = &ci->netfs.inode; |
| 872 | struct ceph_mds_session *s = cap->session; | 872 | struct ceph_mds_session *s = cap->session; |
| 873 | struct ceph_client *cl = s->s_mdsc->fsc->client; | 873 | struct ceph_client *cl = s->s_mdsc->fsc->client; |
| 874 | static u8 skip_counter; | ||
| 875 | |||
| 876 | if (data_race(++skip_counter)) | ||
| 877 | /* skip this call most of the time to reduce lock | ||
| 878 | * contention; the LRU list is still accurate enough | ||
| 879 | * for ceph_trim_caps() | ||
| 880 | */ | ||
| 881 | return; | ||
| 874 | 882 | ||
| 875 | spin_lock(&s->s_cap_lock); | 883 | spin_lock(&s->s_cap_lock); |
| 876 | if (!s->s_cap_iterator) { | 884 | if (!s->s_cap_iterator) { |
| @@ -906,7 +914,7 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) · 29 unmodified lines | |||
| 906 | 914 | ||
| 907 | for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { | 915 | for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { |
| 908 | cap = rb_entry(p, struct ceph_cap, ci_node); | 916 | cap = rb_entry(p, struct ceph_cap, ci_node); |
| 909 | if (!__cap_is_valid(cap)) | 917 | if (!__cap_is_valid(ci, cap)) |
| 910 | continue; | 918 | continue; |
| 911 | if ((cap->issued & mask) == mask) { | 919 | if ((cap->issued & mask) == mask) { |
| 912 | doutc(cl, "mask %p %llx.%llx cap %p issued %s (mask %s)\n", | 920 | doutc(cl, "mask %p %llx.%llx cap %p issued %s (mask %s)\n", |
| @@ -914,7 +922,7 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) · 1 unmodified line | |||
| 914 | ceph_cap_string(cap->issued), | 922 | ceph_cap_string(cap->issued), |
| 915 | ceph_cap_string(mask)); | 923 | ceph_cap_string(mask)); |
| 916 | if (touch) | 924 | if (touch) |
| 917 | __touch_cap(cap); | 925 | __touch_cap(ci, cap); |
| 918 | return 1; | 926 | return 1; |
| 919 | } | 927 | } |
| 920 | 928 | ||
| @@ -929,15 +937,15 @@ int __ceph_caps_issued_mask(struct ceph_inode_info *ci, int mask, int touch) · 8 unmodified lines | |||
| 929 | struct rb_node *q; | 937 | struct rb_node *q; |
| 930 | 938 | ||
| 931 | /* touch this + preceding caps */ | 939 | /* touch this + preceding caps */ |
| 932 | __touch_cap(cap); | 940 | __touch_cap(ci, cap); |
| 933 | for (q = rb_first(&ci->i_caps); q != p; | 941 | for (q = rb_first(&ci->i_caps); q != p; |
| 934 | q = rb_next(q)) { | 942 | q = rb_next(q)) { |
| 935 | cap = rb_entry(q, struct ceph_cap, | 943 | cap = rb_entry(q, struct ceph_cap, |
| 936 | ci_node); | 944 | ci_node); |
| 937 | if (!__cap_is_valid(cap)) | 945 | if (!__cap_is_valid(ci, cap)) |
| 938 | continue; | 946 | continue; |
| 939 | if (cap->issued & mask) | 947 | if (cap->issued & mask) |
| 940 | __touch_cap(cap); | 948 | __touch_cap(ci, cap); |
| 941 | } | 949 | } |
| 942 | } | 950 | } |
| 943 | return 1; | 951 | return 1; |
| @@ -979,6 +987,27 @@ int __ceph_caps_revoking_other(struct ceph_inode_info *ci, · 35 unmodified lines | |||
| 979 | return 0; | 987 | return 0; |
| 980 | } | 988 | } |
| 981 | 989 | ||
| 990 | /* | ||
| 991 | * Return true if any cap of this inode holds caps which the MDS has | ||
| 992 | * revoked, but which we have not released yet. | ||
| 993 | */ | ||
| 994 | static bool __ceph_is_any_revoking(const struct ceph_inode_info *ci) | ||
| 995 | { | ||
| 996 | const struct rb_node *p; | ||
| 997 | |||
| 998 | lockdep_assert_held(&ci->i_ceph_lock); | ||
| 999 | |||
| 1000 | for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { | ||
| 1001 | const struct ceph_cap *cap = | ||
| 1002 | rb_entry(p, struct ceph_cap, ci_node); | ||
| 1003 | |||
| 1004 | if (cap->implemented & ~cap->issued) | ||
| 1005 | return true; | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | return false; | ||
| 1009 | } | ||
| 1010 | |||
| 982 | int __ceph_caps_used(struct ceph_inode_info *ci) | 1011 | int __ceph_caps_used(struct ceph_inode_info *ci) |
| 983 | { | 1012 | { |
| 984 | int used = 0; | 1013 | int used = 0; |
| @@ -1091,7 +1120,7 @@ int __ceph_caps_mds_wanted(struct ceph_inode_info *ci, bool check) · 106 unmodified lines | |||
| 1091 | 1120 | ||
| 1092 | for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { | 1121 | for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { |
| 1093 | cap = rb_entry(p, struct ceph_cap, ci_node); | 1122 | cap = rb_entry(p, struct ceph_cap, ci_node); |
| 1094 | if (check && !__cap_is_valid(cap)) | 1123 | if (check && !__cap_is_valid(ci, cap)) |
| 1095 | continue; | 1124 | continue; |
| 1096 | if (cap == ci->i_auth_cap) | 1125 | if (cap == ci->i_auth_cap) |
| 1097 | mds_wanted |= cap->mds_wanted; | 1126 | mds_wanted |= cap->mds_wanted; |
| @@ -1119,20 +1148,20 @@ int ceph_is_any_caps(struct inode *inode) · 21 unmodified lines | |||
| 1119 | * caller should hold i_ceph_lock. | 1148 | * caller should hold i_ceph_lock. |
| 1120 | * caller will not hold session s_mutex if called from destroy_inode. | 1149 | * caller will not hold session s_mutex if called from destroy_inode. |
| 1121 | */ | 1150 | */ |
| 1122 | void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release) | 1151 | static void __ceph_remove_cap(struct ceph_inode_info *ci, struct ceph_cap *cap, bool queue_release) |
| 1123 | { | 1152 | { |
| 1124 | struct ceph_mds_session *session = cap->session; | 1153 | struct ceph_mds_session *session; |
| 1125 | struct ceph_client *cl = session->s_mdsc->fsc->client; | 1154 | struct ceph_client *cl; |
| 1126 | struct ceph_inode_info *ci = cap->ci; | 1155 | struct inode *inode; |
| 1127 | struct inode *inode = &ci->netfs.inode; | ||
| 1128 | struct ceph_mds_client *mdsc; | 1156 | struct ceph_mds_client *mdsc; |
| 1129 | int removed = 0; | 1157 | int removed = 0; |
| 1130 | 1158 | ||
| 1131 | /* 'ci' being NULL means the remove have already occurred */ | 1159 | if (ceph_cap_is_removed(cap)) |
| 1132 | if (!ci) { | ||
| 1133 | doutc(cl, "inode is NULL\n"); | ||
| 1134 | return; | 1160 | return; |
| 1135 | } | 1161 | |
| 1162 | session = cap->session; | ||
| 1163 | cl = session->s_mdsc->fsc->client; | ||
| 1164 | inode = &ci->netfs.inode; | ||
| 1136 | 1165 | ||
| 1137 | lockdep_assert_held(&ci->i_ceph_lock); | 1166 | lockdep_assert_held(&ci->i_ceph_lock); |
| 1138 | 1167 | ||
| @@ -1158,8 +1187,11 @@ void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release) · 19 unmodified lines | |||
| 1158 | cap->session = NULL; | 1187 | cap->session = NULL; |
| 1159 | removed = 1; | 1188 | removed = 1; |
| 1160 | } | 1189 | } |
| 1161 | /* protect backpointer with s_cap_lock: see iterate_session_caps */ | 1190 | |
| 1162 | cap->ci = NULL; | 1191 | /* protect removal marker with both i_ceph_lock and |
| 1192 | s_cap_lock, so either one can be used to check for | ||
| 1193 | removal */ | ||
| 1194 | RB_CLEAR_NODE(&cap->ci_node); | ||
| 1163 | 1195 | ||
| 1164 | /* | 1196 | /* |
| 1165 | * s_cap_reconnect is protected by s_cap_lock. no one changes | 1197 | * s_cap_reconnect is protected by s_cap_lock. no one changes |
| @@ -1196,13 +1228,12 @@ void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release) · 30 unmodified lines | |||
| 1196 | } | 1228 | } |
| 1197 | 1229 | ||
| 1198 | void ceph_remove_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, | 1230 | void ceph_remove_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, |
| 1231 | struct ceph_inode_info *ci, | ||
| 1199 | bool queue_release) | 1232 | bool queue_release) |
| 1200 | { | 1233 | { |
| 1201 | struct ceph_inode_info *ci = cap->ci; | ||
| 1202 | struct ceph_fs_client *fsc; | 1234 | struct ceph_fs_client *fsc; |
| 1203 | 1235 | ||
| 1204 | /* 'ci' being NULL means the remove have already occurred */ | 1236 | if (ceph_cap_is_removed(cap)) { |
| 1205 | if (!ci) { | ||
| 1206 | doutc(mdsc->fsc->client, "inode is NULL\n"); | 1237 | doutc(mdsc->fsc->client, "inode is NULL\n"); |
| 1207 | return; | 1238 | return; |
| 1208 | } | 1239 | } |
| @@ -1215,7 +1246,7 @@ void ceph_remove_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, · 6 unmodified lines | |||
| 1215 | !fsc->blocklisted && | 1246 | !fsc->blocklisted && |
| 1216 | !ceph_inode_is_shutdown(&ci->netfs.inode)); | 1247 | !ceph_inode_is_shutdown(&ci->netfs.inode)); |
| 1217 | 1248 | ||
| 1218 | __ceph_remove_cap(cap, queue_release); | 1249 | __ceph_remove_cap(ci, cap, queue_release); |
| 1219 | } | 1250 | } |
| 1220 | 1251 | ||
| 1221 | struct cap_msg_args { | 1252 | struct cap_msg_args { |
| @@ -1375,7 +1406,7 @@ void __ceph_remove_caps(struct ceph_inode_info *ci) · 153 unmodified lines | |||
| 1375 | while (p) { | 1406 | while (p) { |
| 1376 | struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node); | 1407 | struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node); |
| 1377 | p = rb_next(p); | 1408 | p = rb_next(p); |
| 1378 | ceph_remove_cap(mdsc, cap, true); | 1409 | ceph_remove_cap(mdsc, cap, ci, true); |
| 1379 | } | 1410 | } |
| 1380 | spin_unlock(&ci->i_ceph_lock); | 1411 | spin_unlock(&ci->i_ceph_lock); |
| 1381 | } | 1412 | } |
| @@ -1388,11 +1419,11 @@ void __ceph_remove_caps(struct ceph_inode_info *ci) · 6 unmodified lines | |||
| 1388 | * Make note of max_size reported/requested from mds, revoked caps | 1419 | * Make note of max_size reported/requested from mds, revoked caps |
| 1389 | * that have now been implemented. | 1420 | * that have now been implemented. |
| 1390 | */ | 1421 | */ |
| 1391 | static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap, | 1422 | static void __prep_cap(struct cap_msg_args *arg, struct ceph_inode_info *ci, |
| 1423 | struct ceph_cap *cap, | ||
| 1392 | int op, int flags, int used, int want, int retain, | 1424 | int op, int flags, int used, int want, int retain, |
| 1393 | int flushing, u64 flush_tid, u64 oldest_flush_tid) | 1425 | int flushing, u64 flush_tid, u64 oldest_flush_tid) |
| 1394 | { | 1426 | { |
| 1395 | struct ceph_inode_info *ci = cap->ci; | ||
| 1396 | struct inode *inode = &ci->netfs.inode; | 1427 | struct inode *inode = &ci->netfs.inode; |
| 1397 | struct ceph_client *cl = ceph_inode_to_client(inode); | 1428 | struct ceph_client *cl = ceph_inode_to_client(inode); |
| 1398 | int held, revoking; | 1429 | int held, revoking; |
| @@ -1421,6 +1452,9 @@ static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap, · 22 unmodified lines | |||
| 1421 | cap->implemented &= cap->issued | used; | 1452 | cap->implemented &= cap->issued | used; |
| 1422 | cap->mds_wanted = want; | 1453 | cap->mds_wanted = want; |
| 1423 | 1454 | ||
| 1455 | if ((ci->i_ceph_flags & CEPH_I_FLUSH_FORCE) != 0 && !__ceph_is_any_revoking(ci)) | ||
| 1456 | clear_bit(CEPH_I_FLUSH_FORCE_BIT, &ci->i_ceph_flags); | ||
| 1457 | |||
| 1424 | arg->session = cap->session; | 1458 | arg->session = cap->session; |
| 1425 | arg->ino = ceph_vino(inode).ino; | 1459 | arg->ino = ceph_vino(inode).ino; |
| 1426 | arg->cid = cap->cap_id; | 1460 | arg->cid = cap->cap_id; |
| @@ -1842,7 +1876,7 @@ struct ceph_cap_flush *ceph_alloc_cap_flush(void) · 415 unmodified lines | |||
| 1842 | { | 1876 | { |
| 1843 | struct ceph_cap_flush *cf; | 1877 | struct ceph_cap_flush *cf; |
| 1844 | 1878 | ||
| 1845 | cf = kmem_cache_alloc(ceph_cap_flush_cachep, GFP_KERNEL); | 1879 | cf = kmem_cache_alloc(ceph_cap_flush_cachep, GFP_NOFS); |
| 1846 | if (!cf) | 1880 | if (!cf) |
| 1847 | return NULL; | 1881 | return NULL; |
| 1848 | 1882 | ||
| @@ -2038,6 +2072,14 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags) · 189 unmodified lines | |||
| 2038 | 2072 | ||
| 2039 | if (ci->i_ceph_flags & CEPH_I_FLUSH) | 2073 | if (ci->i_ceph_flags & CEPH_I_FLUSH) |
| 2040 | flags |= CHECK_CAPS_FLUSH; | 2074 | flags |= CHECK_CAPS_FLUSH; |
| 2075 | /* | ||
| 2076 | * A revoke whose response was deferred (see handle_cap_grant()) must | ||
| 2077 | * still be acknowledged. Replay the forced flush here so that even a | ||
| 2078 | * check triggered by writeback/invalidation completion sends a cap | ||
| 2079 | * message to the MDS. | ||
| 2080 | */ | ||
| 2081 | if (ci->i_ceph_flags & CEPH_I_FLUSH_FORCE) | ||
| 2082 | flags |= CHECK_CAPS_FLUSH_FORCE; | ||
| 2041 | retry: | 2083 | retry: |
| 2042 | /* Caps wanted by virtue of active open files. */ | 2084 | /* Caps wanted by virtue of active open files. */ |
| 2043 | file_wanted = __ceph_caps_file_wanted(ci); | 2085 | file_wanted = __ceph_caps_file_wanted(ci); |
| @@ -2210,7 +2252,7 @@ retry: · 166 unmodified lines | |||
| 2210 | if (want & ~cap->mds_wanted) { | 2252 | if (want & ~cap->mds_wanted) { |
| 2211 | if (want & ~(cap->mds_wanted | cap->issued)) | 2253 | if (want & ~(cap->mds_wanted | cap->issued)) |
| 2212 | goto ack; | 2254 | goto ack; |
| 2213 | if (!__cap_is_valid(cap)) | 2255 | if (!__cap_is_valid(ci, cap)) |
| 2214 | goto ack; | 2256 | goto ack; |
| 2215 | } | 2257 | } |
| 2216 | 2258 | ||
| @@ -2252,7 +2294,7 @@ ack: · 35 unmodified lines | |||
| 2252 | 2294 | ||
| 2253 | mds = cap->mds; /* remember mds, so we don't repeat */ | 2295 | mds = cap->mds; /* remember mds, so we don't repeat */ |
| 2254 | 2296 | ||
| 2255 | __prep_cap(&arg, cap, CEPH_CAP_OP_UPDATE, mflags, cap_used, | 2297 | __prep_cap(&arg, ci, cap, CEPH_CAP_OP_UPDATE, mflags, cap_used, |
| 2256 | want, retain, flushing, flush_tid, oldest_flush_tid); | 2298 | want, retain, flushing, flush_tid, oldest_flush_tid); |
| 2257 | 2299 | ||
| 2258 | spin_unlock(&ci->i_ceph_lock); | 2300 | spin_unlock(&ci->i_ceph_lock); |
| @@ -2314,7 +2356,7 @@ retry_locked: · 55 unmodified lines | |||
| 2314 | flush_tid = __mark_caps_flushing(inode, session, true, | 2356 | flush_tid = __mark_caps_flushing(inode, session, true, |
| 2315 | &oldest_flush_tid); | 2357 | &oldest_flush_tid); |
| 2316 | 2358 | ||
| 2317 | __prep_cap(&arg, cap, CEPH_CAP_OP_FLUSH, CEPH_CLIENT_CAPS_SYNC, | 2359 | __prep_cap(&arg, ci, cap, CEPH_CAP_OP_FLUSH, CEPH_CLIENT_CAPS_SYNC, |
| 2318 | __ceph_caps_used(ci), __ceph_caps_wanted(ci), | 2360 | __ceph_caps_used(ci), __ceph_caps_wanted(ci), |
| 2319 | (cap->issued | cap->implemented), | 2361 | (cap->issued | cap->implemented), |
| 2320 | flushing, flush_tid, oldest_flush_tid); | 2362 | flushing, flush_tid, oldest_flush_tid); |
| @@ -2589,9 +2631,14 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc, · 268 unmodified lines | |||
| 2589 | } | 2631 | } |
| 2590 | } | 2632 | } |
| 2591 | 2633 | ||
| 2592 | list_for_each_entry(cf, &ci->i_cap_flush_list, i_list) { | 2634 | cf = list_first_entry(&ci->i_cap_flush_list, struct ceph_cap_flush, i_list); |
| 2593 | if (cf->tid < first_tid) | 2635 | while (&cf->i_list != &ci->i_cap_flush_list) { |
| 2636 | struct ceph_cap_flush *next; | ||
| 2637 | |||
| 2638 | if (cf->tid < first_tid) { | ||
| 2639 | cf = list_next_entry(cf, i_list); | ||
| 2594 | continue; | 2640 | continue; |
| 2641 | } | ||
| 2595 | 2642 | ||
| 2596 | cap = ci->i_auth_cap; | 2643 | cap = ci->i_auth_cap; |
| 2597 | if (!(cap && cap->session == session)) { | 2644 | if (!(cap && cap->session == session)) { |
| @@ -2601,6 +2648,7 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc, · 3 unmodified lines | |||
| 2601 | } | 2648 | } |
| 2602 | 2649 | ||
| 2603 | first_tid = cf->tid + 1; | 2650 | first_tid = cf->tid + 1; |
| 2651 | next = list_next_entry(cf, i_list); | ||
| 2604 | 2652 | ||
| 2605 | if (!cf->is_capsnap) { | 2653 | if (!cf->is_capsnap) { |
| 2606 | struct cap_msg_args arg; | 2654 | struct cap_msg_args arg; |
| @@ -2608,7 +2656,7 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc, · 1 unmodified line | |||
| 2608 | doutc(cl, "%p %llx.%llx cap %p tid %llu %s\n", | 2656 | doutc(cl, "%p %llx.%llx cap %p tid %llu %s\n", |
| 2609 | inode, ceph_vinop(inode), cap, cf->tid, | 2657 | inode, ceph_vinop(inode), cap, cf->tid, |
| 2610 | ceph_cap_string(cf->caps)); | 2658 | ceph_cap_string(cf->caps)); |
| 2611 | __prep_cap(&arg, cap, CEPH_CAP_OP_FLUSH, | 2659 | __prep_cap(&arg, ci, cap, CEPH_CAP_OP_FLUSH, |
| 2612 | (cf->tid < last_snap_flush ? | 2660 | (cf->tid < last_snap_flush ? |
| 2613 | CEPH_CLIENT_CAPS_PENDING_CAPSNAP : 0), | 2661 | CEPH_CLIENT_CAPS_PENDING_CAPSNAP : 0), |
| 2614 | __ceph_caps_used(ci), | 2662 | __ceph_caps_used(ci), |
| @@ -2641,6 +2689,7 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc, · 26 unmodified lines | |||
| 2641 | } | 2689 | } |
| 2642 | 2690 | ||
| 2643 | spin_lock(&ci->i_ceph_lock); | 2691 | spin_lock(&ci->i_ceph_lock); |
| 2692 | cf = next; | ||
| 2644 | } | 2693 | } |
| 2645 | } | 2694 | } |
| 2646 | 2695 | ||
| @@ -3757,13 +3806,30 @@ static void handle_cap_grant(struct inode *inode, · 1110 unmodified lines | |||
| 3757 | BUG_ON(cap->issued & ~cap->implemented); | 3806 | BUG_ON(cap->issued & ~cap->implemented); |
| 3758 | 3807 | ||
| 3759 | /* don't let check_caps skip sending a response to MDS for revoke msgs */ | 3808 | /* don't let check_caps skip sending a response to MDS for revoke msgs */ |
| 3760 | if (!revoke_wait && le32_to_cpu(grant->op) == CEPH_CAP_OP_REVOKE) { | 3809 | if (le32_to_cpu(grant->op) == CEPH_CAP_OP_REVOKE) { |
| 3761 | cap->mds_wanted = 0; | 3810 | if (revoke_wait) { |
| 3762 | flags |= CHECK_CAPS_FLUSH_FORCE; | 3811 | /* |
| 3763 | if (cap == ci->i_auth_cap) | 3812 | * We can't ack the revoke yet: the response is deferred |
| 3764 | check_caps = 1; /* check auth cap only */ | 3813 | * until the writeback or cache invalidation queued above |
| 3765 | else | 3814 | * completes. Set the CEPH_I_FLUSH_FORCE flag to remember |
| 3766 | check_caps = 2; /* check all caps */ | 3815 | * that a forced cap message is owed so that deferred |
| 3816 | * completion (ceph_put_wrbuffer_cap_refs() or the | ||
| 3817 | * invalidate worker, both of which call ceph_check_caps()) | ||
| 3818 | * actually sends one, even if by then the revoked caps look | ||
| 3819 | * unused, the inode is retaining caps, or the MDS has | ||
| 3820 | * re-granted them. Without this, the cap message is never | ||
| 3821 | * sent and the MDS hangs ("isn't responding to | ||
| 3822 | * mclientcaps(revoke)"). | ||
| 3823 | */ | ||
| 3824 | set_bit(CEPH_I_FLUSH_FORCE_BIT, &ci->i_ceph_flags); | ||
| 3825 | } else { | ||
| 3826 | cap->mds_wanted = 0; | ||
| 3827 | flags |= CHECK_CAPS_FLUSH_FORCE; | ||
| 3828 | if (cap == ci->i_auth_cap) | ||
| 3829 | check_caps = 1; /* check auth cap only */ | ||
| 3830 | else | ||
| 3831 | check_caps = 2; /* check all caps */ | ||
| 3832 | } | ||
| 3767 | } | 3833 | } |
| 3768 | 3834 | ||
| 3769 | if (extra_info->inline_version > 0 && | 3835 | if (extra_info->inline_version > 0 && |
| @@ -4119,7 +4185,7 @@ retry: · 349 unmodified lines | |||
| 4119 | goto out_unlock; | 4185 | goto out_unlock; |
| 4120 | 4186 | ||
| 4121 | if (target < 0) { | 4187 | if (target < 0) { |
| 4122 | ceph_remove_cap(mdsc, cap, false); | 4188 | ceph_remove_cap(mdsc, cap, ci, false); |
| 4123 | goto out_unlock; | 4189 | goto out_unlock; |
| 4124 | } | 4190 | } |
| 4125 | 4191 | ||
| @@ -4156,7 +4222,7 @@ retry: · 30 unmodified lines | |||
| 4156 | change_auth_cap_ses(ci, tcap->session); | 4222 | change_auth_cap_ses(ci, tcap->session); |
| 4157 | } | 4223 | } |
| 4158 | } | 4224 | } |
| 4159 | ceph_remove_cap(mdsc, cap, false); | 4225 | ceph_remove_cap(mdsc, cap, ci, false); |
| 4160 | goto out_unlock; | 4226 | goto out_unlock; |
| 4161 | } else if (tsession) { | 4227 | } else if (tsession) { |
| 4162 | /* add placeholder for the export target */ | 4228 | /* add placeholder for the export target */ |
| @@ -4173,7 +4239,7 @@ retry: · 10 unmodified lines | |||
| 4173 | spin_unlock(&mdsc->cap_dirty_lock); | 4239 | spin_unlock(&mdsc->cap_dirty_lock); |
| 4174 | } | 4240 | } |
| 4175 | 4241 | ||
| 4176 | ceph_remove_cap(mdsc, cap, false); | 4242 | ceph_remove_cap(mdsc, cap, ci, false); |
| 4177 | goto out_unlock; | 4243 | goto out_unlock; |
| 4178 | } | 4244 | } |
| 4179 | 4245 | ||
| @@ -4289,7 +4355,7 @@ retry: · 109 unmodified lines | |||
| 4289 | inode, ceph_vinop(inode), peer, | 4355 | inode, ceph_vinop(inode), peer, |
| 4290 | ocap->seq, ocap->mseq, mds, piseq, pmseq); | 4356 | ocap->seq, ocap->mseq, mds, piseq, pmseq); |
| 4291 | } | 4357 | } |
| 4292 | ceph_remove_cap(mdsc, ocap, (ph->flags & CEPH_CAP_FLAG_RELEASE)); | 4358 | ceph_remove_cap(mdsc, ocap, ci, (ph->flags & CEPH_CAP_FLAG_RELEASE)); |
| 4293 | } | 4359 | } |
| 4294 | 4360 | ||
| 4295 | *old_issued = issued; | 4361 | *old_issued = issued; |
| @@ -4887,7 +4953,7 @@ int ceph_encode_inode_release(void **p, struct inode *inode, · 591 unmodified lines | |||
| 4887 | drop &= ~(used | dirty); | 4953 | drop &= ~(used | dirty); |
| 4888 | 4954 | ||
| 4889 | cap = __get_cap_for_mds(ci, mds); | 4955 | cap = __get_cap_for_mds(ci, mds); |
| 4890 | if (cap && __cap_is_valid(cap)) { | 4956 | if (cap && __cap_is_valid(ci, cap)) { |
| 4891 | unless &= cap->issued; | 4957 | unless &= cap->issued; |
| 4892 | if (unless) { | 4958 | if (unless) { |
| 4893 | if (unless & CEPH_CAP_AUTH_EXCL) | 4959 | if (unless & CEPH_CAP_AUTH_EXCL) |
| @@ -5046,7 +5112,7 @@ int ceph_purge_inode_cap(struct inode *inode, struct ceph_cap *cap, bool *invali · 152 unmodified lines | |||
| 5046 | cap, ci, inode, ceph_vinop(inode)); | 5112 | cap, ci, inode, ceph_vinop(inode)); |
| 5047 | 5113 | ||
| 5048 | is_auth = (cap == ci->i_auth_cap); | 5114 | is_auth = (cap == ci->i_auth_cap); |
| 5049 | __ceph_remove_cap(cap, false); | 5115 | __ceph_remove_cap(ci, cap, false); |
| 5050 | if (is_auth) { | 5116 | if (is_auth) { |
| 5051 | struct ceph_cap_flush *cf; | 5117 | struct ceph_cap_flush *cf; |
| 5052 | 5118 | ||
| @@ -298,18 +298,26 @@ out: · 297 unmodified lines | |||
| 298 | * Otherwise, base64 decode the string, and then ask fscrypt to format it | 298 | * Otherwise, base64 decode the string, and then ask fscrypt to format it |
| 299 | * for userland presentation. | 299 | * for userland presentation. |
| 300 | * | 300 | * |
| 301 | * Though the fscrypt/crypto subsystems broadly expect all buffers to be in the | ||
| 302 | * linear-mapped region, this function slightly relaxes those requirements: | ||
| 303 | * fname->ctext, fname->name, and oname->name may be vmalloc(), but not tname. | ||
| 304 | * | ||
| 301 | * Returns 0 on success or negative error code on error. | 305 | * Returns 0 on success or negative error code on error. |
| 302 | */ | 306 | */ |
| 303 | int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname, | 307 | int ceph_fname_to_usr(const struct ceph_fname *fname, unsigned char *tname, |
| 304 | struct fscrypt_str *oname, bool *is_nokey) | 308 | struct fscrypt_str *oname, bool *is_nokey) |
| 305 | { | 309 | { |
| 306 | struct inode *dir = fname->dir; | 310 | struct inode *dir = fname->dir; |
| 307 | struct fscrypt_str _tname = FSTR_INIT(NULL, 0); | 311 | struct fscrypt_str _tname = FSTR_INIT(NULL, 0); |
| 312 | struct fscrypt_str _oname; | ||
| 308 | struct fscrypt_str iname; | 313 | struct fscrypt_str iname; |
| 309 | char *name = fname->name; | 314 | char *name = fname->name; |
| 310 | int name_len = fname->name_len; | 315 | int name_len = fname->name_len; |
| 311 | int ret; | 316 | int ret; |
| 312 | 317 | ||
| 318 | if (WARN_ON_ONCE(tname && is_vmalloc_addr(tname))) | ||
| 319 | return -EIO; | ||
| 320 | |||
| 313 | /* Sanity check that the resulting name will fit in the buffer */ | 321 | /* Sanity check that the resulting name will fit in the buffer */ |
| 314 | if (fname->name_len > NAME_MAX || fname->ctext_len > NAME_MAX) | 322 | if (fname->name_len > NAME_MAX || fname->ctext_len > NAME_MAX) |
| 315 | return -EIO; | 323 | return -EIO; |
| @@ -350,31 +358,47 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname, · 34 unmodified lines | |||
| 350 | goto out_inode; | 358 | goto out_inode; |
| 351 | } | 359 | } |
| 352 | 360 | ||
| 361 | if (!tname && (fname->ctext_len == 0 || | ||
| 362 | unlikely(is_vmalloc_addr(fname->ctext)) || | ||
| 363 | unlikely(is_vmalloc_addr(oname->name)))) { | ||
| 364 | ret = fscrypt_fname_alloc_buffer(NAME_MAX, &_tname); | ||
| 365 | if (ret) | ||
| 366 | goto out_inode; | ||
| 367 | tname = _tname.name; | ||
| 368 | } | ||
| 369 | |||
| 353 | if (fname->ctext_len == 0) { | 370 | if (fname->ctext_len == 0) { |
| 354 | int declen; | 371 | int declen; |
| 355 | 372 | ||
| 356 | if (!tname) { | 373 | declen = base64_decode(name, name_len, tname, false, BASE64_IMAP); |
| 357 | ret = fscrypt_fname_alloc_buffer(NAME_MAX, &_tname); | ||
| 358 | if (ret) | ||
| 359 | goto out_inode; | ||
| 360 | tname = &_tname; | ||
| 361 | } | ||
| 362 | |||
| 363 | declen = base64_decode(name, name_len, | ||
| 364 | tname->name, false, BASE64_IMAP); | ||
| 365 | if (declen <= 0) { | 374 | if (declen <= 0) { |
| 366 | ret = -EIO; | 375 | ret = -EIO; |
| 367 | goto out; | 376 | goto out; |
| 368 | } | 377 | } |
| 369 | iname.name = tname->name; | 378 | iname.name = tname; |
| 370 | iname.len = declen; | 379 | iname.len = declen; |
| 380 | } else if (unlikely(is_vmalloc_addr(fname->ctext))) { | ||
| 381 | memcpy(tname, fname->ctext, fname->ctext_len); | ||
| 382 | |||
| 383 | iname.name = tname; | ||
| 384 | iname.len = fname->ctext_len; | ||
| 371 | } else { | 385 | } else { |
| 372 | iname.name = fname->ctext; | 386 | iname.name = fname->ctext; |
| 373 | iname.len = fname->ctext_len; | 387 | iname.len = fname->ctext_len; |
| 374 | } | 388 | } |
| 375 | 389 | ||
| 376 | ret = fscrypt_fname_disk_to_usr(dir, 0, 0, &iname, oname); | 390 | _oname.name = unlikely(is_vmalloc_addr(oname->name)) ? tname : oname->name; |
| 377 | if (!ret && (dir != fname->dir)) { | 391 | _oname.len = oname->len; |
| 392 | |||
| 393 | ret = fscrypt_fname_disk_to_usr(dir, 0, 0, &iname, &_oname); | ||
| 394 | if (ret) | ||
| 395 | goto out; | ||
| 396 | |||
| 397 | if (unlikely(is_vmalloc_addr(oname->name))) | ||
| 398 | memcpy(oname->name, _oname.name, _oname.len); | ||
| 399 | oname->len = _oname.len; | ||
| 400 | |||
| 401 | if (dir != fname->dir) { | ||
| 378 | char tmp_buf[BASE64_CHARS(NAME_MAX)]; | 402 | char tmp_buf[BASE64_CHARS(NAME_MAX)]; |
| 379 | 403 | ||
| 380 | name_len = snprintf(tmp_buf, sizeof(tmp_buf), "_%.*s_%llu", | 404 | name_len = snprintf(tmp_buf, sizeof(tmp_buf), "_%.*s_%llu", |
| @@ -115,7 +115,7 @@ static inline void ceph_fname_free_buffer(struct inode *parent, · 114 unmodified lines | |||
| 115 | fscrypt_fname_free_buffer(fname); | 115 | fscrypt_fname_free_buffer(fname); |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname, | 118 | int ceph_fname_to_usr(const struct ceph_fname *fname, unsigned char *tname, |
| 119 | struct fscrypt_str *oname, bool *is_nokey); | 119 | struct fscrypt_str *oname, bool *is_nokey); |
| 120 | int ceph_fscrypt_prepare_readdir(struct inode *dir); | 120 | int ceph_fscrypt_prepare_readdir(struct inode *dir); |
| 121 | 121 | ||
| @@ -204,7 +204,7 @@ static inline void ceph_fname_free_buffer(struct inode *parent, · 82 unmodified lines | |||
| 204 | } | 204 | } |
| 205 | 205 | ||
| 206 | static inline int ceph_fname_to_usr(const struct ceph_fname *fname, | 206 | static inline int ceph_fname_to_usr(const struct ceph_fname *fname, |
| 207 | struct fscrypt_str *tname, | 207 | unsigned char *tname, |
| 208 | struct fscrypt_str *oname, bool *is_nokey) | 208 | struct fscrypt_str *oname, bool *is_nokey) |
| 209 | { | 209 | { |
| 210 | oname->name = fname->name; | 210 | oname->name = fname->name; |
| @@ -774,8 +774,13 @@ struct dentry *ceph_finish_lookup(struct ceph_mds_request *req, · 773 unmodified lines | |||
| 774 | d_drop(dentry); | 774 | d_drop(dentry); |
| 775 | err = -ENOENT; | 775 | err = -ENOENT; |
| 776 | } else { | 776 | } else { |
| 777 | if (d_unhashed(dentry)) | 777 | if (d_unhashed(dentry)) { |
| 778 | d_add(dentry, NULL); | 778 | struct inode *parent = |
| 779 | d_inode(dentry->d_parent); | ||
| 780 | if (!parent || | ||
| 781 | ceph_snap(parent) == CEPH_NOSNAP) | ||
| 782 | d_add(dentry, NULL); | ||
| 783 | } | ||
| 779 | } | 784 | } |
| 780 | } | 785 | } |
| 781 | } | 786 | } |
| @@ -840,6 +845,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, · 58 unmodified lines | |||
| 840 | dentry->d_name.len) && | 845 | dentry->d_name.len) && |
| 841 | !is_root_ceph_dentry(dir, dentry) && | 846 | !is_root_ceph_dentry(dir, dentry) && |
| 842 | ceph_test_mount_opt(fsc, DCACHE) && | 847 | ceph_test_mount_opt(fsc, DCACHE) && |
| 848 | ceph_snap(dir) == CEPH_NOSNAP && | ||
| 843 | __ceph_dir_is_complete(ci) && | 849 | __ceph_dir_is_complete(ci) && |
| 844 | __ceph_caps_issued_mask_metric(ci, CEPH_CAP_FILE_SHARED, 1)) { | 850 | __ceph_caps_issued_mask_metric(ci, CEPH_CAP_FILE_SHARED, 1)) { |
| 845 | __ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_RD); | 851 | __ceph_touch_fmode(ci, mdsc, CEPH_FILE_MODE_RD); |
| @@ -1173,7 +1179,7 @@ static struct dentry *ceph_mkdir(struct mnt_idmap *idmap, struct inode *dir, · 327 unmodified lines | |||
| 1173 | !req->r_reply_info.head->is_target && | 1179 | !req->r_reply_info.head->is_target && |
| 1174 | !req->r_reply_info.head->is_dentry) | 1180 | !req->r_reply_info.head->is_dentry) |
| 1175 | err = ceph_handle_notrace_create(dir, dentry); | 1181 | err = ceph_handle_notrace_create(dir, dentry); |
| 1176 | ret = ERR_PTR(err); | 1182 | ret = err ? ERR_PTR(err) : NULL; |
| 1177 | out_req: | 1183 | out_req: |
| 1178 | if (!IS_ERR(ret) && req->r_dentry != dentry) | 1184 | if (!IS_ERR(ret) && req->r_dentry != dentry) |
| 1179 | /* Some other dentry was spliced in */ | 1185 | /* Some other dentry was spliced in */ |
| @@ -1763,11 +1769,11 @@ static int __dir_lease_check(const struct dentry *dentry, · 583 unmodified lines | |||
| 1763 | if (ret > 0) { | 1769 | if (ret > 0) { |
| 1764 | if (time_before(jiffies, di->time + lwc->dir_lease_ttl)) | 1770 | if (time_before(jiffies, di->time + lwc->dir_lease_ttl)) |
| 1765 | return STOP; | 1771 | return STOP; |
| 1772 | if (!lwc->expire_dir_lease) | ||
| 1773 | return KEEP; | ||
| 1766 | /* Move dentry to tail of dir lease list if we don't want | 1774 | /* Move dentry to tail of dir lease list if we don't want |
| 1767 | * to delete it. So dentries in the list are checked in a | 1775 | * to delete it. So dentries in the list are checked in a |
| 1768 | * round robin manner */ | 1776 | * round robin manner */ |
| 1769 | if (!lwc->expire_dir_lease) | ||
| 1770 | return TOUCH; | ||
| 1771 | if (dentry->d_lockref.count > 0 || | 1777 | if (dentry->d_lockref.count > 0 || |
| 1772 | (di->flags & CEPH_DENTRY_REFERENCED)) | 1778 | (di->flags & CEPH_DENTRY_REFERENCED)) |
| 1773 | return TOUCH; | 1779 | return TOUCH; |
| @@ -1794,7 +1800,7 @@ int ceph_trim_dentries(struct ceph_mds_client *mdsc) · 20 unmodified lines | |||
| 1794 | lwc.dir_lease = false; | 1800 | lwc.dir_lease = false; |
| 1795 | lwc.nr_to_scan = CEPH_CAPS_PER_RELEASE * 2; | 1801 | lwc.nr_to_scan = CEPH_CAPS_PER_RELEASE * 2; |
| 1796 | freed = __dentry_leases_walk(mdsc, &lwc); | 1802 | freed = __dentry_leases_walk(mdsc, &lwc); |
| 1797 | if (!lwc.nr_to_scan) /* more invalid leases */ | 1803 | if (freed > 0 && !lwc.nr_to_scan) /* more invalid leases */ |
| 1798 | return -EAGAIN; | 1804 | return -EAGAIN; |
| 1799 | 1805 | ||
| 1800 | if (lwc.nr_to_scan < CEPH_CAPS_PER_RELEASE) | 1806 | if (lwc.nr_to_scan < CEPH_CAPS_PER_RELEASE) |
| @@ -1804,6 +1810,10 @@ int ceph_trim_dentries(struct ceph_mds_client *mdsc) · 3 unmodified lines | |||
| 1804 | lwc.expire_dir_lease = freed < count; | 1810 | lwc.expire_dir_lease = freed < count; |
| 1805 | lwc.dir_lease_ttl = mdsc->fsc->mount_options->caps_wanted_delay_max * HZ; | 1811 | lwc.dir_lease_ttl = mdsc->fsc->mount_options->caps_wanted_delay_max * HZ; |
| 1806 | freed +=__dentry_leases_walk(mdsc, &lwc); | 1812 | freed +=__dentry_leases_walk(mdsc, &lwc); |
| 1813 | if (freed == 0 && count == 0) | ||
| 1814 | /* no progress possible currently, retry futile */ | ||
| 1815 | return 0; | ||
| 1816 | |||
| 1807 | if (!lwc.nr_to_scan) /* more to check */ | 1817 | if (!lwc.nr_to_scan) /* more to check */ |
| 1808 | return -EAGAIN; | 1818 | return -EAGAIN; |
| 1809 | 1819 | ||
| @@ -442,6 +442,16 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb, · 441 unmodified lines | |||
| 442 | return dentry; | 442 | return dentry; |
| 443 | } | 443 | } |
| 444 | 444 | ||
| 445 | static int ceph_export_copy_name(char *name, const char *src, u32 len) | ||
| 446 | { | ||
| 447 | if (len > NAME_MAX) | ||
| 448 | return -ENAMETOOLONG; | ||
| 449 | |||
| 450 | memcpy(name, src, len); | ||
| 451 | name[len] = '\0'; | ||
| 452 | return 0; | ||
| 453 | } | ||
| 454 | |||
| 445 | static int __get_snap_name(struct dentry *parent, char *name, | 455 | static int __get_snap_name(struct dentry *parent, char *name, |
| 446 | struct dentry *child) | 456 | struct dentry *child) |
| 447 | { | 457 | { |
| @@ -513,9 +523,8 @@ static int __get_snap_name(struct dentry *parent, char *name, · 65 unmodified lines | |||
| 513 | BUG_ON(!rde->inode.in); | 523 | BUG_ON(!rde->inode.in); |
| 514 | if (ceph_snap(inode) == | 524 | if (ceph_snap(inode) == |
| 515 | le64_to_cpu(rde->inode.in->snapid)) { | 525 | le64_to_cpu(rde->inode.in->snapid)) { |
| 516 | memcpy(name, rde->name, rde->name_len); | 526 | err = ceph_export_copy_name(name, rde->name, |
| 517 | name[rde->name_len] = '\0'; | 527 | rde->name_len); |
| 518 | err = 0; | ||
| 519 | goto out; | 528 | goto out; |
| 520 | } | 529 | } |
| 521 | } | 530 | } |
| @@ -580,8 +589,8 @@ static int ceph_get_name(struct dentry *parent, char *name, · 58 unmodified lines | |||
| 580 | 589 | ||
| 581 | rinfo = &req->r_reply_info; | 590 | rinfo = &req->r_reply_info; |
| 582 | if (!IS_ENCRYPTED(dir)) { | 591 | if (!IS_ENCRYPTED(dir)) { |
| 583 | memcpy(name, rinfo->dname, rinfo->dname_len); | 592 | err = ceph_export_copy_name(name, rinfo->dname, |
| 584 | name[rinfo->dname_len] = 0; | 593 | rinfo->dname_len); |
| 585 | } else { | 594 | } else { |
| 586 | struct fscrypt_str oname = FSTR_INIT(NULL, 0); | 595 | struct fscrypt_str oname = FSTR_INIT(NULL, 0); |
| 587 | struct ceph_fname fname = { .dir = dir, | 596 | struct ceph_fname fname = { .dir = dir, |
| @@ -595,10 +604,9 @@ static int ceph_get_name(struct dentry *parent, char *name, · 7 unmodified lines | |||
| 595 | goto out; | 604 | goto out; |
| 596 | 605 | ||
| 597 | err = ceph_fname_to_usr(&fname, NULL, &oname, NULL); | 606 | err = ceph_fname_to_usr(&fname, NULL, &oname, NULL); |
| 598 | if (!err) { | 607 | if (!err) |
| 599 | memcpy(name, oname.name, oname.len); | 608 | err = ceph_export_copy_name(name, oname.name, |
| 600 | name[oname.len] = 0; | 609 | oname.len); |
| 601 | } | ||
| 602 | ceph_fname_free_buffer(dir, &oname); | 610 | ceph_fname_free_buffer(dir, &oname); |
| 603 | } | 611 | } |
| 604 | out: | 612 | out: |
| @@ -2388,7 +2388,8 @@ out_end: · 2387 unmodified lines | |||
| 2388 | * dropping our cap refs and allowing the pending snap to logically | 2388 | * dropping our cap refs and allowing the pending snap to logically |
| 2389 | * complete _before_ this write occurs. | 2389 | * complete _before_ this write occurs. |
| 2390 | * | 2390 | * |
| 2391 | * If we are near ENOSPC, write synchronously. | 2391 | * If requested, nearfull writes are synced to preserve the legacy |
| 2392 | * client-side backpressure behavior. | ||
| 2392 | */ | 2393 | */ |
| 2393 | static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) | 2394 | static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) |
| 2394 | { | 2395 | { |
| @@ -2477,6 +2478,54 @@ retry_snap: · 82 unmodified lines | |||
| 2477 | if (err < 0) | 2478 | if (err < 0) |
| 2478 | goto out; | 2479 | goto out; |
| 2479 | 2480 | ||
| 2481 | /* | ||
| 2482 | * For O_APPEND writes we may have waited for Fwx exclusive caps | ||
| 2483 | * while the previous Fwx holder (another client) extended the | ||
| 2484 | * file. i_size has been updated via the cap grant message from | ||
| 2485 | * the MDS, but ki_pos is still the old EOF. Re-read i_size here | ||
| 2486 | * (no extra MDS round-trip needed) and adjust ki_pos to the true | ||
| 2487 | * EOF. Since we hold Fwx, no other client can change the file. | ||
| 2488 | */ | ||
| 2489 | if (iocb->ki_flags & IOCB_APPEND) { | ||
| 2490 | loff_t cur_eof = i_size_read(inode); | ||
| 2491 | |||
| 2492 | if (cur_eof != pos) { | ||
| 2493 | doutc(cl, | ||
| 2494 | "%p %llx.%llx O_APPEND: pos adjusted %lld -> %lld\n", | ||
| 2495 | inode, ceph_vinop(inode), pos, cur_eof); | ||
| 2496 | iocb->ki_pos = cur_eof; | ||
| 2497 | pos = cur_eof; | ||
| 2498 | if (pos >= limit) { | ||
| 2499 | err = -EFBIG; | ||
| 2500 | goto out_caps; | ||
| 2501 | } | ||
| 2502 | iov_iter_truncate(from, limit - pos); | ||
| 2503 | count = iov_iter_count(from); | ||
| 2504 | |||
| 2505 | /* | ||
| 2506 | * ceph_get_caps() validated the old endoff | ||
| 2507 | * against i_max_size; adjusting ki_pos forward | ||
| 2508 | * may have shifted the write range beyond the | ||
| 2509 | * granted max_size. Re-check and truncate if | ||
| 2510 | * necessary. | ||
| 2511 | */ | ||
| 2512 | spin_lock(&ci->i_ceph_lock); | ||
| 2513 | if (pos + count > (loff_t)ci->i_max_size) { | ||
| 2514 | loff_t max_size = ci->i_max_size; | ||
| 2515 | |||
| 2516 | spin_unlock(&ci->i_ceph_lock); | ||
| 2517 | if (pos >= max_size) { | ||
| 2518 | err = -EFBIG; | ||
| 2519 | goto out_caps; | ||
| 2520 | } | ||
| 2521 | iov_iter_truncate(from, max_size - pos); | ||
| 2522 | count = iov_iter_count(from); | ||
| 2523 | } else { | ||
| 2524 | spin_unlock(&ci->i_ceph_lock); | ||
| 2525 | } | ||
| 2526 | } | ||
| 2527 | } | ||
| 2528 | |||
| 2480 | err = file_update_time(file); | 2529 | err = file_update_time(file); |
| 2481 | if (err) | 2530 | if (err) |
| 2482 | goto out_caps; | 2531 | goto out_caps; |
| @@ -2556,8 +2605,9 @@ retry_snap: · 73 unmodified lines | |||
| 2556 | } | 2605 | } |
| 2557 | 2606 | ||
| 2558 | if (written >= 0) { | 2607 | if (written >= 0) { |
| 2559 | if ((map_flags & CEPH_OSDMAP_NEARFULL) || | 2608 | if (ceph_test_mount_opt(fsc, NEARFULL_SYNC) && |
| 2560 | (pool_flags & CEPH_POOL_FLAG_NEARFULL)) | 2609 | ((map_flags & CEPH_OSDMAP_NEARFULL) || |
| 2610 | (pool_flags & CEPH_POOL_FLAG_NEARFULL))) | ||
| 2561 | iocb->ki_flags |= IOCB_DSYNC; | 2611 | iocb->ki_flags |= IOCB_DSYNC; |
| 2562 | written = generic_write_sync(iocb, written); | 2612 | written = generic_write_sync(iocb, written); |
| 2563 | } | 2613 | } |
| @@ -1814,7 +1814,8 @@ retry_lookup: · 1813 unmodified lines | |||
| 1814 | ceph_dir_clear_ordered(dir); | 1814 | ceph_dir_clear_ordered(dir); |
| 1815 | d_delete(dn); | 1815 | d_delete(dn); |
| 1816 | } else if (have_lease) { | 1816 | } else if (have_lease) { |
| 1817 | if (d_unhashed(dn)) | 1817 | if (d_unhashed(dn) && |
| 1818 | ceph_snap(dir) == CEPH_NOSNAP) | ||
| 1818 | d_add(dn, NULL); | 1819 | d_add(dn, NULL); |
| 1819 | } | 1820 | } |
| 1820 | 1821 | ||
| @@ -491,11 +491,11 @@ static int parse_reply_info_readdir(void **p, void *end, · 490 unmodified lines | |||
| 491 | struct inode *inode = d_inode(req->r_dentry); | 491 | struct inode *inode = d_inode(req->r_dentry); |
| 492 | struct ceph_inode_info *ci = ceph_inode(inode); | 492 | struct ceph_inode_info *ci = ceph_inode(inode); |
| 493 | struct ceph_mds_reply_dir_entry *rde = info->dir_entries + i; | 493 | struct ceph_mds_reply_dir_entry *rde = info->dir_entries + i; |
| 494 | struct fscrypt_str tname = FSTR_INIT(NULL, 0); | ||
| 495 | struct fscrypt_str oname = FSTR_INIT(NULL, 0); | 494 | struct fscrypt_str oname = FSTR_INIT(NULL, 0); |
| 496 | struct ceph_fname fname; | 495 | struct ceph_fname fname; |
| 497 | u32 altname_len, _name_len; | 496 | u32 altname_len, _name_len; |
| 498 | u8 *altname, *_name; | 497 | u8 *altname, *_name; |
| 498 | u8 *tname = NULL; | ||
| 499 | 499 | ||
| 500 | /* dentry */ | 500 | /* dentry */ |
| 501 | ceph_decode_32_safe(p, end, _name_len, bad); | 501 | ceph_decode_32_safe(p, end, _name_len, bad); |
| @@ -541,9 +541,13 @@ static int parse_reply_info_readdir(void **p, void *end, · 39 unmodified lines | |||
| 541 | * to do the base64_decode in-place. It's | 541 | * to do the base64_decode in-place. It's |
| 542 | * safe because the decoded string should | 542 | * safe because the decoded string should |
| 543 | * always be shorter, which is 3/4 of origin | 543 | * always be shorter, which is 3/4 of origin |
| 544 | * string. | 544 | * string. If this message was allocated with |
| 545 | * vmalloc() (happens, but rarely), leave it | ||
| 546 | * NULL and let ceph_fname_to_usr() allocate | ||
| 547 | * suitable temporary working space instead. | ||
| 545 | */ | 548 | */ |
| 546 | tname.name = _name; | 549 | if (likely(!is_vmalloc_addr(_name))) |
| 550 | tname = _name; | ||
| 547 | 551 | ||
| 548 | /* | 552 | /* |
| 549 | * Set oname to _name too, and this will be | 553 | * Set oname to _name too, and this will be |
| @@ -560,7 +564,7 @@ static int parse_reply_info_readdir(void **p, void *end, · 10 unmodified lines | |||
| 560 | oname.len = altname_len; | 564 | oname.len = altname_len; |
| 561 | } | 565 | } |
| 562 | rde->is_nokey = false; | 566 | rde->is_nokey = false; |
| 563 | err = ceph_fname_to_usr(&fname, &tname, &oname, &rde->is_nokey); | 567 | err = ceph_fname_to_usr(&fname, tname, &oname, &rde->is_nokey); |
| 564 | if (err) { | 568 | if (err) { |
| 565 | pr_err_client(cl, "unable to decode %.*s, got %d\n", | 569 | pr_err_client(cl, "unable to decode %.*s, got %d\n", |
| 566 | _name_len, _name, err); | 570 | _name_len, _name, err); |
| @@ -615,10 +619,36 @@ bad: · 48 unmodified lines | |||
| 615 | 619 | ||
| 616 | #define DELEGATED_INO_AVAILABLE xa_mk_value(1) | 620 | #define DELEGATED_INO_AVAILABLE xa_mk_value(1) |
| 617 | 621 | ||
| 622 | static int ceph_insert_deleg_ino(struct ceph_mds_session *s, u64 ino) | ||
| 623 | { | ||
| 624 | struct ceph_client *cl = s->s_mdsc->fsc->client; | ||
| 625 | int err; | ||
| 626 | |||
| 627 | /* | ||
| 628 | * Cap how many delegated inodes a single session may hold. This is | ||
| 629 | * the only place that grows the count, so atomic_add_unless() bounds | ||
| 630 | * it at exactly CEPH_MAX_DELEG_INOS; s_num_deleg_inos can never exceed | ||
| 631 | * that. | ||
| 632 | */ | ||
| 633 | if (!atomic_add_unless(&s->s_num_deleg_inos, 1, CEPH_MAX_DELEG_INOS)) { | ||
| 634 | pr_warn_ratelimited_client(cl, | ||
| 635 | "MDS session already holds %d delegated inodes\n", | ||
| 636 | CEPH_MAX_DELEG_INOS); | ||
| 637 | return -EOVERFLOW; | ||
| 638 | } | ||
| 639 | |||
| 640 | err = xa_insert(&s->s_delegated_inos, ino, DELEGATED_INO_AVAILABLE, | ||
| 641 | GFP_KERNEL); | ||
| 642 | if (err) | ||
| 643 | atomic_dec(&s->s_num_deleg_inos); | ||
| 644 | return err; | ||
| 645 | } | ||
| 646 | |||
| 618 | static int ceph_parse_deleg_inos(void **p, void *end, | 647 | static int ceph_parse_deleg_inos(void **p, void *end, |
| 619 | struct ceph_mds_session *s) | 648 | struct ceph_mds_session *s) |
| 620 | { | 649 | { |
| 621 | struct ceph_client *cl = s->s_mdsc->fsc->client; | 650 | struct ceph_client *cl = s->s_mdsc->fsc->client; |
| 651 | u64 msg_deleg_inos = 0; | ||
| 622 | u32 sets; | 652 | u32 sets; |
| 623 | 653 | ||
| 624 | ceph_decode_32_safe(p, end, sets, bad); | 654 | ceph_decode_32_safe(p, end, sets, bad); |
| @@ -636,16 +666,34 @@ static int ceph_parse_deleg_inos(void **p, void *end, · 11 unmodified lines | |||
| 636 | start, len); | 666 | start, len); |
| 637 | continue; | 667 | continue; |
| 638 | } | 668 | } |
| 669 | |||
| 670 | /* | ||
| 671 | * Bound the number of inodes one reply may delegate. | ||
| 672 | * ceph_insert_deleg_ino() separately caps the per-session | ||
| 673 | * population, so this only has to stop one reply from spinning | ||
| 674 | * the insert loop under an attacker-controlled len. | ||
| 675 | */ | ||
| 676 | if (len > (u64)CEPH_MAX_DELEG_INOS || | ||
| 677 | msg_deleg_inos > (u64)CEPH_MAX_DELEG_INOS - len) { | ||
| 678 | pr_warn_ratelimited_client(cl, | ||
| 679 | "MDS reply delegates too many inodes (have %llu, +%llu, max %d)\n", | ||
| 680 | msg_deleg_inos, len, CEPH_MAX_DELEG_INOS); | ||
| 681 | return -EIO; | ||
| 682 | } | ||
| 683 | msg_deleg_inos += len; | ||
| 684 | |||
| 639 | while (len--) { | 685 | while (len--) { |
| 640 | int err = xa_insert(&s->s_delegated_inos, start++, | 686 | int err = ceph_insert_deleg_ino(s, start++); |
| 641 | DELEGATED_INO_AVAILABLE, | 687 | |
| 642 | GFP_KERNEL); | ||
| 643 | if (!err) { | 688 | if (!err) { |
| 644 | doutc(cl, "added delegated inode 0x%llx\n", start - 1); | 689 | doutc(cl, "added delegated inode 0x%llx\n", start - 1); |
| 645 | } else if (err == -EBUSY) { | 690 | } else if (err == -EBUSY) { |
| 646 | pr_warn_client(cl, | 691 | pr_warn_client(cl, |
| 647 | "MDS delegated inode 0x%llx more than once.\n", | 692 | "MDS delegated inode 0x%llx more than once.\n", |
| 648 | start - 1); | 693 | start - 1); |
| 694 | } else if (err == -EOVERFLOW) { | ||
| 695 | /* ceph_insert_deleg_ino() already warned. */ | ||
| 696 | return -EIO; | ||
| 649 | } else { | 697 | } else { |
| 650 | return err; | 698 | return err; |
| 651 | } | 699 | } |
| @@ -663,16 +711,17 @@ u64 ceph_get_deleg_ino(struct ceph_mds_session *s) · 11 unmodified lines | |||
| 663 | 711 | ||
| 664 | xa_for_each(&s->s_delegated_inos, ino, val) { | 712 | xa_for_each(&s->s_delegated_inos, ino, val) { |
| 665 | val = xa_erase(&s->s_delegated_inos, ino); | 713 | val = xa_erase(&s->s_delegated_inos, ino); |
| 666 | if (val == DELEGATED_INO_AVAILABLE) | 714 | if (val == DELEGATED_INO_AVAILABLE) { |
| 715 | atomic_dec(&s->s_num_deleg_inos); | ||
| 667 | return ino; | 716 | return ino; |
| 717 | } | ||
| 668 | } | 718 | } |
| 669 | return 0; | 719 | return 0; |
| 670 | } | 720 | } |
| 671 | 721 | ||
| 672 | int ceph_restore_deleg_ino(struct ceph_mds_session *s, u64 ino) | 722 | int ceph_restore_deleg_ino(struct ceph_mds_session *s, u64 ino) |
| 673 | { | 723 | { |
| 674 | return xa_insert(&s->s_delegated_inos, ino, DELEGATED_INO_AVAILABLE, | 724 | return ceph_insert_deleg_ino(s, ino); |
| 675 | GFP_KERNEL); | ||
| 676 | } | 725 | } |
| 677 | #else /* BITS_PER_LONG == 64 */ | 726 | #else /* BITS_PER_LONG == 64 */ |
| 678 | /* | 727 | /* |
| @@ -1059,6 +1108,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, · 380 unmodified lines | |||
| 1059 | INIT_LIST_HEAD(&s->s_waiting); | 1108 | INIT_LIST_HEAD(&s->s_waiting); |
| 1060 | INIT_LIST_HEAD(&s->s_unsafe); | 1109 | INIT_LIST_HEAD(&s->s_unsafe); |
| 1061 | xa_init(&s->s_delegated_inos); | 1110 | xa_init(&s->s_delegated_inos); |
| 1111 | atomic_set(&s->s_num_deleg_inos, 0); | ||
| 1062 | INIT_LIST_HEAD(&s->s_cap_releases); | 1112 | INIT_LIST_HEAD(&s->s_cap_releases); |
| 1063 | INIT_WORK(&s->s_cap_release_work, ceph_cap_release_work); | 1113 | INIT_WORK(&s->s_cap_release_work, ceph_cap_release_work); |
| 1064 | 1114 | ||
| @@ -1800,16 +1850,19 @@ static void __open_export_target_sessions(struct ceph_mds_client *mdsc, · 735 unmodified lines | |||
| 1800 | * session caps | 1850 | * session caps |
| 1801 | */ | 1851 | */ |
| 1802 | 1852 | ||
| 1803 | static void detach_cap_releases(struct ceph_mds_session *session, | 1853 | static int detach_cap_releases(struct ceph_mds_session *session, |
| 1804 | struct list_head *target) | 1854 | struct list_head *target) |
| 1805 | { | 1855 | { |
| 1806 | struct ceph_client *cl = session->s_mdsc->fsc->client; | 1856 | struct ceph_client *cl = session->s_mdsc->fsc->client; |
| 1857 | const int num_cap_releases = session->s_num_cap_releases; | ||
| 1807 | 1858 | ||
| 1808 | lockdep_assert_held(&session->s_cap_lock); | 1859 | lockdep_assert_held(&session->s_cap_lock); |
| 1809 | 1860 | ||
| 1810 | list_splice_init(&session->s_cap_releases, target); | 1861 | list_splice_init(&session->s_cap_releases, target); |
| 1811 | session->s_num_cap_releases = 0; | 1862 | session->s_num_cap_releases = 0; |
| 1812 | doutc(cl, "mds%d\n", session->s_mds); | 1863 | doutc(cl, "mds%d\n", session->s_mds); |
| 1864 | |||
| 1865 | return num_cap_releases; | ||
| 1813 | } | 1866 | } |
| 1814 | 1867 | ||
| 1815 | static void dispose_cap_releases(struct ceph_mds_client *mdsc, | 1868 | static void dispose_cap_releases(struct ceph_mds_client *mdsc, |
| @@ -1903,7 +1956,7 @@ int ceph_iterate_session_caps(struct ceph_mds_session *session, · 87 unmodified lines | |||
| 1903 | 1956 | ||
| 1904 | spin_lock(&session->s_cap_lock); | 1957 | spin_lock(&session->s_cap_lock); |
| 1905 | p = p->next; | 1958 | p = p->next; |
| 1906 | if (!cap->ci) { | 1959 | if (ceph_cap_is_removed(cap)) { |
| 1907 | doutc(cl, "finishing cap %p removal\n", cap); | 1960 | doutc(cl, "finishing cap %p removal\n", cap); |
| 1908 | BUG_ON(cap->session != session); | 1961 | BUG_ON(cap->session != session); |
| 1909 | cap->session = NULL; | 1962 | cap->session = NULL; |
| @@ -2259,7 +2312,7 @@ static int trim_caps_cb(struct inode *inode, int mds, void *arg) · 349 unmodified lines | |||
| 2259 | 2312 | ||
| 2260 | if (oissued) { | 2313 | if (oissued) { |
| 2261 | /* we aren't the only cap.. just remove us */ | 2314 | /* we aren't the only cap.. just remove us */ |
| 2262 | ceph_remove_cap(mdsc, cap, true); | 2315 | ceph_remove_cap(mdsc, cap, ci, true); |
| 2263 | (*remaining)--; | 2316 | (*remaining)--; |
| 2264 | } else { | 2317 | } else { |
| 2265 | struct dentry *dentry; | 2318 | struct dentry *dentry; |
| @@ -2465,9 +2518,7 @@ static void ceph_send_cap_releases(struct ceph_mds_client *mdsc, · 199 unmodified lines | |||
| 2465 | 2518 | ||
| 2466 | spin_lock(&session->s_cap_lock); | 2519 | spin_lock(&session->s_cap_lock); |
| 2467 | again: | 2520 | again: |
| 2468 | list_splice_init(&session->s_cap_releases, &tmp_list); | 2521 | num_cap_releases = detach_cap_releases(session, &tmp_list); |
| 2469 | num_cap_releases = session->s_num_cap_releases; | ||
| 2470 | session->s_num_cap_releases = 0; | ||
| 2471 | spin_unlock(&session->s_cap_lock); | 2522 | spin_unlock(&session->s_cap_lock); |
| 2472 | 2523 | ||
| 2473 | while (!list_empty(&tmp_list)) { | 2524 | while (!list_empty(&tmp_list)) { |
| @@ -4091,13 +4142,19 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) · 1617 unmodified lines | |||
| 4091 | list_add_tail(&req->r_unsafe_item, &req->r_session->s_unsafe); | 4142 | list_add_tail(&req->r_unsafe_item, &req->r_session->s_unsafe); |
| 4092 | } | 4143 | } |
| 4093 | 4144 | ||
| 4145 | /* | ||
| 4146 | * Now that all mutex-protected state has been updated above | ||
| 4147 | * (the request has been unregistered or added to the | ||
| 4148 | * session's unsafe list), we can unlock it. | ||
| 4149 | */ | ||
| 4150 | mutex_unlock(&mdsc->mutex); | ||
| 4151 | |||
| 4094 | doutc(cl, "tid %lld result %d\n", tid, result); | 4152 | doutc(cl, "tid %lld result %d\n", tid, result); |
| 4095 | if (test_bit(CEPHFS_FEATURE_REPLY_ENCODING, &session->s_features)) | 4153 | if (test_bit(CEPHFS_FEATURE_REPLY_ENCODING, &session->s_features)) |
| 4096 | err = parse_reply_info(session, msg, req, (u64)-1); | 4154 | err = parse_reply_info(session, msg, req, (u64)-1); |
| 4097 | else | 4155 | else |
| 4098 | err = parse_reply_info(session, msg, req, | 4156 | err = parse_reply_info(session, msg, req, |
| 4099 | session->s_con.peer_features); | 4157 | session->s_con.peer_features); |
| 4100 | mutex_unlock(&mdsc->mutex); | ||
| 4101 | 4158 | ||
| 4102 | /* Must find target inode outside of mutexes to avoid deadlocks */ | 4159 | /* Must find target inode outside of mutexes to avoid deadlocks */ |
| 4103 | rinfo = &req->r_reply_info; | 4160 | rinfo = &req->r_reply_info; |
| @@ -4441,7 +4498,9 @@ static void handle_session(struct ceph_mds_session *session, · 337 unmodified lines | |||
| 4441 | pr_err_client(cl, "No memory for path\n"); | 4498 | pr_err_client(cl, "No memory for path\n"); |
| 4442 | goto fail; | 4499 | goto fail; |
| 4443 | } | 4500 | } |
| 4444 | ceph_decode_copy(&p, cap_auths[i].match.path, _len); | 4501 | ceph_decode_copy_safe(&p, end, |
| 4502 | cap_auths[i].match.path, | ||
| 4503 | _len, bad); | ||
| 4445 | 4504 | ||
| 4446 | /* Remove the tailing '/' */ | 4505 | /* Remove the tailing '/' */ |
| 4447 | while (_len && cap_auths[i].match.path[_len - 1] == '/') { | 4506 | while (_len && cap_auths[i].match.path[_len - 1] == '/') { |
| @@ -4458,7 +4517,9 @@ static void handle_session(struct ceph_mds_session *session, · 10 unmodified lines | |||
| 4458 | pr_err_client(cl, "No memory for fs_name\n"); | 4517 | pr_err_client(cl, "No memory for fs_name\n"); |
| 4459 | goto fail; | 4518 | goto fail; |
| 4460 | } | 4519 | } |
| 4461 | ceph_decode_copy(&p, cap_auths[i].match.fs_name, _len); | 4520 | ceph_decode_copy_safe(&p, end, |
| 4521 | cap_auths[i].match.fs_name, | ||
| 4522 | _len, bad); | ||
| 4462 | } | 4523 | } |
| 4463 | 4524 | ||
| 4464 | ceph_decode_8_safe(&p, end, cap_auths[i].match.root_squash, bad); | 4525 | ceph_decode_8_safe(&p, end, cap_auths[i].match.root_squash, bad); |
| @@ -5106,6 +5167,7 @@ static int send_mds_reconnect(struct ceph_mds_client *mdsc, · 641 unmodified lines | |||
| 5106 | 5167 | ||
| 5107 | /* Serialized by s_mutex against concurrent ceph_get_deleg_ino(). */ | 5168 | /* Serialized by s_mutex against concurrent ceph_get_deleg_ino(). */ |
| 5108 | xa_destroy(&session->s_delegated_inos); | 5169 | xa_destroy(&session->s_delegated_inos); |
| 5170 | atomic_set(&session->s_num_deleg_inos, 0); | ||
| 5109 | if (session->s_state == CEPH_MDS_SESSION_CLOSED || | 5171 | if (session->s_state == CEPH_MDS_SESSION_CLOSED || |
| 5110 | session->s_state == CEPH_MDS_SESSION_REJECTED) { | 5172 | session->s_state == CEPH_MDS_SESSION_REJECTED) { |
| 5111 | pr_info_client(cl, "mds%d skipping reconnect, session %s\n", | 5173 | pr_info_client(cl, "mds%d skipping reconnect, session %s\n", |
| @@ -5753,7 +5815,7 @@ int ceph_mdsc_schedule_reset(struct ceph_mds_client *mdsc, · 641 unmodified lines | |||
| 5753 | strscpy(st->last_reason, msg, sizeof(st->last_reason)); | 5815 | strscpy(st->last_reason, msg, sizeof(st->last_reason)); |
| 5754 | spin_unlock(&st->lock); | 5816 | spin_unlock(&st->lock); |
| 5755 | 5817 | ||
| 5756 | if (WARN_ON_ONCE(!queue_work(system_unbound_wq, &mdsc->reset_work))) { | 5818 | if (WARN_ON_ONCE(!queue_work(system_dfl_wq, &mdsc->reset_work))) { |
| 5757 | spin_lock(&st->lock); | 5819 | spin_lock(&st->lock); |
| 5758 | st->phase = CEPH_CLIENT_RESET_IDLE; | 5820 | st->phase = CEPH_CLIENT_RESET_IDLE; |
| 5759 | st->last_errno = -EALREADY; | 5821 | st->last_errno = -EALREADY; |
| @@ -5834,9 +5896,11 @@ static void check_new_map(struct ceph_mds_client *mdsc, · 74 unmodified lines | |||
| 5834 | ceph_mdsmap_get_addr(newmap, i), | 5896 | ceph_mdsmap_get_addr(newmap, i), |
| 5835 | sizeof(struct ceph_entity_addr))) { | 5897 | sizeof(struct ceph_entity_addr))) { |
| 5836 | /* just close it */ | 5898 | /* just close it */ |
| 5899 | ceph_get_mds_session(s); | ||
| 5837 | mutex_unlock(&mdsc->mutex); | 5900 | mutex_unlock(&mdsc->mutex); |
| 5838 | mutex_lock(&s->s_mutex); | 5901 | mutex_lock(&s->s_mutex); |
| 5839 | mutex_lock(&mdsc->mutex); | 5902 | mutex_lock(&mdsc->mutex); |
| 5903 | ceph_put_mds_session(s); | ||
| 5840 | ceph_con_close(&s->s_con); | 5904 | ceph_con_close(&s->s_con); |
| 5841 | mutex_unlock(&s->s_mutex); | 5905 | mutex_unlock(&s->s_mutex); |
| 5842 | s->s_state = CEPH_MDS_SESSION_RESTARTING; | 5906 | s->s_state = CEPH_MDS_SESSION_RESTARTING; |
| @@ -5851,6 +5915,7 @@ static void check_new_map(struct ceph_mds_client *mdsc, · 8 unmodified lines | |||
| 5851 | newstate >= CEPH_MDS_STATE_RECONNECT) { | 5915 | newstate >= CEPH_MDS_STATE_RECONNECT) { |
| 5852 | int rc; | 5916 | int rc; |
| 5853 | 5917 | ||
| 5918 | ceph_get_mds_session(s); | ||
| 5854 | mutex_unlock(&mdsc->mutex); | 5919 | mutex_unlock(&mdsc->mutex); |
| 5855 | clear_bit(i, targets); | 5920 | clear_bit(i, targets); |
| 5856 | rc = send_mds_reconnect(mdsc, s); | 5921 | rc = send_mds_reconnect(mdsc, s); |
| @@ -5859,6 +5924,7 @@ static void check_new_map(struct ceph_mds_client *mdsc, · 2 unmodified lines | |||
| 5859 | "mds%d reconnect failed: %d\n", | 5924 | "mds%d reconnect failed: %d\n", |
| 5860 | i, rc); | 5925 | i, rc); |
| 5861 | mutex_lock(&mdsc->mutex); | 5926 | mutex_lock(&mdsc->mutex); |
| 5927 | ceph_put_mds_session(s); | ||
| 5862 | } | 5928 | } |
| 5863 | 5929 | ||
| 5864 | /* | 5930 | /* |
| @@ -5871,9 +5937,11 @@ static void check_new_map(struct ceph_mds_client *mdsc, · 6 unmodified lines | |||
| 5871 | pr_info_client(cl, "mds%d recovery completed\n", | 5937 | pr_info_client(cl, "mds%d recovery completed\n", |
| 5872 | s->s_mds); | 5938 | s->s_mds); |
| 5873 | kick_requests(mdsc, i); | 5939 | kick_requests(mdsc, i); |
| 5940 | ceph_get_mds_session(s); | ||
| 5874 | mutex_unlock(&mdsc->mutex); | 5941 | mutex_unlock(&mdsc->mutex); |
| 5875 | mutex_lock(&s->s_mutex); | 5942 | mutex_lock(&s->s_mutex); |
| 5876 | mutex_lock(&mdsc->mutex); | 5943 | mutex_lock(&mdsc->mutex); |
| 5944 | ceph_put_mds_session(s); | ||
| 5877 | ceph_kick_flushing_caps(mdsc, s); | 5945 | ceph_kick_flushing_caps(mdsc, s); |
| 5878 | mutex_unlock(&s->s_mutex); | 5946 | mutex_unlock(&s->s_mutex); |
| 5879 | wake_up_session_caps(s, RECONNECT); | 5947 | wake_up_session_caps(s, RECONNECT); |
| @@ -300,6 +300,7 @@ struct ceph_mds_session { · 299 unmodified lines | |||
| 300 | struct list_head s_waiting; /* waiting requests */ | 300 | struct list_head s_waiting; /* waiting requests */ |
| 301 | struct list_head s_unsafe; /* unsafe requests */ | 301 | struct list_head s_unsafe; /* unsafe requests */ |
| 302 | struct xarray s_delegated_inos; | 302 | struct xarray s_delegated_inos; |
| 303 | atomic_t s_num_deleg_inos; | ||
| 303 | }; | 304 | }; |
| 304 | 305 | ||
| 305 | /* | 306 | /* |
| @@ -3,6 +3,7 @@ · 2 unmodified lines | |||
| 3 | 3 | ||
| 4 | #include <linux/bug.h> | 4 | #include <linux/bug.h> |
| 5 | #include <linux/err.h> | 5 | #include <linux/err.h> |
| 6 | #include <linux/overflow.h> | ||
| 6 | #include <linux/random.h> | 7 | #include <linux/random.h> |
| 7 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
| 8 | #include <linux/types.h> | 9 | #include <linux/types.h> |
| @@ -126,6 +127,7 @@ struct ceph_mdsmap *ceph_mdsmap_decode(struct ceph_mds_client *mdsc, void **p, · 117 unmodified lines | |||
| 126 | u8 mdsmap_v; | 127 | u8 mdsmap_v; |
| 127 | u16 mdsmap_ev; | 128 | u16 mdsmap_ev; |
| 128 | u32 target; | 129 | u32 target; |
| 130 | size_t export_targets_len; | ||
| 129 | 131 | ||
| 130 | m = kzalloc_obj(*m, GFP_NOFS); | 132 | m = kzalloc_obj(*m, GFP_NOFS); |
| 131 | if (!m) | 133 | if (!m) |
| @@ -224,8 +226,11 @@ struct ceph_mdsmap *ceph_mdsmap_decode(struct ceph_mds_client *mdsc, void **p, · 92 unmodified lines | |||
| 224 | *p += namelen; | 226 | *p += namelen; |
| 225 | if (info_v >= 2) { | 227 | if (info_v >= 2) { |
| 226 | ceph_decode_32_safe(p, end, num_export_targets, bad); | 228 | ceph_decode_32_safe(p, end, num_export_targets, bad); |
| 229 | export_targets_len = size_mul(num_export_targets, | ||
| 230 | sizeof(u32)); | ||
| 231 | ceph_decode_need(p, end, export_targets_len, bad); | ||
| 227 | pexport_targets = *p; | 232 | pexport_targets = *p; |
| 228 | *p += num_export_targets * sizeof(u32); | 233 | *p += export_targets_len; |
| 229 | } else { | 234 | } else { |
| 230 | num_export_targets = 0; | 235 | num_export_targets = 0; |
| 231 | } | 236 | } |
| @@ -264,6 +269,10 @@ struct ceph_mdsmap *ceph_mdsmap_decode(struct ceph_mds_client *mdsc, void **p, · 32 unmodified lines | |||
| 264 | goto nomem; | 269 | goto nomem; |
| 265 | for (j = 0; j < num_export_targets; j++) { | 270 | for (j = 0; j < num_export_targets; j++) { |
| 266 | target = ceph_decode_32(&pexport_targets); | 271 | target = ceph_decode_32(&pexport_targets); |
| 272 | if (target >= CEPH_MAX_MDS) { | ||
| 273 | err = -EIO; | ||
| 274 | goto corrupt; | ||
| 275 | } | ||
| 267 | info->export_targets[j] = target; | 276 | info->export_targets[j] = target; |
| 268 | } | 277 | } |
| 269 | } else { | 278 | } else { |
| @@ -177,6 +177,7 @@ enum { · 176 unmodified lines | |||
| 177 | Opt_wsync, | 177 | Opt_wsync, |
| 178 | Opt_pagecache, | 178 | Opt_pagecache, |
| 179 | Opt_sparseread, | 179 | Opt_sparseread, |
| 180 | Opt_nearfull_sync, | ||
| 180 | }; | 181 | }; |
| 181 | 182 | ||
| 182 | enum ceph_recover_session_mode { | 183 | enum ceph_recover_session_mode { |
| @@ -205,6 +206,7 @@ static const struct fs_parameter_spec ceph_mount_parameters[] = { · 22 unmodified lines | |||
| 205 | fsparam_flag_no ("ino32", Opt_ino32), | 206 | fsparam_flag_no ("ino32", Opt_ino32), |
| 206 | fsparam_string ("mds_namespace", Opt_mds_namespace), | 207 | fsparam_string ("mds_namespace", Opt_mds_namespace), |
| 207 | fsparam_string ("mon_addr", Opt_mon_addr), | 208 | fsparam_string ("mon_addr", Opt_mon_addr), |
| 209 | fsparam_flag_no ("nearfull_sync", Opt_nearfull_sync), | ||
| 208 | fsparam_flag_no ("poolperm", Opt_poolperm), | 210 | fsparam_flag_no ("poolperm", Opt_poolperm), |
| 209 | fsparam_flag_no ("quotadf", Opt_quotadf), | 211 | fsparam_flag_no ("quotadf", Opt_quotadf), |
| 210 | fsparam_u32 ("rasize", Opt_rasize), | 212 | fsparam_u32 ("rasize", Opt_rasize), |
| @@ -593,6 +595,12 @@ static int ceph_parse_mount_param(struct fs_context *fc, · 382 unmodified lines | |||
| 593 | else | 595 | else |
| 594 | fsopt->flags |= CEPH_MOUNT_OPT_SPARSEREAD; | 596 | fsopt->flags |= CEPH_MOUNT_OPT_SPARSEREAD; |
| 595 | break; | 597 | break; |
| 598 | case Opt_nearfull_sync: | ||
| 599 | if (result.negated) | ||
| 600 | fsopt->flags &= ~CEPH_MOUNT_OPT_NEARFULL_SYNC; | ||
| 601 | else | ||
| 602 | fsopt->flags |= CEPH_MOUNT_OPT_NEARFULL_SYNC; | ||
| 603 | break; | ||
| 596 | case Opt_test_dummy_encryption: | 604 | case Opt_test_dummy_encryption: |
| 597 | #ifdef CONFIG_FS_ENCRYPTION | 605 | #ifdef CONFIG_FS_ENCRYPTION |
| 598 | fscrypt_free_dummy_policy(&fsopt->dummy_enc_policy); | 606 | fscrypt_free_dummy_policy(&fsopt->dummy_enc_policy); |
| @@ -749,6 +757,8 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) · 150 unmodified lines | |||
| 749 | seq_puts(m, ",nopagecache"); | 757 | seq_puts(m, ",nopagecache"); |
| 750 | if (fsopt->flags & CEPH_MOUNT_OPT_SPARSEREAD) | 758 | if (fsopt->flags & CEPH_MOUNT_OPT_SPARSEREAD) |
| 751 | seq_puts(m, ",sparseread"); | 759 | seq_puts(m, ",sparseread"); |
| 760 | if (fsopt->flags & CEPH_MOUNT_OPT_NEARFULL_SYNC) | ||
| 761 | seq_puts(m, ",nearfull_sync"); | ||
| 752 | 762 | ||
| 753 | fscrypt_show_test_dummy_encryption(m, ',', root->d_sb); | 763 | fscrypt_show_test_dummy_encryption(m, ',', root->d_sb); |
| 754 | 764 | ||
| @@ -45,6 +45,7 @@ · 44 unmodified lines | |||
| 45 | #define CEPH_MOUNT_OPT_ASYNC_DIROPS (1<<15) /* allow async directory ops */ | 45 | #define CEPH_MOUNT_OPT_ASYNC_DIROPS (1<<15) /* allow async directory ops */ |
| 46 | #define CEPH_MOUNT_OPT_NOPAGECACHE (1<<16) /* bypass pagecache altogether */ | 46 | #define CEPH_MOUNT_OPT_NOPAGECACHE (1<<16) /* bypass pagecache altogether */ |
| 47 | #define CEPH_MOUNT_OPT_SPARSEREAD (1<<17) /* always do sparse reads */ | 47 | #define CEPH_MOUNT_OPT_SPARSEREAD (1<<17) /* always do sparse reads */ |
| 48 | #define CEPH_MOUNT_OPT_NEARFULL_SYNC (1<<18) /* sync writes when nearfull */ | ||
| 48 | 49 | ||
| 49 | #define CEPH_MOUNT_OPT_DEFAULT \ | 50 | #define CEPH_MOUNT_OPT_DEFAULT \ |
| 50 | (CEPH_MOUNT_OPT_DCACHE | \ | 51 | (CEPH_MOUNT_OPT_DCACHE | \ |
| @@ -203,7 +204,19 @@ struct ceph_fs_client { · 152 unmodified lines | |||
| 203 | */ | 204 | */ |
| 204 | struct ceph_cap { | 205 | struct ceph_cap { |
| 205 | struct ceph_inode_info *ci; | 206 | struct ceph_inode_info *ci; |
| 206 | struct rb_node ci_node; /* per-ci cap tree */ | 207 | |
| 208 | /** | ||
| 209 | * Per-ci cap tree. Protected with | ||
| 210 | * `ceph_inode_info.i_ceph_lock`. | ||
| 211 | * | ||
| 212 | * Clearing this field with RB_CLEAR_NODE() requires holding | ||
| 213 | * both `ceph_inode_info.i_ceph_lock` and | ||
| 214 | * `ceph_mds_session->s_cap_lock`. Calling RB_EMPTY_NODE() | ||
| 215 | * (via ceph_cap_is_removed()) requires holding at least one | ||
| 216 | * of these. | ||
| 217 | */ | ||
| 218 | struct rb_node ci_node; | ||
| 219 | |||
| 207 | struct ceph_mds_session *session; | 220 | struct ceph_mds_session *session; |
| 208 | struct list_head session_caps; /* per-session caplist */ | 221 | struct list_head session_caps; /* per-session caplist */ |
| 209 | u64 cap_id; /* unique cap id (mds provided) */ | 222 | u64 cap_id; /* unique cap id (mds provided) */ |
| @@ -641,6 +654,15 @@ static inline int ceph_ino_compare(struct inode *inode, void *data) · 431 unmodified lines | |||
| 641 | #define CEPH_MDS_INO_LOG_OFFSET (2 * CEPH_MAX_MDS) | 654 | #define CEPH_MDS_INO_LOG_OFFSET (2 * CEPH_MAX_MDS) |
| 642 | #define CEPH_INO_SYSTEM_BASE ((6*CEPH_MAX_MDS) + (CEPH_MAX_MDS * CEPH_NUM_STRAY)) | 655 | #define CEPH_INO_SYSTEM_BASE ((6*CEPH_MAX_MDS) + (CEPH_MAX_MDS * CEPH_NUM_STRAY)) |
| 643 | 656 | ||
| 657 | /* | ||
| 658 | * Upper bound on the number of delegated inodes a single MDS session may | ||
| 659 | * hold. The MDS normally hands out a small preallocation window (the | ||
| 660 | * userspace mds_client_prealloc_inos option defaults to 1000) and refills | ||
| 661 | * it as the client consumes entries. This leaves generous headroom while | ||
| 662 | * bounding the CPU and memory a malformed delegation interval can consume. | ||
| 663 | */ | ||
| 664 | #define CEPH_MAX_DELEG_INOS 8192 | ||
| 665 | |||
| 644 | static inline bool ceph_vino_is_reserved(const struct ceph_vino vino) | 666 | static inline bool ceph_vino_is_reserved(const struct ceph_vino vino) |
| 645 | { | 667 | { |
| 646 | if (vino.ino >= CEPH_INO_SYSTEM_BASE || | 668 | if (vino.ino >= CEPH_INO_SYSTEM_BASE || |
| @@ -687,6 +709,10 @@ static inline struct inode *ceph_find_inode(struct super_block *sb, · 40 unmodified lines | |||
| 687 | #define CEPH_I_ASYNC_CREATE_BIT (12) /* async create in flight for this */ | 709 | #define CEPH_I_ASYNC_CREATE_BIT (12) /* async create in flight for this */ |
| 688 | #define CEPH_I_SHUTDOWN_BIT (13) /* inode is no longer usable */ | 710 | #define CEPH_I_SHUTDOWN_BIT (13) /* inode is no longer usable */ |
| 689 | #define CEPH_I_ASYNC_CHECK_CAPS_BIT (14) /* check caps after async creating finishes */ | 711 | #define CEPH_I_ASYNC_CHECK_CAPS_BIT (14) /* check caps after async creating finishes */ |
| 712 | #define CEPH_I_FLUSH_FORCE_BIT (15) /* a revoke's response was deferred; | ||
| 713 | * force a cap message to the MDS once | ||
| 714 | * the deferred work completes | ||
| 715 | */ | ||
| 690 | 716 | ||
| 691 | #define CEPH_I_DIR_ORDERED (1 << CEPH_I_DIR_ORDERED_BIT) | 717 | #define CEPH_I_DIR_ORDERED (1 << CEPH_I_DIR_ORDERED_BIT) |
| 692 | #define CEPH_I_FLUSH (1 << CEPH_I_FLUSH_BIT) | 718 | #define CEPH_I_FLUSH (1 << CEPH_I_FLUSH_BIT) |
| @@ -699,6 +725,7 @@ static inline struct inode *ceph_find_inode(struct super_block *sb, · 6 unmodified lines | |||
| 699 | #define CEPH_I_ODIRECT (1 << CEPH_I_ODIRECT_BIT) | 725 | #define CEPH_I_ODIRECT (1 << CEPH_I_ODIRECT_BIT) |
| 700 | #define CEPH_I_ASYNC_CREATE (1 << CEPH_I_ASYNC_CREATE_BIT) | 726 | #define CEPH_I_ASYNC_CREATE (1 << CEPH_I_ASYNC_CREATE_BIT) |
| 701 | #define CEPH_I_SHUTDOWN (1 << CEPH_I_SHUTDOWN_BIT) | 727 | #define CEPH_I_SHUTDOWN (1 << CEPH_I_SHUTDOWN_BIT) |
| 728 | #define CEPH_I_FLUSH_FORCE (1 << CEPH_I_FLUSH_FORCE_BIT) | ||
| 702 | 729 | ||
| 703 | /* | 730 | /* |
| 704 | * Masks of ceph inode work. | 731 | * Masks of ceph inode work. |
| @@ -1269,8 +1296,22 @@ extern void ceph_add_cap(struct inode *inode, · 564 unmodified lines | |||
| 1269 | unsigned issued, unsigned wanted, | 1296 | unsigned issued, unsigned wanted, |
| 1270 | unsigned cap, unsigned seq, u64 realmino, int flags, | 1297 | unsigned cap, unsigned seq, u64 realmino, int flags, |
| 1271 | struct ceph_cap **new_cap); | 1298 | struct ceph_cap **new_cap); |
| 1272 | extern void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release); | 1299 | |
| 1300 | /** | ||
| 1301 | * Determine whether __ceph_remove_cap() has been called on this #cap | ||
| 1302 | * (but the object has not yet been freed because it is protected by | ||
| 1303 | * `ceph_mds_session.s_cap_iterator`). | ||
| 1304 | * | ||
| 1305 | * Caller must lock either `ceph_inode_info.i_ceph_lock` or | ||
| 1306 | * `ceph_mds_session.s_cap_lock`. | ||
| 1307 | */ | ||
| 1308 | static inline bool ceph_cap_is_removed(const struct ceph_cap *cap) | ||
| 1309 | { | ||
| 1310 | return RB_EMPTY_NODE(&cap->ci_node); | ||
| 1311 | } | ||
| 1312 | |||
| 1273 | extern void ceph_remove_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, | 1313 | extern void ceph_remove_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, |
| 1314 | struct ceph_inode_info *ci, | ||
| 1274 | bool queue_release); | 1315 | bool queue_release); |
| 1275 | extern void __ceph_remove_caps(struct ceph_inode_info *ci); | 1316 | extern void __ceph_remove_caps(struct ceph_inode_info *ci); |
| 1276 | extern void ceph_put_cap(struct ceph_mds_client *mdsc, | 1317 | extern void ceph_put_cap(struct ceph_mds_client *mdsc, |
| @@ -848,6 +848,7 @@ start: · 847 unmodified lines | |||
| 848 | name = p; | 848 | name = p; |
| 849 | p += len; | 849 | p += len; |
| 850 | ceph_decode_32_safe(&p, end, len, bad); | 850 | ceph_decode_32_safe(&p, end, len, bad); |
| 851 | ceph_decode_need(&p, end, len, bad); | ||
| 851 | val = p; | 852 | val = p; |
| 852 | p += len; | 853 | p += len; |
| 853 | 854 | ||
| @@ -313,8 +313,6 @@ int ceph_wait_for_latest_osdmap(struct ceph_client *client, · 312 unmodified lines | |||
| 313 | 313 | ||
| 314 | /* pagevec.c */ | 314 | /* pagevec.c */ |
| 315 | extern void ceph_release_page_vector(struct page **pages, int num_pages); | 315 | extern void ceph_release_page_vector(struct page **pages, int num_pages); |
| 316 | extern void ceph_put_page_vector(struct page **pages, int num_pages, | ||
| 317 | bool dirty); | ||
| 318 | extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags); | 316 | extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags); |
| 319 | extern void ceph_copy_from_page_vector(struct page **pages, | 317 | extern void ceph_copy_from_page_vector(struct page **pages, |
| 320 | void *data, | 318 | void *data, |
| @@ -2142,6 +2142,11 @@ static int process_banner_prefix(struct ceph_connection *con) · 2141 unmodified lines | |||
| 2142 | payload_len = ceph_decode_16(&p); | 2142 | payload_len = ceph_decode_16(&p); |
| 2143 | dout("%s con %p payload_len %d\n", __func__, con, payload_len); | 2143 | dout("%s con %p payload_len %d\n", __func__, con, payload_len); |
| 2144 | 2144 | ||
| 2145 | if (payload_len < sizeof(u64) + sizeof(u64)) { | ||
| 2146 | con->error_msg = "protocol error, bad banner payload len"; | ||
| 2147 | return -EINVAL; | ||
| 2148 | } | ||
| 2149 | |||
| 2145 | return prepare_read_banner_payload(con, payload_len); | 2150 | return prepare_read_banner_payload(con, payload_len); |
| 2146 | } | 2151 | } |
| 2147 | 2152 | ||
| @@ -6,6 +6,7 @@ · 5 unmodified lines | |||
| 6 | #include <linux/err.h> | 6 | #include <linux/err.h> |
| 7 | #include <linux/highmem.h> | 7 | #include <linux/highmem.h> |
| 8 | #include <linux/mm.h> | 8 | #include <linux/mm.h> |
| 9 | #include <linux/overflow.h> | ||
| 9 | #include <linux/pagemap.h> | 10 | #include <linux/pagemap.h> |
| 10 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
| 11 | #include <linux/uaccess.h> | 12 | #include <linux/uaccess.h> |
| @@ -5802,6 +5803,31 @@ static inline void convert_extent_map(struct ceph_sparse_read *sr) · 5790 unmodified lines | |||
| 5802 | } | 5803 | } |
| 5803 | #endif | 5804 | #endif |
| 5804 | 5805 | ||
| 5806 | static bool sparse_extent_map_valid(struct ceph_sparse_read *sr) | ||
| 5807 | { | ||
| 5808 | u64 req_end, pos; | ||
| 5809 | int i; | ||
| 5810 | |||
| 5811 | if (check_add_overflow(sr->sr_req_off, sr->sr_req_len, &req_end)) | ||
| 5812 | return false; | ||
| 5813 | |||
| 5814 | pos = sr->sr_req_off; | ||
| 5815 | for (i = 0; i < sr->sr_count; i++) { | ||
| 5816 | struct ceph_sparse_extent *ext = &sr->sr_extent[i]; | ||
| 5817 | u64 end; | ||
| 5818 | |||
| 5819 | if (ext->off < pos) | ||
| 5820 | return false; | ||
| 5821 | if (check_add_overflow(ext->off, ext->len, &end)) | ||
| 5822 | return false; | ||
| 5823 | if (end > req_end) | ||
| 5824 | return false; | ||
| 5825 | pos = end; | ||
| 5826 | } | ||
| 5827 | |||
| 5828 | return true; | ||
| 5829 | } | ||
| 5830 | |||
| 5805 | static int osd_sparse_read(struct ceph_connection *con, | 5831 | static int osd_sparse_read(struct ceph_connection *con, |
| 5806 | struct ceph_msg_data_cursor *cursor, | 5832 | struct ceph_msg_data_cursor *cursor, |
| 5807 | char **pbuf) | 5833 | char **pbuf) |
| @@ -5852,6 +5878,10 @@ next_op: · 44 unmodified lines | |||
| 5852 | fallthrough; | 5878 | fallthrough; |
| 5853 | case CEPH_SPARSE_READ_DATA_LEN: | 5879 | case CEPH_SPARSE_READ_DATA_LEN: |
| 5854 | convert_extent_map(sr); | 5880 | convert_extent_map(sr); |
| 5881 | if (!sparse_extent_map_valid(sr)) { | ||
| 5882 | pr_warn_ratelimited("invalid sparse extent map\n"); | ||
| 5883 | return -EREMOTEIO; | ||
| 5884 | } | ||
| 5855 | ret = sizeof(sr->sr_datalen); | 5885 | ret = sizeof(sr->sr_datalen); |
| 5856 | *pbuf = (char *)&sr->sr_datalen; | 5886 | *pbuf = (char *)&sr->sr_datalen; |
| 5857 | sr->sr_state = CEPH_SPARSE_READ_DATA_PRE; | 5887 | sr->sr_state = CEPH_SPARSE_READ_DATA_PRE; |
| @@ -517,6 +517,8 @@ static struct crush_map *crush_decode(void *pbyval, void *end) · 516 unmodified lines | |||
| 517 | 517 | ||
| 518 | ceph_decode_need(p, end, 4*sizeof(u32), bad); | 518 | ceph_decode_need(p, end, 4*sizeof(u32), bad); |
| 519 | b->id = ceph_decode_32(p); | 519 | b->id = ceph_decode_32(p); |
| 520 | if (b->id != -1 - i) | ||
| 521 | goto bad; | ||
| 520 | b->type = ceph_decode_16(p); | 522 | b->type = ceph_decode_16(p); |
| 521 | if (b->type == 0) | 523 | if (b->type == 0) |
| 522 | goto bad; | 524 | goto bad; |
| @@ -10,19 +10,6 @@ · 9 unmodified lines | |||
| 10 | 10 | ||
| 11 | #include <linux/ceph/libceph.h> | 11 | #include <linux/ceph/libceph.h> |
| 12 | 12 | ||
| 13 | void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty) | ||
| 14 | { | ||
| 15 | int i; | ||
| 16 | |||
| 17 | for (i = 0; i < num_pages; i++) { | ||
| 18 | if (dirty) | ||
| 19 | set_page_dirty_lock(pages[i]); | ||
| 20 | put_page(pages[i]); | ||
| 21 | } | ||
| 22 | kvfree(pages); | ||
| 23 | } | ||
| 24 | EXPORT_SYMBOL(ceph_put_page_vector); | ||
| 25 | |||
| 26 | void ceph_release_page_vector(struct page **pages, int num_pages) | 13 | void ceph_release_page_vector(struct page **pages, int num_pages) |
| 27 | { | 14 | { |
| 28 | int i; | 15 | int i; |