]>
Commit | Line | Data |
---|---|---|
1d09f67e TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2021 Red Hat Inc. | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include "include/compat.h" | |
16 | #include "gtest/gtest.h" | |
17 | #include "include/cephfs/libcephfs.h" | |
18 | #include "mds/mdstypes.h" | |
19 | #include "include/stat.h" | |
20 | #include <errno.h> | |
21 | #include <fcntl.h> | |
22 | #include <unistd.h> | |
23 | #include <sys/types.h> | |
24 | #include <sys/stat.h> | |
25 | #include <dirent.h> | |
26 | #include <sys/uio.h> | |
27 | #include <sys/time.h> | |
28 | #include <sys/resource.h> | |
29 | #include <string.h> | |
30 | ||
31 | #include "common/Clock.h" | |
32 | #include "common/ceph_json.h" | |
33 | ||
34 | #ifdef __linux__ | |
35 | #include <limits.h> | |
36 | #include <sys/xattr.h> | |
37 | #endif | |
38 | ||
39 | #include <fmt/format.h> | |
40 | #include <map> | |
41 | #include <vector> | |
42 | #include <thread> | |
43 | #include <regex> | |
44 | #include <string> | |
45 | ||
46 | #ifndef ALLPERMS | |
47 | #define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) | |
48 | #endif | |
49 | ||
50 | using namespace std; | |
51 | ||
52 | TEST(LibCephFS, LayoutVerifyDefaultLayout) { | |
53 | ||
54 | struct ceph_mount_info *cmount; | |
55 | ASSERT_EQ(0, ceph_create(&cmount, NULL)); | |
56 | ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL)); | |
57 | ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL)); | |
58 | ASSERT_EQ(0, ceph_mount(cmount, "/")); | |
59 | ||
60 | ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d0/subdir", 0777)); | |
61 | ||
62 | { | |
63 | char value[1024] = ""; | |
64 | int r = 0; | |
65 | ||
66 | // check for default layout | |
67 | r = ceph_getxattr(cmount, "/", "ceph.dir.layout.json", (void*)value, sizeof(value)); | |
68 | ASSERT_GT(r, 0); | |
69 | ASSERT_LT(r, sizeof value); | |
70 | std::clog << "layout:" << value << std::endl; | |
71 | ASSERT_STRNE((char*)NULL, strstr(value, "\"inheritance\": \"@default\"")); | |
72 | } | |
73 | ||
74 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0/subdir")); | |
75 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0")); | |
76 | ASSERT_EQ(0, ceph_rmdir(cmount, "test")); | |
77 | ||
78 | ceph_shutdown(cmount); | |
79 | } | |
80 | ||
81 | TEST(LibCephFS, LayoutSetAndVerifyNewAndInheritedLayout) { | |
82 | ||
83 | struct ceph_mount_info *cmount; | |
84 | ASSERT_EQ(0, ceph_create(&cmount, NULL)); | |
85 | ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL)); | |
86 | ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL)); | |
87 | ASSERT_EQ(0, ceph_mount(cmount, "/")); | |
88 | ||
89 | ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d0/subdir", 0777)); | |
90 | ||
91 | std::string pool_name_set; | |
92 | ||
93 | { | |
94 | char value[1024] = ""; | |
95 | int r = 0; | |
96 | ||
97 | r = ceph_getxattr(cmount, "/", "ceph.dir.layout.json", (void*)value, sizeof(value)); | |
98 | ASSERT_GT(r, 0); | |
99 | ASSERT_LT(r, sizeof value); | |
100 | ||
101 | JSONParser json_parser; | |
102 | ASSERT_EQ(json_parser.parse(value, r), 1); | |
103 | ASSERT_EQ(json_parser.is_object(), 1); | |
104 | ||
105 | std::string pool_name; | |
106 | ||
107 | JSONDecoder::decode_json("pool_name", pool_name, &json_parser, true); | |
108 | ||
109 | pool_name_set = pool_name; | |
110 | ||
111 | // set a new layout | |
112 | std::string new_layout; | |
113 | new_layout += "{"; | |
114 | new_layout += "\"stripe_unit\": 65536, "; | |
115 | new_layout += "\"stripe_count\": 1, "; | |
116 | new_layout += "\"object_size\": 65536, "; | |
117 | new_layout += "\"pool_name\": \"" + pool_name + "\""; | |
118 | new_layout += "}"; | |
119 | ||
120 | ASSERT_EQ(0, ceph_setxattr(cmount, "test/d0", "ceph.dir.layout.json", (void*)new_layout.c_str(), new_layout.length(), XATTR_CREATE)); | |
121 | } | |
122 | ||
123 | { | |
124 | char value[1024] = ""; | |
125 | int r = 0; | |
126 | ||
127 | r = ceph_getxattr(cmount, "test/d0", "ceph.dir.layout.json", (void*)value, sizeof(value)); | |
128 | ASSERT_GT(r, 0); | |
129 | ASSERT_LT(r, sizeof value); | |
130 | std::clog << "layout:" << value << std::endl; | |
131 | ||
132 | JSONParser json_parser; | |
133 | ASSERT_EQ(json_parser.parse(value, r), 1); | |
134 | ASSERT_EQ(json_parser.is_object(), 1); | |
135 | ||
136 | int64_t object_size; | |
137 | int64_t stripe_unit; | |
138 | int64_t stripe_count; | |
139 | std::string pool_name; | |
140 | std::string inheritance; | |
141 | ||
142 | JSONDecoder::decode_json("pool_name", pool_name, &json_parser, true); | |
143 | JSONDecoder::decode_json("object_size", object_size, &json_parser, true); | |
144 | JSONDecoder::decode_json("stripe_unit", stripe_unit, &json_parser, true); | |
145 | JSONDecoder::decode_json("stripe_count", stripe_count, &json_parser, true); | |
146 | JSONDecoder::decode_json("inheritance", inheritance, &json_parser, true); | |
147 | ||
148 | // now verify the layout | |
149 | ASSERT_EQ(pool_name.compare(pool_name_set), 0); | |
150 | ASSERT_EQ(object_size, 65536); | |
151 | ASSERT_EQ(stripe_unit, 65536); | |
152 | ASSERT_EQ(stripe_count, 1); | |
153 | ASSERT_EQ(inheritance.compare("@set"), 0); | |
154 | } | |
155 | ||
156 | { | |
157 | char value[1024] = ""; | |
158 | int r = 0; | |
159 | ||
160 | JSONParser json_parser; | |
161 | std::string inheritance; | |
162 | ||
163 | // now check that the subdir layout is inherited | |
164 | r = ceph_getxattr(cmount, "test/d0/subdir", "ceph.dir.layout.json", (void*)value, sizeof(value)); | |
165 | ASSERT_GT(r, 0); | |
166 | ASSERT_LT(r, sizeof value); | |
167 | std::clog << "layout:" << value << std::endl; | |
168 | ASSERT_EQ(json_parser.parse(value, r), 1); | |
169 | ASSERT_EQ(json_parser.is_object(), 1); | |
170 | JSONDecoder::decode_json("inheritance", inheritance, &json_parser, true); | |
171 | ASSERT_EQ(inheritance.compare("@inherited"), 0); | |
172 | } | |
173 | ||
174 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0/subdir")); | |
175 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0")); | |
176 | ASSERT_EQ(0, ceph_rmdir(cmount, "test")); | |
177 | ||
178 | ceph_shutdown(cmount); | |
179 | } | |
180 | ||
181 | TEST(LibCephFS, LayoutSetBadJSON) { | |
182 | ||
183 | struct ceph_mount_info *cmount; | |
184 | ASSERT_EQ(0, ceph_create(&cmount, NULL)); | |
185 | ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL)); | |
186 | ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL)); | |
187 | ASSERT_EQ(0, ceph_mount(cmount, "/")); | |
188 | ||
189 | ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d0/subdir", 0777)); | |
190 | ||
191 | { | |
192 | // set a new layout and verify the same | |
193 | const char *new_layout = "" // bad json without starting brace | |
194 | "\"stripe_unit\": 65536, " | |
195 | "\"stripe_count\": 1, " | |
196 | "\"object_size\": 65536, " | |
197 | "\"pool_name\": \"cephfs.a.data\", " | |
198 | "}"; | |
199 | // try to set a malformed JSON, eg. without an open brace | |
200 | ASSERT_EQ(-EINVAL, ceph_setxattr(cmount, "test/d0", "ceph.dir.layout.json", (void*)new_layout, strlen(new_layout), XATTR_CREATE)); | |
201 | } | |
202 | ||
203 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0/subdir")); | |
204 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0")); | |
205 | ASSERT_EQ(0, ceph_rmdir(cmount, "test")); | |
206 | ||
207 | ceph_shutdown(cmount); | |
208 | } | |
209 | ||
210 | TEST(LibCephFS, LayoutSetBadPoolName) { | |
211 | ||
212 | struct ceph_mount_info *cmount; | |
213 | ASSERT_EQ(0, ceph_create(&cmount, NULL)); | |
214 | ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL)); | |
215 | ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL)); | |
216 | ASSERT_EQ(0, ceph_mount(cmount, "/")); | |
217 | ||
218 | ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d0/subdir", 0777)); | |
219 | ||
220 | { | |
221 | // try setting a bad pool name | |
222 | ASSERT_EQ(-EINVAL, ceph_setxattr(cmount, "test/d0", "ceph.dir.layout.pool_name", (void*)"UglyPoolName", 12, XATTR_CREATE)); | |
223 | } | |
224 | ||
225 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0/subdir")); | |
226 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0")); | |
227 | ASSERT_EQ(0, ceph_rmdir(cmount, "test")); | |
228 | ||
229 | ceph_shutdown(cmount); | |
230 | } | |
231 | ||
232 | TEST(LibCephFS, LayoutSetBadPoolId) { | |
233 | ||
234 | struct ceph_mount_info *cmount; | |
235 | ASSERT_EQ(0, ceph_create(&cmount, NULL)); | |
236 | ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL)); | |
237 | ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL)); | |
238 | ASSERT_EQ(0, ceph_mount(cmount, "/")); | |
239 | ||
240 | ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d0/subdir", 0777)); | |
241 | ||
242 | { | |
243 | // try setting a bad pool id | |
244 | ASSERT_EQ(-EINVAL, ceph_setxattr(cmount, "test/d0", "ceph.dir.layout.pool_id", (void*)"300", 3, XATTR_CREATE)); | |
245 | } | |
246 | ||
247 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0/subdir")); | |
248 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0")); | |
249 | ASSERT_EQ(0, ceph_rmdir(cmount, "test")); | |
250 | ||
251 | ceph_shutdown(cmount); | |
252 | } | |
253 | ||
254 | TEST(LibCephFS, LayoutSetInvalidFieldName) { | |
255 | ||
256 | struct ceph_mount_info *cmount; | |
257 | ASSERT_EQ(0, ceph_create(&cmount, NULL)); | |
258 | ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL)); | |
259 | ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL)); | |
260 | ASSERT_EQ(0, ceph_mount(cmount, "/")); | |
261 | ||
262 | ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d0/subdir", 0777)); | |
263 | ||
264 | { | |
265 | // try to set in invalid field | |
266 | ASSERT_EQ(-ENODATA, ceph_setxattr(cmount, "test/d0", "ceph.dir.layout.bad_field", (void*)"300", 3, XATTR_CREATE)); | |
267 | } | |
268 | ||
269 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0/subdir")); | |
270 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d0")); | |
271 | ASSERT_EQ(0, ceph_rmdir(cmount, "test")); | |
272 | ||
273 | ceph_shutdown(cmount); | |
274 | } | |
275 | ||
276 | TEST(LibCephFS, GetAndSetDirPin) { | |
277 | ||
278 | struct ceph_mount_info *cmount; | |
279 | ASSERT_EQ(0, ceph_create(&cmount, NULL)); | |
280 | ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL)); | |
281 | ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL)); | |
282 | ASSERT_EQ(0, ceph_mount(cmount, "/")); | |
283 | ||
284 | ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d1", 0777)); | |
285 | ||
286 | { | |
287 | char value[1024] = ""; | |
288 | int r = ceph_getxattr(cmount, "test/d1", "ceph.dir.pin", (void*)value, sizeof(value)); | |
289 | ASSERT_GT(r, 0); | |
290 | ASSERT_LT(r, sizeof value); | |
291 | ASSERT_STREQ("-1", value); | |
292 | } | |
293 | ||
294 | { | |
295 | char value[1024] = ""; | |
296 | int r = -1; | |
297 | ||
298 | ASSERT_EQ(0, ceph_setxattr(cmount, "test/d1", "ceph.dir.pin", (void*)"1", 1, XATTR_CREATE)); | |
299 | ||
300 | r = ceph_getxattr(cmount, "test/d1", "ceph.dir.pin", (void*)value, sizeof(value)); | |
301 | ASSERT_GT(r, 0); | |
302 | ASSERT_LT(r, sizeof value); | |
303 | ASSERT_STREQ("1", value); | |
304 | } | |
305 | ||
306 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d1")); | |
307 | ASSERT_EQ(0, ceph_rmdir(cmount, "test")); | |
308 | ||
309 | ceph_shutdown(cmount); | |
310 | } | |
311 | ||
312 | TEST(LibCephFS, GetAndSetDirDistribution) { | |
313 | ||
314 | struct ceph_mount_info *cmount; | |
315 | ASSERT_EQ(0, ceph_create(&cmount, NULL)); | |
316 | ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL)); | |
317 | ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL)); | |
318 | ASSERT_EQ(0, ceph_mount(cmount, "/")); | |
319 | ||
320 | ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d2", 0777)); | |
321 | ||
322 | { | |
323 | char value[1024] = ""; | |
324 | int r = ceph_getxattr(cmount, "test/d2", "ceph.dir.pin.distributed", (void*)value, sizeof(value)); | |
325 | ASSERT_GT(r, 0); | |
326 | ASSERT_LT(r, sizeof value); | |
327 | ASSERT_STREQ("0", value); | |
328 | } | |
329 | ||
330 | { | |
331 | char value[1024] = ""; | |
332 | int r = -1; | |
333 | ||
334 | ASSERT_EQ(0, ceph_setxattr(cmount, "test/d2", "ceph.dir.pin.distributed", (void*)"1", 1, XATTR_CREATE)); | |
335 | ||
336 | r = ceph_getxattr(cmount, "test/d2", "ceph.dir.pin.distributed", (void*)value, sizeof(value)); | |
337 | ASSERT_GT(r, 0); | |
338 | ASSERT_LT(r, sizeof value); | |
339 | ASSERT_STREQ("1", value); | |
340 | } | |
341 | ||
342 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d2")); | |
343 | ASSERT_EQ(0, ceph_rmdir(cmount, "test")); | |
344 | ||
345 | ceph_shutdown(cmount); | |
346 | } | |
347 | ||
348 | TEST(LibCephFS, GetAndSetDirRandom) { | |
349 | ||
350 | struct ceph_mount_info *cmount; | |
351 | ASSERT_EQ(0, ceph_create(&cmount, NULL)); | |
352 | ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL)); | |
353 | ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL)); | |
354 | ASSERT_EQ(0, ceph_mount(cmount, "/")); | |
355 | ||
356 | ASSERT_EQ(0, ceph_mkdirs(cmount, "test/d3", 0777)); | |
357 | ||
358 | { | |
359 | char value[1024] = ""; | |
360 | int r = ceph_getxattr(cmount, "test/d3", "ceph.dir.pin.random", (void*)value, sizeof(value)); | |
361 | ASSERT_GT(r, 0); | |
362 | ASSERT_LT(r, sizeof value); | |
363 | ASSERT_STREQ("0", value); | |
364 | } | |
365 | ||
366 | { | |
367 | double val = (double)1.0/(double)128.0; | |
368 | std::stringstream ss; | |
369 | ss << val; | |
370 | ASSERT_EQ(0, ceph_setxattr(cmount, "test/d3", "ceph.dir.pin.random", (void*)ss.str().c_str(), strlen(ss.str().c_str()), XATTR_CREATE)); | |
371 | ||
372 | char value[1024] = ""; | |
373 | int r = -1; | |
374 | ||
375 | r = ceph_getxattr(cmount, "test/d3", "ceph.dir.pin.random", (void*)value, sizeof(value)); | |
376 | ASSERT_GT(r, 0); | |
377 | ASSERT_LT(r, sizeof value); | |
378 | ASSERT_STREQ(ss.str().c_str(), value); | |
379 | } | |
380 | ||
381 | ASSERT_EQ(0, ceph_rmdir(cmount, "test/d3")); | |
382 | ASSERT_EQ(0, ceph_rmdir(cmount, "test")); | |
383 | ||
384 | ceph_shutdown(cmount); | |
385 | } |