aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2019-01-08 21:10:17 -0500
committerIlya Dryomov <idryomov@gmail.com>2019-03-05 12:55:16 -0500
commitb37fe1f923fb4b17dc7d63406ec8dc67f13c2799 (patch)
tree3628f4834ca063b260c4627a834fcf6df2cd5340 /fs/ceph
parent75c9627efb7288e1725e9903ea275cc6b5992f17 (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.c214
-rw-r--r--fs/ceph/mds_client.h1
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
68static 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;
87bad:
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;
192bad:
193 err = -EIO;
194out_bad:
195 return err;
196}
197
198static 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 } 224bad:
225 return -EIO;
226}
227
228static 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;
135bad: 252bad:
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 */
190static int parse_reply_info_dir(void **p, void *end, 305static 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}