diff options
author | Yan, Zheng <zyan@redhat.com> | 2019-01-08 21:10:17 -0500 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2019-03-05 12:55:16 -0500 |
commit | b37fe1f923fb4b17dc7d63406ec8dc67f13c2799 (patch) | |
tree | 3628f4834ca063b260c4627a834fcf6df2cd5340 /fs/ceph | |
parent | 75c9627efb7288e1725e9903ea275cc6b5992f17 (diff) |
ceph: support versioned reply
In versioned reply, inodestat, dirstat and lease are encoded with
version, compat_version and struct_len.
Based on a patch from Jos Collin <jcollin@redhat.com>.
Link: http://tracker.ceph.com/issues/26936
Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs/ceph')
-rw-r--r-- | fs/ceph/mds_client.c | 214 | ||||
-rw-r--r-- | fs/ceph/mds_client.h | 1 |
2 files changed, 166 insertions, 49 deletions
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index f2f57775d2d5..e87544e42488 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -65,6 +65,29 @@ static const struct ceph_connection_operations mds_con_ops; | |||
65 | * mds reply parsing | 65 | * mds reply parsing |
66 | */ | 66 | */ |
67 | 67 | ||
68 | static int parse_reply_info_quota(void **p, void *end, | ||
69 | struct ceph_mds_reply_info_in *info) | ||
70 | { | ||
71 | u8 struct_v, struct_compat; | ||
72 | u32 struct_len; | ||
73 | |||
74 | ceph_decode_8_safe(p, end, struct_v, bad); | ||
75 | ceph_decode_8_safe(p, end, struct_compat, bad); | ||
76 | /* struct_v is expected to be >= 1. we only | ||
77 | * understand encoding with struct_compat == 1. */ | ||
78 | if (!struct_v || struct_compat != 1) | ||
79 | goto bad; | ||
80 | ceph_decode_32_safe(p, end, struct_len, bad); | ||
81 | ceph_decode_need(p, end, struct_len, bad); | ||
82 | end = *p + struct_len; | ||
83 | ceph_decode_64_safe(p, end, info->max_bytes, bad); | ||
84 | ceph_decode_64_safe(p, end, info->max_files, bad); | ||
85 | *p = end; | ||
86 | return 0; | ||
87 | bad: | ||
88 | return -EIO; | ||
89 | } | ||
90 | |||
68 | /* | 91 | /* |
69 | * parse individual inode info | 92 | * parse individual inode info |
70 | */ | 93 | */ |
@@ -72,8 +95,24 @@ static int parse_reply_info_in(void **p, void *end, | |||
72 | struct ceph_mds_reply_info_in *info, | 95 | struct ceph_mds_reply_info_in *info, |
73 | u64 features) | 96 | u64 features) |
74 | { | 97 | { |
75 | int err = -EIO; | 98 | int err = 0; |
99 | u8 struct_v = 0; | ||
76 | 100 | ||
101 | if (features == (u64)-1) { | ||
102 | u32 struct_len; | ||
103 | u8 struct_compat; | ||
104 | ceph_decode_8_safe(p, end, struct_v, bad); | ||
105 | ceph_decode_8_safe(p, end, struct_compat, bad); | ||
106 | /* struct_v is expected to be >= 1. we only understand | ||
107 | * encoding with struct_compat == 1. */ | ||
108 | if (!struct_v || struct_compat != 1) | ||
109 | goto bad; | ||
110 | ceph_decode_32_safe(p, end, struct_len, bad); | ||
111 | ceph_decode_need(p, end, struct_len, bad); | ||
112 | end = *p + struct_len; | ||
113 | } | ||
114 | |||
115 | ceph_decode_need(p, end, sizeof(struct ceph_mds_reply_inode), bad); | ||
77 | info->in = *p; | 116 | info->in = *p; |
78 | *p += sizeof(struct ceph_mds_reply_inode) + | 117 | *p += sizeof(struct ceph_mds_reply_inode) + |
79 | sizeof(*info->in->fragtree.splits) * | 118 | sizeof(*info->in->fragtree.splits) * |
@@ -91,49 +130,127 @@ static int parse_reply_info_in(void **p, void *end, | |||
91 | info->xattr_data = *p; | 130 | info->xattr_data = *p; |
92 | *p += info->xattr_len; | 131 | *p += info->xattr_len; |
93 | 132 | ||
94 | if (features & CEPH_FEATURE_MDS_INLINE_DATA) { | 133 | if (features == (u64)-1) { |
134 | /* inline data */ | ||
95 | ceph_decode_64_safe(p, end, info->inline_version, bad); | 135 | ceph_decode_64_safe(p, end, info->inline_version, bad); |
96 | ceph_decode_32_safe(p, end, info->inline_len, bad); | 136 | ceph_decode_32_safe(p, end, info->inline_len, bad); |
97 | ceph_decode_need(p, end, info->inline_len, bad); | 137 | ceph_decode_need(p, end, info->inline_len, bad); |
98 | info->inline_data = *p; | 138 | info->inline_data = *p; |
99 | *p += info->inline_len; | 139 | *p += info->inline_len; |
100 | } else | 140 | /* quota */ |
101 | info->inline_version = CEPH_INLINE_NONE; | 141 | err = parse_reply_info_quota(p, end, info); |
142 | if (err < 0) | ||
143 | goto out_bad; | ||
144 | /* pool namespace */ | ||
145 | ceph_decode_32_safe(p, end, info->pool_ns_len, bad); | ||
146 | if (info->pool_ns_len > 0) { | ||
147 | ceph_decode_need(p, end, info->pool_ns_len, bad); | ||
148 | info->pool_ns_data = *p; | ||
149 | *p += info->pool_ns_len; | ||
150 | } | ||
151 | /* btime, change_attr */ | ||
152 | { | ||
153 | struct ceph_timespec btime; | ||
154 | u64 change_attr; | ||
155 | ceph_decode_need(p, end, sizeof(btime), bad); | ||
156 | ceph_decode_copy(p, &btime, sizeof(btime)); | ||
157 | ceph_decode_64_safe(p, end, change_attr, bad); | ||
158 | } | ||
102 | 159 | ||
103 | if (features & CEPH_FEATURE_MDS_QUOTA) { | 160 | *p = end; |
161 | } else { | ||
162 | if (features & CEPH_FEATURE_MDS_INLINE_DATA) { | ||
163 | ceph_decode_64_safe(p, end, info->inline_version, bad); | ||
164 | ceph_decode_32_safe(p, end, info->inline_len, bad); | ||
165 | ceph_decode_need(p, end, info->inline_len, bad); | ||
166 | info->inline_data = *p; | ||
167 | *p += info->inline_len; | ||
168 | } else | ||
169 | info->inline_version = CEPH_INLINE_NONE; | ||
170 | |||
171 | if (features & CEPH_FEATURE_MDS_QUOTA) { | ||
172 | err = parse_reply_info_quota(p, end, info); | ||
173 | if (err < 0) | ||
174 | goto out_bad; | ||
175 | } else { | ||
176 | info->max_bytes = 0; | ||
177 | info->max_files = 0; | ||
178 | } | ||
179 | |||
180 | info->pool_ns_len = 0; | ||
181 | info->pool_ns_data = NULL; | ||
182 | if (features & CEPH_FEATURE_FS_FILE_LAYOUT_V2) { | ||
183 | ceph_decode_32_safe(p, end, info->pool_ns_len, bad); | ||
184 | if (info->pool_ns_len > 0) { | ||
185 | ceph_decode_need(p, end, info->pool_ns_len, bad); | ||
186 | info->pool_ns_data = *p; | ||
187 | *p += info->pool_ns_len; | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | return 0; | ||
192 | bad: | ||
193 | err = -EIO; | ||
194 | out_bad: | ||
195 | return err; | ||
196 | } | ||
197 | |||
198 | static int parse_reply_info_dir(void **p, void *end, | ||
199 | struct ceph_mds_reply_dirfrag **dirfrag, | ||
200 | u64 features) | ||
201 | { | ||
202 | if (features == (u64)-1) { | ||
104 | u8 struct_v, struct_compat; | 203 | u8 struct_v, struct_compat; |
105 | u32 struct_len; | 204 | u32 struct_len; |
106 | |||
107 | /* | ||
108 | * both struct_v and struct_compat are expected to be >= 1 | ||
109 | */ | ||
110 | ceph_decode_8_safe(p, end, struct_v, bad); | 205 | ceph_decode_8_safe(p, end, struct_v, bad); |
111 | ceph_decode_8_safe(p, end, struct_compat, bad); | 206 | ceph_decode_8_safe(p, end, struct_compat, bad); |
112 | if (!struct_v || !struct_compat) | 207 | /* struct_v is expected to be >= 1. we only understand |
208 | * encoding whose struct_compat == 1. */ | ||
209 | if (!struct_v || struct_compat != 1) | ||
113 | goto bad; | 210 | goto bad; |
114 | ceph_decode_32_safe(p, end, struct_len, bad); | 211 | ceph_decode_32_safe(p, end, struct_len, bad); |
115 | ceph_decode_need(p, end, struct_len, bad); | 212 | ceph_decode_need(p, end, struct_len, bad); |
116 | ceph_decode_64_safe(p, end, info->max_bytes, bad); | 213 | end = *p + struct_len; |
117 | ceph_decode_64_safe(p, end, info->max_files, bad); | ||
118 | } else { | ||
119 | info->max_bytes = 0; | ||
120 | info->max_files = 0; | ||
121 | } | 214 | } |
122 | 215 | ||
123 | info->pool_ns_len = 0; | 216 | ceph_decode_need(p, end, sizeof(**dirfrag), bad); |
124 | info->pool_ns_data = NULL; | 217 | *dirfrag = *p; |
125 | if (features & CEPH_FEATURE_FS_FILE_LAYOUT_V2) { | 218 | *p += sizeof(**dirfrag) + sizeof(u32) * le32_to_cpu((*dirfrag)->ndist); |
126 | ceph_decode_32_safe(p, end, info->pool_ns_len, bad); | 219 | if (unlikely(*p > end)) |
127 | if (info->pool_ns_len > 0) { | 220 | goto bad; |
128 | ceph_decode_need(p, end, info->pool_ns_len, bad); | 221 | if (features == (u64)-1) |
129 | info->pool_ns_data = *p; | 222 | *p = end; |
130 | *p += info->pool_ns_len; | 223 | return 0; |
131 | } | 224 | bad: |
225 | return -EIO; | ||
226 | } | ||
227 | |||
228 | static int parse_reply_info_lease(void **p, void *end, | ||
229 | struct ceph_mds_reply_lease **lease, | ||
230 | u64 features) | ||
231 | { | ||
232 | if (features == (u64)-1) { | ||
233 | u8 struct_v, struct_compat; | ||
234 | u32 struct_len; | ||
235 | ceph_decode_8_safe(p, end, struct_v, bad); | ||
236 | ceph_decode_8_safe(p, end, struct_compat, bad); | ||
237 | /* struct_v is expected to be >= 1. we only understand | ||
238 | * encoding whose struct_compat == 1. */ | ||
239 | if (!struct_v || struct_compat != 1) | ||
240 | goto bad; | ||
241 | ceph_decode_32_safe(p, end, struct_len, bad); | ||
242 | ceph_decode_need(p, end, struct_len, bad); | ||
243 | end = *p + struct_len; | ||
132 | } | 244 | } |
133 | 245 | ||
246 | ceph_decode_need(p, end, sizeof(**lease), bad); | ||
247 | *lease = *p; | ||
248 | *p += sizeof(**lease); | ||
249 | if (features == (u64)-1) | ||
250 | *p = end; | ||
134 | return 0; | 251 | return 0; |
135 | bad: | 252 | bad: |
136 | return err; | 253 | return -EIO; |
137 | } | 254 | } |
138 | 255 | ||
139 | /* | 256 | /* |
@@ -151,20 +268,18 @@ static int parse_reply_info_trace(void **p, void *end, | |||
151 | if (err < 0) | 268 | if (err < 0) |
152 | goto out_bad; | 269 | goto out_bad; |
153 | 270 | ||
154 | if (unlikely(*p + sizeof(*info->dirfrag) > end)) | 271 | err = parse_reply_info_dir(p, end, &info->dirfrag, features); |
155 | goto bad; | 272 | if (err < 0) |
156 | info->dirfrag = *p; | 273 | goto out_bad; |
157 | *p += sizeof(*info->dirfrag) + | ||
158 | sizeof(u32)*le32_to_cpu(info->dirfrag->ndist); | ||
159 | if (unlikely(*p > end)) | ||
160 | goto bad; | ||
161 | 274 | ||
162 | ceph_decode_32_safe(p, end, info->dname_len, bad); | 275 | ceph_decode_32_safe(p, end, info->dname_len, bad); |
163 | ceph_decode_need(p, end, info->dname_len, bad); | 276 | ceph_decode_need(p, end, info->dname_len, bad); |
164 | info->dname = *p; | 277 | info->dname = *p; |
165 | *p += info->dname_len; | 278 | *p += info->dname_len; |
166 | info->dlease = *p; | 279 | |
167 | *p += sizeof(*info->dlease); | 280 | err = parse_reply_info_lease(p, end, &info->dlease, features); |
281 | if (err < 0) | ||
282 | goto out_bad; | ||
168 | } | 283 | } |
169 | 284 | ||
170 | if (info->head->is_target) { | 285 | if (info->head->is_target) { |
@@ -187,20 +302,16 @@ out_bad: | |||
187 | /* | 302 | /* |
188 | * parse readdir results | 303 | * parse readdir results |
189 | */ | 304 | */ |
190 | static int parse_reply_info_dir(void **p, void *end, | 305 | static int parse_reply_info_readdir(void **p, void *end, |
191 | struct ceph_mds_reply_info_parsed *info, | 306 | struct ceph_mds_reply_info_parsed *info, |
192 | u64 features) | 307 | u64 features) |
193 | { | 308 | { |
194 | u32 num, i = 0; | 309 | u32 num, i = 0; |
195 | int err; | 310 | int err; |
196 | 311 | ||
197 | info->dir_dir = *p; | 312 | err = parse_reply_info_dir(p, end, &info->dir_dir, features); |
198 | if (*p + sizeof(*info->dir_dir) > end) | 313 | if (err < 0) |
199 | goto bad; | 314 | goto out_bad; |
200 | *p += sizeof(*info->dir_dir) + | ||
201 | sizeof(u32)*le32_to_cpu(info->dir_dir->ndist); | ||
202 | if (*p > end) | ||
203 | goto bad; | ||
204 | 315 | ||
205 | ceph_decode_need(p, end, sizeof(num) + 2, bad); | 316 | ceph_decode_need(p, end, sizeof(num) + 2, bad); |
206 | num = ceph_decode_32(p); | 317 | num = ceph_decode_32(p); |
@@ -226,15 +337,16 @@ static int parse_reply_info_dir(void **p, void *end, | |||
226 | while (num) { | 337 | while (num) { |
227 | struct ceph_mds_reply_dir_entry *rde = info->dir_entries + i; | 338 | struct ceph_mds_reply_dir_entry *rde = info->dir_entries + i; |
228 | /* dentry */ | 339 | /* dentry */ |
229 | ceph_decode_need(p, end, sizeof(u32)*2, bad); | 340 | ceph_decode_32_safe(p, end, rde->name_len, bad); |
230 | rde->name_len = ceph_decode_32(p); | ||
231 | ceph_decode_need(p, end, rde->name_len, bad); | 341 | ceph_decode_need(p, end, rde->name_len, bad); |
232 | rde->name = *p; | 342 | rde->name = *p; |
233 | *p += rde->name_len; | 343 | *p += rde->name_len; |
234 | dout("parsed dir dname '%.*s'\n", rde->name_len, rde->name); | 344 | dout("parsed dir dname '%.*s'\n", rde->name_len, rde->name); |
235 | rde->lease = *p; | ||
236 | *p += sizeof(struct ceph_mds_reply_lease); | ||
237 | 345 | ||
346 | /* dentry lease */ | ||
347 | err = parse_reply_info_lease(p, end, &rde->lease, features); | ||
348 | if (err) | ||
349 | goto out_bad; | ||
238 | /* inode */ | 350 | /* inode */ |
239 | err = parse_reply_info_in(p, end, &rde->inode, features); | 351 | err = parse_reply_info_in(p, end, &rde->inode, features); |
240 | if (err < 0) | 352 | if (err < 0) |
@@ -285,7 +397,8 @@ static int parse_reply_info_create(void **p, void *end, | |||
285 | struct ceph_mds_reply_info_parsed *info, | 397 | struct ceph_mds_reply_info_parsed *info, |
286 | u64 features) | 398 | u64 features) |
287 | { | 399 | { |
288 | if (features & CEPH_FEATURE_REPLY_CREATE_INODE) { | 400 | if (features == (u64)-1 || |
401 | (features & CEPH_FEATURE_REPLY_CREATE_INODE)) { | ||
289 | if (*p == end) { | 402 | if (*p == end) { |
290 | info->has_create_ino = false; | 403 | info->has_create_ino = false; |
291 | } else { | 404 | } else { |
@@ -314,7 +427,7 @@ static int parse_reply_info_extra(void **p, void *end, | |||
314 | if (op == CEPH_MDS_OP_GETFILELOCK) | 427 | if (op == CEPH_MDS_OP_GETFILELOCK) |
315 | return parse_reply_info_filelock(p, end, info, features); | 428 | return parse_reply_info_filelock(p, end, info, features); |
316 | else if (op == CEPH_MDS_OP_READDIR || op == CEPH_MDS_OP_LSSNAP) | 429 | else if (op == CEPH_MDS_OP_READDIR || op == CEPH_MDS_OP_LSSNAP) |
317 | return parse_reply_info_dir(p, end, info, features); | 430 | return parse_reply_info_readdir(p, end, info, features); |
318 | else if (op == CEPH_MDS_OP_CREATE) | 431 | else if (op == CEPH_MDS_OP_CREATE) |
319 | return parse_reply_info_create(p, end, info, features); | 432 | return parse_reply_info_create(p, end, info, features); |
320 | else | 433 | else |
@@ -2657,7 +2770,10 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) | |||
2657 | 2770 | ||
2658 | dout("handle_reply tid %lld result %d\n", tid, result); | 2771 | dout("handle_reply tid %lld result %d\n", tid, result); |
2659 | rinfo = &req->r_reply_info; | 2772 | rinfo = &req->r_reply_info; |
2660 | err = parse_reply_info(msg, rinfo, session->s_con.peer_features); | 2773 | if (test_bit(CEPHFS_FEATURE_REPLY_ENCODING, &session->s_features)) |
2774 | err = parse_reply_info(msg, rinfo, (u64)-1); | ||
2775 | else | ||
2776 | err = parse_reply_info(msg, rinfo, session->s_con.peer_features); | ||
2661 | mutex_unlock(&mdsc->mutex); | 2777 | mutex_unlock(&mdsc->mutex); |
2662 | 2778 | ||
2663 | mutex_lock(&session->s_mutex); | 2779 | mutex_lock(&session->s_mutex); |
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index d3a5c4046316..0919aacc1af3 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h | |||
@@ -26,6 +26,7 @@ | |||
26 | #define CEPHFS_FEATURES_CLIENT_SUPPORTED { \ | 26 | #define CEPHFS_FEATURES_CLIENT_SUPPORTED { \ |
27 | 0, 1, 2, 3, 4, 5, 6, 7, \ | 27 | 0, 1, 2, 3, 4, 5, 6, 7, \ |
28 | CEPHFS_FEATURE_MIMIC, \ | 28 | CEPHFS_FEATURE_MIMIC, \ |
29 | CEPHFS_FEATURE_REPLY_ENCODING, \ | ||
29 | CEPHFS_FEATURE_LAZY_CAP_WANTED, \ | 30 | CEPHFS_FEATURE_LAZY_CAP_WANTED, \ |
30 | CEPHFS_FEATURE_MULTI_RECONNECT, \ | 31 | CEPHFS_FEATURE_MULTI_RECONNECT, \ |
31 | } | 32 | } |