]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/libcephfs/test.cc
update sources to v12.2.3
[ceph.git] / ceph / src / test / libcephfs / test.cc
CommitLineData
7c673cae
FG
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) 2011 New Dream Network
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 "gtest/gtest.h"
16#include "include/cephfs/libcephfs.h"
17#include "include/stat.h"
18#include <errno.h>
19#include <fcntl.h>
20#include <unistd.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <dirent.h>
24#include <sys/xattr.h>
25#include <sys/uio.h>
b32b8144
FG
26#include <sys/time.h>
27#include <sys/resource.h>
7c673cae
FG
28
29#ifdef __linux__
30#include <limits.h>
31#endif
32
33#include <map>
34#include <vector>
b32b8144 35#include <thread>
7c673cae
FG
36
37TEST(LibCephFS, OpenEmptyComponent) {
38
39 pid_t mypid = getpid();
40 struct ceph_mount_info *cmount;
41 ASSERT_EQ(0, ceph_create(&cmount, NULL));
42 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
43 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
44 ASSERT_EQ(0, ceph_mount(cmount, "/"));
45
46 char c_dir[1024];
47 sprintf(c_dir, "/open_test_%d", mypid);
48 struct ceph_dir_result *dirp;
49
50 ASSERT_EQ(0, ceph_mkdirs(cmount, c_dir, 0777));
51
52 ASSERT_EQ(0, ceph_opendir(cmount, c_dir, &dirp));
53
54 char c_path[1024];
55 sprintf(c_path, "/open_test_%d//created_file_%d", mypid, mypid);
56 int fd = ceph_open(cmount, c_path, O_RDONLY|O_CREAT, 0666);
57 ASSERT_LT(0, fd);
58
59 ASSERT_EQ(0, ceph_close(cmount, fd));
60 ASSERT_EQ(0, ceph_closedir(cmount, dirp));
61 ceph_shutdown(cmount);
62
63 ASSERT_EQ(0, ceph_create(&cmount, NULL));
64 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
65 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
66
67 ASSERT_EQ(0, ceph_mount(cmount, "/"));
68
69 fd = ceph_open(cmount, c_path, O_RDONLY, 0666);
70 ASSERT_LT(0, fd);
71
72 ASSERT_EQ(0, ceph_close(cmount, fd));
73 ceph_shutdown(cmount);
74}
75
76TEST(LibCephFS, OpenReadWrite) {
77 struct ceph_mount_info *cmount;
78 ASSERT_EQ(0, ceph_create(&cmount, NULL));
79 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
80 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
81 ASSERT_EQ(0, ceph_mount(cmount, "/"));
82
83 char c_path[1024];
84 sprintf(c_path, "test_open_rdwr_%d", getpid());
85 int fd = ceph_open(cmount, c_path, O_WRONLY|O_CREAT, 0666);
86 ASSERT_LT(0, fd);
87
88 const char *out_buf = "hello world";
89 size_t size = strlen(out_buf);
90 char in_buf[100];
91 ASSERT_EQ(ceph_write(cmount, fd, out_buf, size, 0), (int)size);
92 ASSERT_EQ(ceph_read(cmount, fd, in_buf, sizeof(in_buf), 0), -EBADF);
93 ASSERT_EQ(0, ceph_close(cmount, fd));
94
95 fd = ceph_open(cmount, c_path, O_RDONLY, 0);
96 ASSERT_LT(0, fd);
97 ASSERT_EQ(ceph_write(cmount, fd, out_buf, size, 0), -EBADF);
98 ASSERT_EQ(ceph_read(cmount, fd, in_buf, sizeof(in_buf), 0), (int)size);
99 ASSERT_EQ(0, ceph_close(cmount, fd));
100
101 fd = ceph_open(cmount, c_path, O_RDWR, 0);
102 ASSERT_LT(0, fd);
103 ASSERT_EQ(ceph_write(cmount, fd, out_buf, size, 0), (int)size);
104 ASSERT_EQ(ceph_read(cmount, fd, in_buf, sizeof(in_buf), 0), (int)size);
105 ASSERT_EQ(0, ceph_close(cmount, fd));
106
107 ceph_shutdown(cmount);
108}
109
110TEST(LibCephFS, MountNonExist) {
111
112 struct ceph_mount_info *cmount;
113
114 ASSERT_EQ(0, ceph_create(&cmount, NULL));
115 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
116 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
117 ASSERT_NE(0, ceph_mount(cmount, "/non-exist"));
118 ceph_shutdown(cmount);
119}
120
121TEST(LibCephFS, MountDouble) {
122
123 struct ceph_mount_info *cmount;
124
125 ASSERT_EQ(0, ceph_create(&cmount, NULL));
126 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
127 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
128 ASSERT_EQ(0, ceph_mount(cmount, "/"));
129 ASSERT_EQ(-EISCONN, ceph_mount(cmount, "/"));
130 ceph_shutdown(cmount);
131}
132
133TEST(LibCephFS, MountRemount) {
134
135 struct ceph_mount_info *cmount;
136
137 ASSERT_EQ(0, ceph_create(&cmount, NULL));
138 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
139 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
140
141 CephContext *cct = ceph_get_mount_context(cmount);
142 ASSERT_EQ(0, ceph_mount(cmount, "/"));
143 ASSERT_EQ(0, ceph_unmount(cmount));
144
145 ASSERT_EQ(0, ceph_mount(cmount, "/"));
146 ASSERT_EQ(cct, ceph_get_mount_context(cmount));
147
148 ceph_shutdown(cmount);
149}
150
151TEST(LibCephFS, UnmountUnmounted) {
152
153 struct ceph_mount_info *cmount;
154
155 ASSERT_EQ(0, ceph_create(&cmount, NULL));
156 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
157 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
158 ASSERT_EQ(-ENOTCONN, ceph_unmount(cmount));
159 ceph_shutdown(cmount);
160}
161
162TEST(LibCephFS, ReleaseUnmounted) {
163
164 struct ceph_mount_info *cmount;
165
166 ASSERT_EQ(0, ceph_create(&cmount, NULL));
167 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
168 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
169 ASSERT_EQ(0, ceph_release(cmount));
170}
171
172TEST(LibCephFS, ReleaseMounted) {
173
174 struct ceph_mount_info *cmount;
175
176 ASSERT_EQ(0, ceph_create(&cmount, NULL));
177 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
178 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
179 ASSERT_EQ(0, ceph_mount(cmount, "/"));
180 ASSERT_EQ(-EISCONN, ceph_release(cmount));
181 ASSERT_EQ(0, ceph_unmount(cmount));
182 ASSERT_EQ(0, ceph_release(cmount));
183}
184
185TEST(LibCephFS, UnmountRelease) {
186
187 struct ceph_mount_info *cmount;
188
189 ASSERT_EQ(0, ceph_create(&cmount, NULL));
190 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
191 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
192 ASSERT_EQ(0, ceph_mount(cmount, "/"));
193 ASSERT_EQ(0, ceph_unmount(cmount));
194 ASSERT_EQ(0, ceph_release(cmount));
195}
196
197TEST(LibCephFS, Mount) {
198 struct ceph_mount_info *cmount;
199 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
200 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
201 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
202 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
203 ceph_shutdown(cmount);
204
205 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
206 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
207 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
208 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
209 ceph_shutdown(cmount);
210}
211
212TEST(LibCephFS, OpenLayout) {
213 struct ceph_mount_info *cmount;
214 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
215 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
216 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
217 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
218
219 /* valid layout */
220 char test_layout_file[256];
221 sprintf(test_layout_file, "test_layout_%d_b", getpid());
222 int fd = ceph_open_layout(cmount, test_layout_file, O_CREAT|O_WRONLY, 0666, (1<<20), 7, (1<<20), NULL);
223 ASSERT_GT(fd, 0);
224 char poolname[80];
225 ASSERT_LT(0, ceph_get_file_pool_name(cmount, fd, poolname, sizeof(poolname)));
226 ASSERT_LT(0, ceph_get_file_pool_name(cmount, fd, poolname, 0));
227
228 /* on already-written file (ENOTEMPTY) */
229 ceph_write(cmount, fd, "hello world", 11, 0);
230 ceph_close(cmount, fd);
231
232 char xattrk[128];
233 char xattrv[128];
234 sprintf(xattrk, "ceph.file.layout.stripe_unit");
235 sprintf(xattrv, "65536");
236 ASSERT_EQ(-ENOTEMPTY, ceph_setxattr(cmount, test_layout_file, xattrk, (void *)xattrv, 5, 0));
237
238 /* invalid layout */
239 sprintf(test_layout_file, "test_layout_%d_c", getpid());
240 fd = ceph_open_layout(cmount, test_layout_file, O_CREAT, 0666, (1<<20), 1, 19, NULL);
241 ASSERT_EQ(fd, -EINVAL);
242
243 /* with data pool */
244 sprintf(test_layout_file, "test_layout_%d_d", getpid());
245 fd = ceph_open_layout(cmount, test_layout_file, O_CREAT, 0666, (1<<20), 7, (1<<20), poolname);
246 ASSERT_GT(fd, 0);
247 ceph_close(cmount, fd);
248
249 /* with metadata pool (invalid) */
250 sprintf(test_layout_file, "test_layout_%d_e", getpid());
251 fd = ceph_open_layout(cmount, test_layout_file, O_CREAT, 0666, (1<<20), 7, (1<<20), "metadata");
252 ASSERT_EQ(fd, -EINVAL);
253
254 /* with metadata pool (does not exist) */
255 sprintf(test_layout_file, "test_layout_%d_f", getpid());
256 fd = ceph_open_layout(cmount, test_layout_file, O_CREAT, 0666, (1<<20), 7, (1<<20), "asdfjasdfjasdf");
257 ASSERT_EQ(fd, -EINVAL);
258
259 ceph_shutdown(cmount);
260}
261
262TEST(LibCephFS, DirLs) {
263
264 pid_t mypid = getpid();
265
266 struct ceph_mount_info *cmount;
267 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
268 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
269 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
270 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
271
272 struct ceph_dir_result *ls_dir = NULL;
273 char foostr[256];
274 sprintf(foostr, "dir_ls%d", mypid);
275 ASSERT_EQ(ceph_opendir(cmount, foostr, &ls_dir), -ENOENT);
276
277 ASSERT_EQ(ceph_mkdir(cmount, foostr, 0777), 0);
278 struct ceph_statx stx;
279 ASSERT_EQ(ceph_statx(cmount, foostr, &stx, 0, 0), 0);
280 ASSERT_NE(S_ISDIR(stx.stx_mode), 0);
281
282 char barstr[256];
283 sprintf(barstr, "dir_ls2%d", mypid);
284 ASSERT_EQ(ceph_statx(cmount, barstr, &stx, 0, AT_SYMLINK_NOFOLLOW), -ENOENT);
285
286 // insert files into directory and test open
287 char bazstr[256];
288 int i = 0, r = rand() % 4096;
289 if (getenv("LIBCEPHFS_RAND")) {
290 r = atoi(getenv("LIBCEPHFS_RAND"));
291 }
292 printf("rand: %d\n", r);
293 for(; i < r; ++i) {
294
295 sprintf(bazstr, "dir_ls%d/dirf%d", mypid, i);
296 int fd = ceph_open(cmount, bazstr, O_CREAT|O_RDONLY, 0666);
297 ASSERT_GT(fd, 0);
298 ASSERT_EQ(ceph_close(cmount, fd), 0);
299
300 // set file sizes for readdirplus
301 ceph_truncate(cmount, bazstr, i);
302 }
303
304 ASSERT_EQ(ceph_opendir(cmount, foostr, &ls_dir), 0);
305
306 // not guaranteed to get . and .. first, but its a safe assumption in this case
307 struct dirent *result = ceph_readdir(cmount, ls_dir);
308 ASSERT_TRUE(result != NULL);
309 ASSERT_STREQ(result->d_name, ".");
310 result = ceph_readdir(cmount, ls_dir);
311 ASSERT_TRUE(result != NULL);
312 ASSERT_STREQ(result->d_name, "..");
313
314 std::vector<std::string> entries;
315 std::map<std::string, int64_t> offset_map;
316 int64_t offset = ceph_telldir(cmount, ls_dir);
317 for(i = 0; i < r; ++i) {
318 result = ceph_readdir(cmount, ls_dir);
319 ASSERT_TRUE(result != NULL);
320 entries.push_back(result->d_name);
321 offset_map[result->d_name] = offset;
322 offset = ceph_telldir(cmount, ls_dir);
323 }
324
325 ASSERT_TRUE(ceph_readdir(cmount, ls_dir) == NULL);
326 offset = ceph_telldir(cmount, ls_dir);
327
328 ASSERT_EQ(offset_map.size(), entries.size());
329 for(i = 0; i < r; ++i) {
330 sprintf(bazstr, "dirf%d", i);
331 ASSERT_TRUE(offset_map.count(bazstr) == 1);
332 }
333
334 // test seekdir
335 ceph_seekdir(cmount, ls_dir, offset);
336 ASSERT_TRUE(ceph_readdir(cmount, ls_dir) == NULL);
337
338 for (auto p = offset_map.begin(); p != offset_map.end(); ++p) {
339 ceph_seekdir(cmount, ls_dir, p->second);
340 result = ceph_readdir(cmount, ls_dir);
341 ASSERT_TRUE(result != NULL);
342 std::string d_name(result->d_name);
343 ASSERT_EQ(p->first, d_name);
344 }
345
346 // test rewinddir
347 ceph_rewinddir(cmount, ls_dir);
348
349 result = ceph_readdir(cmount, ls_dir);
350 ASSERT_TRUE(result != NULL);
351 ASSERT_STREQ(result->d_name, ".");
352 result = ceph_readdir(cmount, ls_dir);
353 ASSERT_TRUE(result != NULL);
354 ASSERT_STREQ(result->d_name, "..");
355
356 ceph_rewinddir(cmount, ls_dir);
357
358 int t = ceph_telldir(cmount, ls_dir);
359 ASSERT_GT(t, -1);
360
361 ASSERT_TRUE(ceph_readdir(cmount, ls_dir) != NULL);
362
363 // test seekdir - move back to the beginning
364 ceph_seekdir(cmount, ls_dir, t);
365
366 // test getdents
367 struct dirent *getdents_entries;
368 getdents_entries = (struct dirent *)malloc((r + 2) * sizeof(*getdents_entries));
369
370 int count = 0;
371 std::vector<std::string> found;
372 while (true) {
373 int len = ceph_getdents(cmount, ls_dir, (char *)getdents_entries, r * sizeof(*getdents_entries));
374 if (len == 0)
375 break;
376 ASSERT_GT(len, 0);
377 ASSERT_TRUE((len % sizeof(*getdents_entries)) == 0);
378 int n = len / sizeof(*getdents_entries);
379 int j;
380 if (count == 0) {
381 ASSERT_STREQ(getdents_entries[0].d_name, ".");
382 ASSERT_STREQ(getdents_entries[1].d_name, "..");
383 j = 2;
384 } else {
385 j = 0;
386 }
387 count += n;
388 for(; j < n; ++i, ++j) {
389 const char *name = getdents_entries[j].d_name;
390 found.push_back(name);
391 }
392 }
393 ASSERT_EQ(found, entries);
394 free(getdents_entries);
395
396 // test readdir_r
397 ceph_rewinddir(cmount, ls_dir);
398
399 result = ceph_readdir(cmount, ls_dir);
400 ASSERT_TRUE(result != NULL);
401 ASSERT_STREQ(result->d_name, ".");
402 result = ceph_readdir(cmount, ls_dir);
403 ASSERT_TRUE(result != NULL);
404 ASSERT_STREQ(result->d_name, "..");
405
406 found.clear();
407 while (true) {
408 struct dirent rdent;
409 int len = ceph_readdir_r(cmount, ls_dir, &rdent);
410 if (len == 0)
411 break;
412 ASSERT_EQ(len, 1);
413 found.push_back(rdent.d_name);
414 }
415 ASSERT_EQ(found, entries);
416
417 // test readdirplus
418 ceph_rewinddir(cmount, ls_dir);
419
420 result = ceph_readdir(cmount, ls_dir);
421 ASSERT_TRUE(result != NULL);
422 ASSERT_STREQ(result->d_name, ".");
423 result = ceph_readdir(cmount, ls_dir);
424 ASSERT_TRUE(result != NULL);
425 ASSERT_STREQ(result->d_name, "..");
426
427 found.clear();
428 while (true) {
429 struct dirent rdent;
430 struct ceph_statx stx;
431 int len = ceph_readdirplus_r(cmount, ls_dir, &rdent, &stx,
432 CEPH_STATX_SIZE, AT_NO_ATTR_SYNC, NULL);
433 if (len == 0)
434 break;
435 ASSERT_EQ(len, 1);
436 const char *name = rdent.d_name;
437 found.push_back(name);
438 int size;
439 sscanf(name, "dirf%d", &size);
440 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_SIZE);
441 ASSERT_EQ(stx.stx_size, (size_t)size);
442 ASSERT_EQ(stx.stx_ino, rdent.d_ino);
443 //ASSERT_EQ(st.st_mode, (mode_t)0666);
444 }
445 ASSERT_EQ(found, entries);
446
447 ASSERT_EQ(ceph_closedir(cmount, ls_dir), 0);
448
449 ceph_shutdown(cmount);
450}
451
452TEST(LibCephFS, ManyNestedDirs) {
453 struct ceph_mount_info *cmount;
454 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
455 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
456 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
457 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
458
459 const char *many_path = "a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a";
460 ASSERT_EQ(ceph_mkdirs(cmount, many_path, 0755), 0);
461
462 int i = 0;
463
464 for(; i < 39; ++i) {
465 ASSERT_EQ(ceph_chdir(cmount, "a"), 0);
466
467 struct ceph_dir_result *dirp;
468 ASSERT_EQ(ceph_opendir(cmount, "a", &dirp), 0);
469 struct dirent *dent = ceph_readdir(cmount, dirp);
470 ASSERT_TRUE(dent != NULL);
471 ASSERT_STREQ(dent->d_name, ".");
472 dent = ceph_readdir(cmount, dirp);
473 ASSERT_TRUE(dent != NULL);
474 ASSERT_STREQ(dent->d_name, "..");
475 dent = ceph_readdir(cmount, dirp);
476 ASSERT_TRUE(dent != NULL);
477 ASSERT_STREQ(dent->d_name, "a");
478 ASSERT_EQ(ceph_closedir(cmount, dirp), 0);
479 }
480
481 ASSERT_STREQ(ceph_getcwd(cmount), "/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a");
482
483 ASSERT_EQ(ceph_chdir(cmount, "a/a/a"), 0);
484
485 for(i = 0; i < 39; ++i) {
486 ASSERT_EQ(ceph_chdir(cmount, ".."), 0);
487 ASSERT_EQ(ceph_rmdir(cmount, "a"), 0);
488 }
489
490 ASSERT_EQ(ceph_chdir(cmount, "/"), 0);
491
492 ASSERT_EQ(ceph_rmdir(cmount, "a/a/a"), 0);
493
494 ceph_shutdown(cmount);
495}
496
497TEST(LibCephFS, Xattrs) {
498 struct ceph_mount_info *cmount;
499 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
500 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
501 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
502 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
503
504 char test_xattr_file[256];
505 sprintf(test_xattr_file, "test_xattr_%d", getpid());
506 int fd = ceph_open(cmount, test_xattr_file, O_CREAT, 0666);
507 ASSERT_GT(fd, 0);
508
509 char i = 'a';
510 char xattrk[128];
511 char xattrv[128];
512 for(; i < 'a'+26; ++i) {
513 sprintf(xattrk, "user.test_xattr_%c", i);
514 int len = sprintf(xattrv, "testxattr%c", i);
515 ASSERT_EQ(ceph_setxattr(cmount, test_xattr_file, xattrk, (void *) xattrv, len, XATTR_CREATE), 0);
516 }
517
518 char xattrlist[128*26];
519 int len = ceph_listxattr(cmount, test_xattr_file, xattrlist, sizeof(xattrlist));
520 char *p = xattrlist;
521 char *n;
522 i = 'a';
523 while (len > 0) {
524 // skip/ignore the dir layout
525 if (strcmp(p, "ceph.dir.layout") == 0 ||
526 strcmp(p, "ceph.file.layout") == 0) {
527 len -= strlen(p) + 1;
528 p += strlen(p) + 1;
529 continue;
530 }
531
532 sprintf(xattrk, "user.test_xattr_%c", i);
533 ASSERT_STREQ(p, xattrk);
534
535 char gxattrv[128];
536 std::cout << "getting attr " << p << std::endl;
537 int alen = ceph_getxattr(cmount, test_xattr_file, p, (void *) gxattrv, 128);
538 ASSERT_GT(alen, 0);
539 sprintf(xattrv, "testxattr%c", i);
540 ASSERT_TRUE(!strncmp(xattrv, gxattrv, alen));
541
542 n = index(p, '\0');
543 n++;
544 len -= (n - p);
545 p = n;
546 ++i;
547 }
548
549 i = 'a';
550 for(i = 'a'; i < 'a'+26; ++i) {
551 sprintf(xattrk, "user.test_xattr_%c", i);
552 ASSERT_EQ(ceph_removexattr(cmount, test_xattr_file, xattrk), 0);
553 }
554
555 ceph_close(cmount, fd);
556 ceph_shutdown(cmount);
557
558}
559
560TEST(LibCephFS, Xattrs_ll) {
561 struct ceph_mount_info *cmount;
562 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
563 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
564 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
565 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
566
567 char test_xattr_file[256];
568 sprintf(test_xattr_file, "test_xattr_%d", getpid());
569 int fd = ceph_open(cmount, test_xattr_file, O_CREAT, 0666);
570 ASSERT_GT(fd, 0);
571 ceph_close(cmount, fd);
572
573 Inode *root = NULL;
574 Inode *existent_file_handle = NULL;
575
576 int res = ceph_ll_lookup_root(cmount, &root);
577 ASSERT_EQ(res, 0);
578
579 UserPerm *perms = ceph_mount_perms(cmount);
580 struct ceph_statx stx;
581
582 res = ceph_ll_lookup(cmount, root, test_xattr_file, &existent_file_handle,
583 &stx, 0, 0, perms);
584 ASSERT_EQ(res, 0);
585
586 const char *valid_name = "user.attrname";
587 const char *value = "attrvalue";
588 char value_buf[256] = { 0 };
589
590 res = ceph_ll_setxattr(cmount, existent_file_handle, valid_name, value, strlen(value), 0, perms);
591 ASSERT_EQ(res, 0);
592
593 res = ceph_ll_getxattr(cmount, existent_file_handle, valid_name, value_buf, 256, perms);
594 ASSERT_EQ(res, (int)strlen(value));
595
596 value_buf[res] = '\0';
597 ASSERT_STREQ(value_buf, value);
598
599 ceph_shutdown(cmount);
600}
601
602TEST(LibCephFS, LstatSlashdot) {
603 struct ceph_mount_info *cmount;
604 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
605 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
606 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
607 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
608
609 struct ceph_statx stx;
610 ASSERT_EQ(ceph_statx(cmount, "/.", &stx, 0, AT_SYMLINK_NOFOLLOW), 0);
611 ASSERT_EQ(ceph_statx(cmount, ".", &stx, 0, AT_SYMLINK_NOFOLLOW), 0);
612
613 ceph_shutdown(cmount);
614}
615
616TEST(LibCephFS, DoubleChmod) {
617
618 struct ceph_mount_info *cmount;
619 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
620 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
621 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
622 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
623
624 char test_file[256];
625 sprintf(test_file, "test_perms_%d", getpid());
626
627 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
628 ASSERT_GT(fd, 0);
629
630 // write some stuff
631 const char *bytes = "foobarbaz";
632 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
633
634 ceph_close(cmount, fd);
635
636 // set perms to read but can't write
637 ASSERT_EQ(ceph_chmod(cmount, test_file, 0400), 0);
638
639 fd = ceph_open(cmount, test_file, O_RDWR, 0);
640 ASSERT_EQ(fd, -EACCES);
641
642 fd = ceph_open(cmount, test_file, O_RDONLY, 0);
643 ASSERT_GT(fd, -1);
644
645 char buf[100];
646 int ret = ceph_read(cmount, fd, buf, 100, 0);
647 ASSERT_EQ(ret, (int)strlen(bytes));
648 buf[ret] = '\0';
649 ASSERT_STREQ(buf, bytes);
650
651 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), -EBADF);
652
653 ceph_close(cmount, fd);
654
655 // reset back to writeable
656 ASSERT_EQ(ceph_chmod(cmount, test_file, 0600), 0);
657
658 // ensure perms are correct
659 struct ceph_statx stx;
660 ASSERT_EQ(ceph_statx(cmount, test_file, &stx, CEPH_STATX_MODE, AT_SYMLINK_NOFOLLOW), 0);
661 ASSERT_EQ(stx.stx_mode, 0100600U);
662
663 fd = ceph_open(cmount, test_file, O_RDWR, 0);
664 ASSERT_GT(fd, 0);
665
666 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
667 ceph_close(cmount, fd);
668
669 ceph_shutdown(cmount);
670}
671
672TEST(LibCephFS, Fchmod) {
673 struct ceph_mount_info *cmount;
674 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
675 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
676 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
677 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
678
679 char test_file[256];
680 sprintf(test_file, "test_perms_%d", getpid());
681
682 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
683 ASSERT_GT(fd, 0);
684
685 // write some stuff
686 const char *bytes = "foobarbaz";
687 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
688
689 // set perms to read but can't write
690 ASSERT_EQ(ceph_fchmod(cmount, fd, 0400), 0);
691
692 char buf[100];
693 int ret = ceph_read(cmount, fd, buf, 100, 0);
694 ASSERT_EQ(ret, (int)strlen(bytes));
695 buf[ret] = '\0';
696 ASSERT_STREQ(buf, bytes);
697
698 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
699
700 ceph_close(cmount, fd);
701
702 ASSERT_EQ(ceph_open(cmount, test_file, O_RDWR, 0), -EACCES);
703
704 // reset back to writeable
705 ASSERT_EQ(ceph_chmod(cmount, test_file, 0600), 0);
706
707 fd = ceph_open(cmount, test_file, O_RDWR, 0);
708 ASSERT_GT(fd, 0);
709
710 ASSERT_EQ(ceph_write(cmount, fd, bytes, strlen(bytes), 0), (int)strlen(bytes));
711 ceph_close(cmount, fd);
712
713 ceph_shutdown(cmount);
714}
715
716TEST(LibCephFS, Fchown) {
717 struct ceph_mount_info *cmount;
718 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
719 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
720 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
721 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
722
723 char test_file[256];
724 sprintf(test_file, "test_fchown_%d", getpid());
725
726 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
727 ASSERT_GT(fd, 0);
728
729 // set perms to readable and writeable only by owner
730 ASSERT_EQ(ceph_fchmod(cmount, fd, 0600), 0);
731
732 // change ownership to nobody -- we assume nobody exists and id is always 65534
733 ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "0"), 0);
734 ASSERT_EQ(ceph_fchown(cmount, fd, 65534, 65534), 0);
735 ASSERT_EQ(ceph_conf_set(cmount, "client_permissions", "1"), 0);
736
737 ceph_close(cmount, fd);
738
739 fd = ceph_open(cmount, test_file, O_RDWR, 0);
740 ASSERT_EQ(fd, -EACCES);
741
742 ceph_shutdown(cmount);
743}
744
745#if defined(__linux__) && defined(O_PATH)
746TEST(LibCephFS, FlagO_PATH) {
747 struct ceph_mount_info *cmount;
748
749 ASSERT_EQ(0, ceph_create(&cmount, NULL));
750 ASSERT_EQ(0, ceph_conf_read_file(cmount, NULL));
751 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
752 ASSERT_EQ(0, ceph_mount(cmount, NULL));
753
754 char test_file[PATH_MAX];
755 sprintf(test_file, "test_oflag_%d", getpid());
756
757 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR|O_PATH, 0666);
758 ASSERT_EQ(-ENOENT, fd);
759
760 fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
761 ASSERT_GT(fd, 0);
762 ASSERT_EQ(0, ceph_close(cmount, fd));
763
764 // ok, the file has been created. perform real checks now
765 fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR|O_PATH, 0666);
766 ASSERT_GT(fd, 0);
767
768 char buf[128];
769 ASSERT_EQ(-EBADF, ceph_read(cmount, fd, buf, sizeof(buf), 0));
770 ASSERT_EQ(-EBADF, ceph_write(cmount, fd, buf, sizeof(buf), 0));
771
772 // set perms to readable and writeable only by owner
773 ASSERT_EQ(-EBADF, ceph_fchmod(cmount, fd, 0600));
774
775 // change ownership to nobody -- we assume nobody exists and id is always 65534
776 ASSERT_EQ(-EBADF, ceph_fchown(cmount, fd, 65534, 65534));
777
778 // try to sync
779 ASSERT_EQ(-EBADF, ceph_fsync(cmount, fd, false));
780
781 struct ceph_statx stx;
782 ASSERT_EQ(0, ceph_fstatx(cmount, fd, &stx, 0, 0));
783
784 ASSERT_EQ(0, ceph_close(cmount, fd));
785 ceph_shutdown(cmount);
786}
787#endif /* __linux */
788
789TEST(LibCephFS, Symlinks) {
790 struct ceph_mount_info *cmount;
791 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
792 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
793 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
794 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
795
796 char test_file[256];
797 sprintf(test_file, "test_symlinks_%d", getpid());
798
799 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
800 ASSERT_GT(fd, 0);
801
802 ceph_close(cmount, fd);
803
804 char test_symlink[256];
805 sprintf(test_symlink, "test_symlinks_sym_%d", getpid());
806
807 ASSERT_EQ(ceph_symlink(cmount, test_file, test_symlink), 0);
808
809 // test the O_NOFOLLOW case
810 fd = ceph_open(cmount, test_symlink, O_NOFOLLOW, 0);
811 ASSERT_EQ(fd, -ELOOP);
812
813 // stat the original file
814 struct ceph_statx stx_orig;
815 ASSERT_EQ(ceph_statx(cmount, test_file, &stx_orig, CEPH_STATX_ALL_STATS, 0), 0);
816 // stat the symlink
817 struct ceph_statx stx_symlink_orig;
818 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx_symlink_orig, CEPH_STATX_ALL_STATS, 0), 0);
819 // ensure the statx bufs are equal
820 ASSERT_EQ(memcmp(&stx_orig, &stx_symlink_orig, sizeof(stx_orig)), 0);
821
822 sprintf(test_file, "/test_symlinks_abs_%d", getpid());
823
824 fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
825 ASSERT_GT(fd, 0);
826
827 ceph_close(cmount, fd);
828
829 sprintf(test_symlink, "/test_symlinks_abs_sym_%d", getpid());
830
831 ASSERT_EQ(ceph_symlink(cmount, test_file, test_symlink), 0);
832
833 // stat the original file
834 ASSERT_EQ(ceph_statx(cmount, test_file, &stx_orig, CEPH_STATX_ALL_STATS, 0), 0);
835 // stat the symlink
836 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx_symlink_orig, CEPH_STATX_ALL_STATS, 0), 0);
837 // ensure the statx bufs are equal
838 ASSERT_TRUE(!memcmp(&stx_orig, &stx_symlink_orig, sizeof(stx_orig)));
839
840 // test lstat
841 ASSERT_EQ(ceph_statx(cmount, test_symlink, &stx_orig, CEPH_STATX_ALL_STATS, AT_SYMLINK_NOFOLLOW), 0);
842 ASSERT_TRUE(S_ISLNK(stx_orig.stx_mode));
843
844 ceph_shutdown(cmount);
845}
846
847TEST(LibCephFS, DirSyms) {
848 struct ceph_mount_info *cmount;
849 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
850 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
851 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
852 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
853
854 char test_dir1[256];
855 sprintf(test_dir1, "dir1_symlinks_%d", getpid());
856
857 ASSERT_EQ(ceph_mkdir(cmount, test_dir1, 0700), 0);
858
859 char test_symdir[256];
860 sprintf(test_symdir, "symdir_symlinks_%d", getpid());
861
862 ASSERT_EQ(ceph_symlink(cmount, test_dir1, test_symdir), 0);
863
864 char test_file[256];
865 sprintf(test_file, "/symdir_symlinks_%d/test_symdir_file", getpid());
866 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0600);
867 ASSERT_GT(fd, 0);
868 ceph_close(cmount, fd);
869
870 struct ceph_statx stx;
871 ASSERT_EQ(ceph_statx(cmount, test_file, &stx, 0, AT_SYMLINK_NOFOLLOW), 0);
872
873 // ensure that its a file not a directory we get back
874 ASSERT_TRUE(S_ISREG(stx.stx_mode));
875
876 ceph_shutdown(cmount);
877}
878
879TEST(LibCephFS, LoopSyms) {
880 struct ceph_mount_info *cmount;
881 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
882 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
883 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
884 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
885
886 char test_dir1[256];
887 sprintf(test_dir1, "dir1_loopsym_%d", getpid());
888
889 ASSERT_EQ(ceph_mkdir(cmount, test_dir1, 0700), 0);
890
891 char test_dir2[256];
892 sprintf(test_dir2, "/dir1_loopsym_%d/loop_dir", getpid());
893
894 ASSERT_EQ(ceph_mkdir(cmount, test_dir2, 0700), 0);
895
896 // symlink it itself: /path/to/mysym -> /path/to/mysym
897 char test_symdir[256];
898 sprintf(test_symdir, "/dir1_loopsym_%d/loop_dir/symdir", getpid());
899
900 ASSERT_EQ(ceph_symlink(cmount, test_symdir, test_symdir), 0);
901
902 char test_file[256];
903 sprintf(test_file, "/dir1_loopsym_%d/loop_dir/symdir/test_loopsym_file", getpid());
904 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0600);
905 ASSERT_EQ(fd, -ELOOP);
906
907 // loop: /a -> /b, /b -> /c, /c -> /a
908 char a[256], b[256], c[256];
909 sprintf(a, "/%s/a", test_dir1);
910 sprintf(b, "/%s/b", test_dir1);
911 sprintf(c, "/%s/c", test_dir1);
912 ASSERT_EQ(ceph_symlink(cmount, a, b), 0);
913 ASSERT_EQ(ceph_symlink(cmount, b, c), 0);
914 ASSERT_EQ(ceph_symlink(cmount, c, a), 0);
915 ASSERT_EQ(ceph_open(cmount, a, O_RDWR, 0), -ELOOP);
916
917 ceph_shutdown(cmount);
918}
919
920TEST(LibCephFS, HardlinkNoOriginal) {
921
922 int mypid = getpid();
923
924 struct ceph_mount_info *cmount;
925 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
926 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
927 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
928 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
929
930 char dir[256];
931 sprintf(dir, "/test_rmdirfail%d", mypid);
932 ASSERT_EQ(ceph_mkdir(cmount, dir, 0777), 0);
933
934 ASSERT_EQ(ceph_chdir(cmount, dir), 0);
935
936 int fd = ceph_open(cmount, "f1", O_CREAT, 0644);
937 ASSERT_GT(fd, 0);
938
939 ceph_close(cmount, fd);
940
941 // create hard link
942 ASSERT_EQ(ceph_link(cmount, "f1", "hardl1"), 0);
943
944 // remove file link points to
945 ASSERT_EQ(ceph_unlink(cmount, "f1"), 0);
946
947 ceph_shutdown(cmount);
948
949 // now cleanup
950 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
951 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
952 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
953 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
954 ASSERT_EQ(ceph_chdir(cmount, dir), 0);
955 ASSERT_EQ(ceph_unlink(cmount, "hardl1"), 0);
956 ASSERT_EQ(ceph_rmdir(cmount, dir), 0);
957
958 ceph_shutdown(cmount);
959}
960
961TEST(LibCephFS, BadArgument) {
962 struct ceph_mount_info *cmount;
963 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
964 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
965 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
966 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
967
968 int fd = ceph_open(cmount, "test_file", O_CREAT|O_RDWR, 0666);
969 ASSERT_GT(fd, 0);
970 char buf[100];
971 ASSERT_EQ(ceph_write(cmount, fd, buf, sizeof(buf), 0), (int)sizeof(buf));
972 ASSERT_EQ(ceph_read(cmount, fd, buf, 0, 5), 0);
973 ceph_close(cmount, fd);
974 ASSERT_EQ(ceph_unlink(cmount, "test_file"), 0);
975
976 ceph_shutdown(cmount);
977}
978
979TEST(LibCephFS, BadFileDesc) {
980 struct ceph_mount_info *cmount;
981 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
982 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
983 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
984 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
985
986 ASSERT_EQ(ceph_fchmod(cmount, -1, 0655), -EBADF);
987 ASSERT_EQ(ceph_close(cmount, -1), -EBADF);
988 ASSERT_EQ(ceph_lseek(cmount, -1, 0, SEEK_SET), -EBADF);
989
990 char buf[0];
991 ASSERT_EQ(ceph_read(cmount, -1, buf, 0, 0), -EBADF);
992 ASSERT_EQ(ceph_write(cmount, -1, buf, 0, 0), -EBADF);
993
994 ASSERT_EQ(ceph_ftruncate(cmount, -1, 0), -EBADF);
995 ASSERT_EQ(ceph_fsync(cmount, -1, 0), -EBADF);
996
997 struct ceph_statx stx;
998 ASSERT_EQ(ceph_fstatx(cmount, -1, &stx, 0, 0), -EBADF);
999
1000 struct sockaddr_storage addr;
1001 ASSERT_EQ(ceph_get_file_stripe_address(cmount, -1, 0, &addr, 1), -EBADF);
1002
1003 ASSERT_EQ(ceph_get_file_stripe_unit(cmount, -1), -EBADF);
1004 ASSERT_EQ(ceph_get_file_pool(cmount, -1), -EBADF);
1005 char poolname[80];
1006 ASSERT_EQ(ceph_get_file_pool_name(cmount, -1, poolname, sizeof(poolname)), -EBADF);
1007 ASSERT_EQ(ceph_get_file_replication(cmount, -1), -EBADF);
1008 ASSERT_EQ(ceph_get_file_object_size(cmount, -1), -EBADF);
1009 int stripe_unit, stripe_count, object_size, pg_pool;
1010 ASSERT_EQ(ceph_get_file_layout(cmount, -1, &stripe_unit, &stripe_count, &object_size, &pg_pool), -EBADF);
1011 ASSERT_EQ(ceph_get_file_stripe_count(cmount, -1), -EBADF);
1012
1013 ceph_shutdown(cmount);
1014}
1015
1016TEST(LibCephFS, ReadEmptyFile) {
1017 struct ceph_mount_info *cmount;
1018 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1019 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1020 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1021 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1022
1023 // test the read_sync path in the client for zero files
1024 ASSERT_EQ(ceph_conf_set(cmount, "client_debug_force_sync_read", "true"), 0);
1025
1026 int mypid = getpid();
1027 char testf[256];
1028
1029 sprintf(testf, "test_reademptyfile%d", mypid);
1030 int fd = ceph_open(cmount, testf, O_CREAT|O_TRUNC|O_WRONLY, 0644);
1031 ASSERT_GT(fd, 0);
1032
1033 ceph_close(cmount, fd);
1034
1035 fd = ceph_open(cmount, testf, O_RDONLY, 0);
1036 ASSERT_GT(fd, 0);
1037
1038 char buf[4096];
1039 ASSERT_EQ(ceph_read(cmount, fd, buf, 4096, 0), 0);
1040
1041 ceph_close(cmount, fd);
1042 ceph_shutdown(cmount);
1043}
1044
1045TEST(LibCephFS, PreadvPwritev) {
1046 struct ceph_mount_info *cmount;
1047 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1048 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1049 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1050 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1051
1052 int mypid = getpid();
1053 char testf[256];
1054
1055 sprintf(testf, "test_preadvpwritevfile%d", mypid);
1056 int fd = ceph_open(cmount, testf, O_CREAT|O_RDWR, 0666);
1057 ASSERT_GT(fd, 0);
1058
1059 char out0[] = "hello ";
1060 char out1[] = "world\n";
1061 struct iovec iov_out[2] = {
1062 {out0, sizeof(out0)},
1063 {out1, sizeof(out1)},
1064 };
1065 char in0[sizeof(out0)];
1066 char in1[sizeof(out1)];
1067 struct iovec iov_in[2] = {
1068 {in0, sizeof(in0)},
1069 {in1, sizeof(in1)},
1070 };
1071 ssize_t nwritten = iov_out[0].iov_len + iov_out[1].iov_len;
1072 ssize_t nread = iov_in[0].iov_len + iov_in[1].iov_len;
1073
1074 ASSERT_EQ(ceph_pwritev(cmount, fd, iov_out, 2, 0), nwritten);
1075 ASSERT_EQ(ceph_preadv(cmount, fd, iov_in, 2, 0), nread);
1076 ASSERT_EQ(0, strncmp((const char*)iov_in[0].iov_base, (const char*)iov_out[0].iov_base, iov_out[0].iov_len));
1077 ASSERT_EQ(0, strncmp((const char*)iov_in[1].iov_base, (const char*)iov_out[1].iov_base, iov_out[1].iov_len));
1078
1079 ceph_close(cmount, fd);
1080 ceph_shutdown(cmount);
1081}
1082
1083TEST(LibCephFS, StripeUnitGran) {
1084 struct ceph_mount_info *cmount;
1085 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1086 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1087 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1088 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1089 ASSERT_GT(ceph_get_stripe_unit_granularity(cmount), 0);
1090 ceph_shutdown(cmount);
1091}
1092
1093TEST(LibCephFS, Rename) {
1094 struct ceph_mount_info *cmount;
1095 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1096 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1097 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1098 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1099
1100 int mypid = getpid();
1101 char path_src[256];
1102 char path_dst[256];
1103
1104 /* make a source file */
1105 sprintf(path_src, "test_rename_src%d", mypid);
1106 int fd = ceph_open(cmount, path_src, O_CREAT|O_TRUNC|O_WRONLY, 0777);
1107 ASSERT_GT(fd, 0);
1108 ASSERT_EQ(0, ceph_close(cmount, fd));
1109
1110 /* rename to a new dest path */
1111 sprintf(path_dst, "test_rename_dst%d", mypid);
1112 ASSERT_EQ(0, ceph_rename(cmount, path_src, path_dst));
1113
1114 /* test that dest path exists */
1115 struct ceph_statx stx;
1116 ASSERT_EQ(0, ceph_statx(cmount, path_dst, &stx, 0, 0));
1117
1118 /* test that src path doesn't exist */
1119 ASSERT_EQ(-ENOENT, ceph_statx(cmount, path_src, &stx, 0, AT_SYMLINK_NOFOLLOW));
1120
1121 /* rename with non-existent source path */
1122 ASSERT_EQ(-ENOENT, ceph_rename(cmount, path_src, path_dst));
1123
1124 ASSERT_EQ(0, ceph_unlink(cmount, path_dst));
1125 ceph_shutdown(cmount);
1126}
1127
1128TEST(LibCephFS, UseUnmounted) {
1129 struct ceph_mount_info *cmount;
1130 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1131 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1132 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1133
1134 struct statvfs stvfs;
1135 EXPECT_EQ(-ENOTCONN, ceph_statfs(cmount, "/", &stvfs));
1136 EXPECT_EQ(-ENOTCONN, ceph_get_local_osd(cmount));
1137 EXPECT_EQ(-ENOTCONN, ceph_chdir(cmount, "/"));
1138
1139 struct ceph_dir_result *dirp;
1140 EXPECT_EQ(-ENOTCONN, ceph_opendir(cmount, "/", &dirp));
1141 EXPECT_EQ(-ENOTCONN, ceph_closedir(cmount, dirp));
1142
1143 ceph_readdir(cmount, dirp);
1144 EXPECT_EQ(ENOTCONN, errno);
1145
1146 struct dirent rdent;
1147 EXPECT_EQ(-ENOTCONN, ceph_readdir_r(cmount, dirp, &rdent));
1148
1149 struct ceph_statx stx;
1150 EXPECT_EQ(-ENOTCONN, ceph_readdirplus_r(cmount, dirp, &rdent, &stx, 0, 0, NULL));
1151 EXPECT_EQ(-ENOTCONN, ceph_getdents(cmount, dirp, NULL, 0));
1152 EXPECT_EQ(-ENOTCONN, ceph_getdnames(cmount, dirp, NULL, 0));
1153 EXPECT_EQ(-ENOTCONN, ceph_telldir(cmount, dirp));
1154 EXPECT_EQ(-ENOTCONN, ceph_link(cmount, "/", "/link"));
1155 EXPECT_EQ(-ENOTCONN, ceph_unlink(cmount, "/path"));
1156 EXPECT_EQ(-ENOTCONN, ceph_rename(cmount, "/path", "/path"));
1157 EXPECT_EQ(-ENOTCONN, ceph_mkdir(cmount, "/", 0655));
1158 EXPECT_EQ(-ENOTCONN, ceph_mkdirs(cmount, "/", 0655));
1159 EXPECT_EQ(-ENOTCONN, ceph_rmdir(cmount, "/path"));
1160 EXPECT_EQ(-ENOTCONN, ceph_readlink(cmount, "/path", NULL, 0));
1161 EXPECT_EQ(-ENOTCONN, ceph_symlink(cmount, "/path", "/path"));
1162 EXPECT_EQ(-ENOTCONN, ceph_statx(cmount, "/path", &stx, 0, 0));
1163 EXPECT_EQ(-ENOTCONN, ceph_setattrx(cmount, "/path", &stx, 0, 0));
1164 EXPECT_EQ(-ENOTCONN, ceph_getxattr(cmount, "/path", "name", NULL, 0));
1165 EXPECT_EQ(-ENOTCONN, ceph_lgetxattr(cmount, "/path", "name", NULL, 0));
1166 EXPECT_EQ(-ENOTCONN, ceph_listxattr(cmount, "/path", NULL, 0));
1167 EXPECT_EQ(-ENOTCONN, ceph_llistxattr(cmount, "/path", NULL, 0));
1168 EXPECT_EQ(-ENOTCONN, ceph_removexattr(cmount, "/path", "name"));
1169 EXPECT_EQ(-ENOTCONN, ceph_lremovexattr(cmount, "/path", "name"));
1170 EXPECT_EQ(-ENOTCONN, ceph_setxattr(cmount, "/path", "name", NULL, 0, 0));
1171 EXPECT_EQ(-ENOTCONN, ceph_lsetxattr(cmount, "/path", "name", NULL, 0, 0));
1172 EXPECT_EQ(-ENOTCONN, ceph_fsetattrx(cmount, 0, &stx, 0));
1173 EXPECT_EQ(-ENOTCONN, ceph_chmod(cmount, "/path", 0));
1174 EXPECT_EQ(-ENOTCONN, ceph_fchmod(cmount, 0, 0));
1175 EXPECT_EQ(-ENOTCONN, ceph_chown(cmount, "/path", 0, 0));
1176 EXPECT_EQ(-ENOTCONN, ceph_lchown(cmount, "/path", 0, 0));
1177 EXPECT_EQ(-ENOTCONN, ceph_fchown(cmount, 0, 0, 0));
1178
1179 struct utimbuf utb;
1180 EXPECT_EQ(-ENOTCONN, ceph_utime(cmount, "/path", &utb));
1181 EXPECT_EQ(-ENOTCONN, ceph_truncate(cmount, "/path", 0));
1182 EXPECT_EQ(-ENOTCONN, ceph_mknod(cmount, "/path", 0, 0));
1183 EXPECT_EQ(-ENOTCONN, ceph_open(cmount, "/path", 0, 0));
1184 EXPECT_EQ(-ENOTCONN, ceph_open_layout(cmount, "/path", 0, 0, 0, 0, 0, "pool"));
1185 EXPECT_EQ(-ENOTCONN, ceph_close(cmount, 0));
1186 EXPECT_EQ(-ENOTCONN, ceph_lseek(cmount, 0, 0, SEEK_SET));
1187 EXPECT_EQ(-ENOTCONN, ceph_read(cmount, 0, NULL, 0, 0));
1188 EXPECT_EQ(-ENOTCONN, ceph_write(cmount, 0, NULL, 0, 0));
1189 EXPECT_EQ(-ENOTCONN, ceph_ftruncate(cmount, 0, 0));
1190 EXPECT_EQ(-ENOTCONN, ceph_fsync(cmount, 0, 0));
1191 EXPECT_EQ(-ENOTCONN, ceph_fstatx(cmount, 0, &stx, 0, 0));
1192 EXPECT_EQ(-ENOTCONN, ceph_sync_fs(cmount));
1193 EXPECT_EQ(-ENOTCONN, ceph_get_file_stripe_unit(cmount, 0));
1194 EXPECT_EQ(-ENOTCONN, ceph_get_file_stripe_count(cmount, 0));
1195 EXPECT_EQ(-ENOTCONN, ceph_get_file_layout(cmount, 0, NULL, NULL ,NULL ,NULL));
1196 EXPECT_EQ(-ENOTCONN, ceph_get_file_object_size(cmount, 0));
1197 EXPECT_EQ(-ENOTCONN, ceph_get_file_pool(cmount, 0));
1198 EXPECT_EQ(-ENOTCONN, ceph_get_file_pool_name(cmount, 0, NULL, 0));
1199 EXPECT_EQ(-ENOTCONN, ceph_get_file_replication(cmount, 0));
1200 EXPECT_EQ(-ENOTCONN, ceph_get_path_replication(cmount, "/path"));
1201 EXPECT_EQ(-ENOTCONN, ceph_get_path_layout(cmount, "/path", NULL, NULL, NULL, NULL));
1202 EXPECT_EQ(-ENOTCONN, ceph_get_path_object_size(cmount, "/path"));
1203 EXPECT_EQ(-ENOTCONN, ceph_get_path_stripe_count(cmount, "/path"));
1204 EXPECT_EQ(-ENOTCONN, ceph_get_path_stripe_unit(cmount, "/path"));
1205 EXPECT_EQ(-ENOTCONN, ceph_get_path_pool(cmount, "/path"));
1206 EXPECT_EQ(-ENOTCONN, ceph_get_path_pool_name(cmount, "/path", NULL, 0));
1207 EXPECT_EQ(-ENOTCONN, ceph_get_pool_name(cmount, 0, NULL, 0));
1208 EXPECT_EQ(-ENOTCONN, ceph_get_file_stripe_address(cmount, 0, 0, NULL, 0));
1209 EXPECT_EQ(-ENOTCONN, ceph_localize_reads(cmount, 0));
1210 EXPECT_EQ(-ENOTCONN, ceph_debug_get_fd_caps(cmount, 0));
1211 EXPECT_EQ(-ENOTCONN, ceph_debug_get_file_caps(cmount, "/path"));
1212 EXPECT_EQ(-ENOTCONN, ceph_get_stripe_unit_granularity(cmount));
1213 EXPECT_EQ(-ENOTCONN, ceph_get_pool_id(cmount, "data"));
1214 EXPECT_EQ(-ENOTCONN, ceph_get_pool_replication(cmount, 1));
1215
1216 ceph_release(cmount);
1217}
1218
1219TEST(LibCephFS, GetPoolId) {
1220 struct ceph_mount_info *cmount;
1221 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1222 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1223 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1224 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1225
1226 char name[80];
1227 memset(name, 0, sizeof(name));
1228 ASSERT_LE(0, ceph_get_path_pool_name(cmount, "/", name, sizeof(name)));
1229 ASSERT_GE(ceph_get_pool_id(cmount, name), 0);
1230 ASSERT_EQ(ceph_get_pool_id(cmount, "weflkjwelfjwlkejf"), -ENOENT);
1231
1232 ceph_shutdown(cmount);
1233}
1234
1235TEST(LibCephFS, GetPoolReplication) {
1236 struct ceph_mount_info *cmount;
1237 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1238 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1239 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1240 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1241
1242 /* negative pools */
1243 ASSERT_EQ(ceph_get_pool_replication(cmount, -10), -ENOENT);
1244
1245 /* valid pool */
1246 int pool_id;
1247 int stripe_unit, stripe_count, object_size;
1248 ASSERT_EQ(0, ceph_get_path_layout(cmount, "/", &stripe_unit, &stripe_count,
1249 &object_size, &pool_id));
1250 ASSERT_GE(pool_id, 0);
1251 ASSERT_GT(ceph_get_pool_replication(cmount, pool_id), 0);
1252
1253 ceph_shutdown(cmount);
1254}
1255
1256TEST(LibCephFS, GetExtentOsds) {
1257 struct ceph_mount_info *cmount;
1258 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1259
1260 EXPECT_EQ(-ENOTCONN, ceph_get_file_extent_osds(cmount, 0, 0, NULL, NULL, 0));
1261
1262 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1263 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1264 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1265
1266 int stripe_unit = (1<<18);
1267
1268 /* make a file! */
1269 char test_file[256];
1270 sprintf(test_file, "test_extent_osds_%d", getpid());
1271 int fd = ceph_open_layout(cmount, test_file, O_CREAT|O_RDWR, 0666,
1272 stripe_unit, 2, stripe_unit*2, NULL);
1273 ASSERT_GT(fd, 0);
1274
1275 /* get back how many osds > 0 */
1276 int ret = ceph_get_file_extent_osds(cmount, fd, 0, NULL, NULL, 0);
1277 EXPECT_GT(ret, 0);
1278
1279 int64_t len;
1280 int osds[ret];
1281
1282 /* full stripe extent */
1283 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 0, &len, osds, ret));
1284 EXPECT_EQ(len, (int64_t)stripe_unit);
1285
1286 /* half stripe extent */
1287 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, stripe_unit/2, &len, osds, ret));
1288 EXPECT_EQ(len, (int64_t)stripe_unit/2);
1289
1290 /* 1.5 stripe unit offset -1 byte */
1291 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 3*stripe_unit/2-1, &len, osds, ret));
1292 EXPECT_EQ(len, (int64_t)stripe_unit/2+1);
1293
1294 /* 1.5 stripe unit offset +1 byte */
1295 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 3*stripe_unit/2+1, &len, osds, ret));
1296 EXPECT_EQ(len, (int64_t)stripe_unit/2-1);
1297
1298 /* only when more than 1 osd */
1299 if (ret > 1) {
1300 EXPECT_EQ(-ERANGE, ceph_get_file_extent_osds(cmount, fd, 0, NULL, osds, 1));
1301 }
1302
1303 ceph_close(cmount, fd);
1304
1305 ceph_shutdown(cmount);
1306}
1307
1308TEST(LibCephFS, GetOsdCrushLocation) {
1309 struct ceph_mount_info *cmount;
1310 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1311
1312 EXPECT_EQ(-ENOTCONN, ceph_get_osd_crush_location(cmount, 0, NULL, 0));
1313
1314 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1315 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1316 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1317
1318 ASSERT_EQ(ceph_get_osd_crush_location(cmount, 0, NULL, 1), -EINVAL);
1319
1320 char path[256];
1321 ASSERT_EQ(ceph_get_osd_crush_location(cmount, 9999999, path, 0), -ENOENT);
1322 ASSERT_EQ(ceph_get_osd_crush_location(cmount, -1, path, 0), -EINVAL);
1323
1324 char test_file[256];
1325 sprintf(test_file, "test_osds_loc_%d", getpid());
1326 int fd = ceph_open(cmount, test_file, O_CREAT|O_RDWR, 0666);
1327 ASSERT_GT(fd, 0);
1328
1329 /* get back how many osds > 0 */
1330 int ret = ceph_get_file_extent_osds(cmount, fd, 0, NULL, NULL, 0);
1331 EXPECT_GT(ret, 0);
1332
1333 /* full stripe extent */
1334 int osds[ret];
1335 EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 0, NULL, osds, ret));
1336
1337 ASSERT_GT(ceph_get_osd_crush_location(cmount, 0, path, 0), 0);
1338 ASSERT_EQ(ceph_get_osd_crush_location(cmount, 0, path, 1), -ERANGE);
1339
1340 for (int i = 0; i < ret; i++) {
1341 int len = ceph_get_osd_crush_location(cmount, osds[i], path, sizeof(path));
1342 ASSERT_GT(len, 0);
1343 int pos = 0;
1344 while (pos < len) {
1345 std::string type(path + pos);
1346 ASSERT_GT((int)type.size(), 0);
1347 pos += type.size() + 1;
1348
1349 std::string name(path + pos);
1350 ASSERT_GT((int)name.size(), 0);
1351 pos += name.size() + 1;
1352 }
1353 }
1354
1355 ceph_close(cmount, fd);
1356 ceph_shutdown(cmount);
1357}
1358
1359TEST(LibCephFS, GetOsdAddr) {
1360 struct ceph_mount_info *cmount;
1361 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1362
1363 EXPECT_EQ(-ENOTCONN, ceph_get_osd_addr(cmount, 0, NULL));
1364
1365 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1366 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1367 ASSERT_EQ(ceph_mount(cmount, NULL), 0);
1368
1369 ASSERT_EQ(-EINVAL, ceph_get_osd_addr(cmount, 0, NULL));
1370
1371 struct sockaddr_storage addr;
1372 ASSERT_EQ(-ENOENT, ceph_get_osd_addr(cmount, -1, &addr));
1373 ASSERT_EQ(-ENOENT, ceph_get_osd_addr(cmount, 9999999, &addr));
1374
1375 ASSERT_EQ(0, ceph_get_osd_addr(cmount, 0, &addr));
1376
1377 ceph_shutdown(cmount);
1378}
1379
1380TEST(LibCephFS, OpenNoClose) {
1381 struct ceph_mount_info *cmount;
1382 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1383 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1384 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1385 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1386
1387 pid_t mypid = getpid();
1388 char str_buf[256];
1389 sprintf(str_buf, "open_no_close_dir%d", mypid);
1390 ASSERT_EQ(0, ceph_mkdirs(cmount, str_buf, 0777));
1391
1392 struct ceph_dir_result *ls_dir = NULL;
1393 ASSERT_EQ(ceph_opendir(cmount, str_buf, &ls_dir), 0);
1394
1395 sprintf(str_buf, "open_no_close_file%d", mypid);
1396 int fd = ceph_open(cmount, str_buf, O_RDONLY|O_CREAT, 0666);
1397 ASSERT_LT(0, fd);
1398
1399 // shutdown should force close opened file/dir
1400 ceph_shutdown(cmount);
1401}
1402
1403TEST(LibCephFS, Nlink) {
1404 struct ceph_mount_info *cmount;
1405 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1406 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1407 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1408 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1409
1410 Inode *root, *dir, *file;
1411
1412 ASSERT_EQ(ceph_ll_lookup_root(cmount, &root), 0);
1413
1414 char dirname[32], filename[32], linkname[32];
1415 sprintf(dirname, "nlinkdir%x", getpid());
1416 sprintf(filename, "nlinkorig%x", getpid());
1417 sprintf(linkname, "nlinklink%x", getpid());
1418
1419 struct ceph_statx stx;
1420 Fh *fh;
1421 UserPerm *perms = ceph_mount_perms(cmount);
1422
1423 ASSERT_EQ(ceph_ll_mkdir(cmount, root, dirname, 0755, &dir, &stx, 0, 0, perms), 0);
1424 ASSERT_EQ(ceph_ll_create(cmount, dir, filename, 0666, O_RDWR|O_CREAT|O_EXCL,
1425 &file, &fh, &stx, CEPH_STATX_NLINK, 0, perms), 0);
1426 ASSERT_EQ(ceph_ll_close(cmount, fh), 0);
1427 ASSERT_EQ(stx.stx_nlink, (nlink_t)1);
1428
1429 ASSERT_EQ(ceph_ll_link(cmount, file, dir, linkname, perms), 0);
1430 ASSERT_EQ(ceph_ll_getattr(cmount, file, &stx, CEPH_STATX_NLINK, 0, perms), 0);
1431 ASSERT_EQ(stx.stx_nlink, (nlink_t)2);
1432
1433 ASSERT_EQ(ceph_ll_unlink(cmount, dir, linkname, perms), 0);
1434 ASSERT_EQ(ceph_ll_lookup(cmount, dir, filename, &file, &stx,
1435 CEPH_STATX_NLINK, 0, perms), 0);
1436 ASSERT_EQ(stx.stx_nlink, (nlink_t)1);
1437
1438 ceph_shutdown(cmount);
1439}
1440
1441TEST(LibCephFS, SlashDotDot) {
1442 struct ceph_mount_info *cmount;
1443 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1444 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1445 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1446 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1447
1448 struct ceph_statx stx;
1449 ASSERT_EQ(ceph_statx(cmount, "/.", &stx, CEPH_STATX_INO, 0), 0);
1450
1451 ino_t ino = stx.stx_ino;
1452 ASSERT_EQ(ceph_statx(cmount, "/..", &stx, CEPH_STATX_INO, 0), 0);
1453
1454 /* At root, "." and ".." should be the same inode */
1455 ASSERT_EQ(ino, stx.stx_ino);
1456
1457 /* Test accessing the parent of an unlinked directory */
1458 char dir1[32], dir2[32];
1459 sprintf(dir1, "/sldotdot%x", getpid());
1460 sprintf(dir2, "%s/sub%x", dir1, getpid());
1461
1462 ASSERT_EQ(ceph_mkdir(cmount, dir1, 0755), 0);
1463 ASSERT_EQ(ceph_mkdir(cmount, dir2, 0755), 0);
1464
1465 ASSERT_EQ(ceph_chdir(cmount, dir2), 0);
1466
1467 /* Test behavior when unlinking cwd */
1468 struct ceph_dir_result *rdir;
1469 ASSERT_EQ(ceph_opendir(cmount, ".", &rdir), 0);
1470 ASSERT_EQ(ceph_rmdir(cmount, dir2), 0);
1471
1472 /* get "." entry */
1473 struct dirent *result = ceph_readdir(cmount, rdir);
1474 ino = result->d_ino;
1475
1476 /* get ".." entry */
1477 result = ceph_readdir(cmount, rdir);
1478 ASSERT_EQ(ino, result->d_ino);
1479 ceph_closedir(cmount, rdir);
1480
1481 /* Make sure it works same way when mounting subtree */
1482 ASSERT_EQ(ceph_unmount(cmount), 0);
1483 ASSERT_EQ(ceph_mount(cmount, dir1), 0);
1484 ASSERT_EQ(ceph_statx(cmount, "/..", &stx, CEPH_STATX_INO, 0), 0);
1485
1486 /* Test readdir behavior */
1487 ASSERT_EQ(ceph_opendir(cmount, "/", &rdir), 0);
1488 result = ceph_readdir(cmount, rdir);
1489 ASSERT_TRUE(result != NULL);
1490 ASSERT_STREQ(result->d_name, ".");
1491 ino = result->d_ino;
1492 result = ceph_readdir(cmount, rdir);
1493 ASSERT_TRUE(result != NULL);
1494 ASSERT_STREQ(result->d_name, "..");
1495 ASSERT_EQ(ino, result->d_ino);
1496
1497 ceph_shutdown(cmount);
1498}
1499
1500static inline bool
1501timespec_eq(timespec const& lhs, timespec const& rhs)
1502{
1503 return lhs.tv_sec == rhs.tv_sec && lhs.tv_nsec == rhs.tv_nsec;
1504}
1505
1506TEST(LibCephFS, Btime) {
1507 struct ceph_mount_info *cmount;
1508 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1509 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1510 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1511 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1512
1513 char filename[32];
1514 sprintf(filename, "/getattrx%x", getpid());
1515
1516 ceph_unlink(cmount, filename);
1517 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1518 ASSERT_LT(0, fd);
1519
1520 /* make sure fstatx works */
1521 struct ceph_statx stx;
1522
1523 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_CTIME|CEPH_STATX_BTIME, 0), 0);
1524 ASSERT_TRUE(stx.stx_mask & (CEPH_STATX_CTIME|CEPH_STATX_BTIME));
1525 ASSERT_TRUE(timespec_eq(stx.stx_ctime, stx.stx_btime));
1526 ceph_close(cmount, fd);
1527
1528 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_CTIME|CEPH_STATX_BTIME, 0), 0);
1529 ASSERT_TRUE(timespec_eq(stx.stx_ctime, stx.stx_btime));
1530 ASSERT_TRUE(stx.stx_mask & (CEPH_STATX_CTIME|CEPH_STATX_BTIME));
1531
1532 struct timespec old_btime = stx.stx_btime;
1533
1534 /* Now sleep, do a chmod and verify that the ctime changed, but btime didn't */
1535 sleep(1);
1536 ASSERT_EQ(ceph_chmod(cmount, filename, 0644), 0);
1537 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_CTIME|CEPH_STATX_BTIME, 0), 0);
1538 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_BTIME);
1539 ASSERT_TRUE(timespec_eq(stx.stx_btime, old_btime));
1540 ASSERT_FALSE(timespec_eq(stx.stx_ctime, stx.stx_btime));
1541
1542 ceph_shutdown(cmount);
1543}
1544
1545TEST(LibCephFS, SetBtime) {
1546 struct ceph_mount_info *cmount;
1547 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1548 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1549 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1550 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1551
1552 char filename[32];
1553 sprintf(filename, "/setbtime%x", getpid());
1554
1555 ceph_unlink(cmount, filename);
1556 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1557 ASSERT_LT(0, fd);
1558 ceph_close(cmount, fd);
1559
1560 struct ceph_statx stx;
1561 struct timespec old_btime = { 1, 2 };
1562
1563 stx.stx_btime = old_btime;
1564
1565 ASSERT_EQ(ceph_setattrx(cmount, filename, &stx, CEPH_SETATTR_BTIME, 0), 0);
1566
1567 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_BTIME, 0), 0);
1568 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_BTIME);
1569 ASSERT_TRUE(timespec_eq(stx.stx_btime, old_btime));
1570
1571 ceph_shutdown(cmount);
1572}
1573
1574TEST(LibCephFS, LazyStatx) {
1575 struct ceph_mount_info *cmount1, *cmount2;
1576 ASSERT_EQ(ceph_create(&cmount1, NULL), 0);
1577 ASSERT_EQ(ceph_create(&cmount2, NULL), 0);
1578 ASSERT_EQ(ceph_conf_read_file(cmount1, NULL), 0);
1579 ASSERT_EQ(ceph_conf_read_file(cmount2, NULL), 0);
1580 ASSERT_EQ(0, ceph_conf_parse_env(cmount1, NULL));
1581 ASSERT_EQ(0, ceph_conf_parse_env(cmount2, NULL));
1582 ASSERT_EQ(ceph_mount(cmount1, "/"), 0);
1583 ASSERT_EQ(ceph_mount(cmount2, "/"), 0);
1584
1585 char filename[32];
1586 sprintf(filename, "lazystatx%x", getpid());
1587
1588 Inode *root1, *file1, *root2, *file2;
1589 struct ceph_statx stx;
1590 Fh *fh;
1591 UserPerm *perms1 = ceph_mount_perms(cmount1);
1592 UserPerm *perms2 = ceph_mount_perms(cmount2);
1593
1594 ASSERT_EQ(ceph_ll_lookup_root(cmount1, &root1), 0);
1595 ceph_ll_unlink(cmount1, root1, filename, perms1);
1596 ASSERT_EQ(ceph_ll_create(cmount1, root1, filename, 0666, O_RDWR|O_CREAT|O_EXCL,
1597 &file1, &fh, &stx, 0, 0, perms1), 0);
1598 ASSERT_EQ(ceph_ll_close(cmount1, fh), 0);
1599
1600 ASSERT_EQ(ceph_ll_lookup_root(cmount2, &root2), 0);
1601
1602 ASSERT_EQ(ceph_ll_lookup(cmount2, root2, filename, &file2, &stx, CEPH_STATX_CTIME, 0, perms2), 0);
1603
1604 struct timespec old_ctime = stx.stx_ctime;
1605
1606 /*
1607 * Now sleep, do a chmod on the first client and the see whether we get a
1608 * different ctime with a statx that uses AT_NO_ATTR_SYNC
1609 */
1610 sleep(1);
1611 stx.stx_mode = 0644;
1612 ASSERT_EQ(ceph_ll_setattr(cmount1, file1, &stx, CEPH_SETATTR_MODE, perms1), 0);
1613
1614 ASSERT_EQ(ceph_ll_getattr(cmount2, file2, &stx, CEPH_STATX_CTIME, AT_NO_ATTR_SYNC, perms2), 0);
1615 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_CTIME);
1616 ASSERT_TRUE(stx.stx_ctime.tv_sec == old_ctime.tv_sec &&
1617 stx.stx_ctime.tv_nsec == old_ctime.tv_nsec);
1618
1619 ceph_shutdown(cmount1);
1620 ceph_shutdown(cmount2);
1621}
1622
1623TEST(LibCephFS, ChangeAttr) {
1624 struct ceph_mount_info *cmount;
1625 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1626 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1627 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1628 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1629
1630 char filename[32];
1631 sprintf(filename, "/changeattr%x", getpid());
1632
1633 ceph_unlink(cmount, filename);
1634 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1635 ASSERT_LT(0, fd);
1636
1637 struct ceph_statx stx;
1638 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_VERSION, 0), 0);
1639 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1640
1641 uint64_t old_change_attr = stx.stx_version;
1642
1643 /* do chmod, and check whether change_attr changed */
1644 ASSERT_EQ(ceph_chmod(cmount, filename, 0644), 0);
1645 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_VERSION, 0), 0);
1646 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1647 ASSERT_NE(stx.stx_version, old_change_attr);
1648 old_change_attr = stx.stx_version;
1649
1650 /* now do a write and see if it changed again */
1651 ASSERT_EQ(3, ceph_write(cmount, fd, "foo", 3, 0));
1652 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_VERSION, 0), 0);
1653 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1654 ASSERT_NE(stx.stx_version, old_change_attr);
1655 old_change_attr = stx.stx_version;
1656
1657 /* Now truncate and check again */
1658 ASSERT_EQ(0, ceph_ftruncate(cmount, fd, 0));
1659 ASSERT_EQ(ceph_statx(cmount, filename, &stx, CEPH_STATX_VERSION, 0), 0);
1660 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1661 ASSERT_NE(stx.stx_version, old_change_attr);
1662
1663 ceph_close(cmount, fd);
1664 ceph_shutdown(cmount);
1665}
1666
1667TEST(LibCephFS, DirChangeAttr) {
1668 struct ceph_mount_info *cmount;
1669 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1670 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1671 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1672 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1673
1674 char dirname[32], filename[32];
1675 sprintf(dirname, "/dirchange%x", getpid());
1676 sprintf(filename, "%s/foo", dirname);
1677
1678 ASSERT_EQ(ceph_mkdir(cmount, dirname, 0755), 0);
1679
1680 struct ceph_statx stx;
1681 ASSERT_EQ(ceph_statx(cmount, dirname, &stx, CEPH_STATX_VERSION, 0), 0);
1682 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1683
1684 uint64_t old_change_attr = stx.stx_version;
1685
1686 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1687 ASSERT_LT(0, fd);
1688 ceph_close(cmount, fd);
1689
1690 ASSERT_EQ(ceph_statx(cmount, dirname, &stx, CEPH_STATX_VERSION, 0), 0);
1691 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1692 ASSERT_NE(stx.stx_version, old_change_attr);
1693
1694 old_change_attr = stx.stx_version;
1695
1696 ASSERT_EQ(ceph_unlink(cmount, filename), 0);
1697 ASSERT_EQ(ceph_statx(cmount, dirname, &stx, CEPH_STATX_VERSION, 0), 0);
1698 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_VERSION);
1699 ASSERT_NE(stx.stx_version, old_change_attr);
1700
1701 ceph_shutdown(cmount);
1702}
1703
1704TEST(LibCephFS, SetSize) {
1705 struct ceph_mount_info *cmount;
1706 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1707 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1708 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1709 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1710
1711 char filename[32];
1712 sprintf(filename, "/setsize%x", getpid());
1713
1714 ceph_unlink(cmount, filename);
1715 int fd = ceph_open(cmount, filename, O_RDWR|O_CREAT|O_EXCL, 0666);
1716 ASSERT_LT(0, fd);
1717
1718 struct ceph_statx stx;
1719 uint64_t size = 8388608;
1720 stx.stx_size = size;
1721 ASSERT_EQ(ceph_fsetattrx(cmount, fd, &stx, CEPH_SETATTR_SIZE), 0);
1722 ASSERT_EQ(ceph_fstatx(cmount, fd, &stx, CEPH_STATX_SIZE, 0), 0);
1723 ASSERT_EQ(stx.stx_size, size);
1724
1725 ceph_close(cmount, fd);
1726 ceph_shutdown(cmount);
1727}
1728
1729TEST(LibCephFS, ClearSetuid) {
1730 struct ceph_mount_info *cmount;
1731 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1732 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1733 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1734 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1735
1736 Inode *root;
1737 ASSERT_EQ(ceph_ll_lookup_root(cmount, &root), 0);
1738
1739 char filename[32];
1740 sprintf(filename, "clearsetuid%x", getpid());
1741
1742 Fh *fh;
1743 Inode *in;
1744 struct ceph_statx stx;
181888fb
FG
1745 const mode_t after_mode = S_IRWXU;
1746 const mode_t before_mode = S_IRWXU | S_ISUID | S_ISGID;
7c673cae
FG
1747 const unsigned want = CEPH_STATX_UID|CEPH_STATX_GID|CEPH_STATX_MODE;
1748 UserPerm *usercred = ceph_mount_perms(cmount);
1749
1750 ceph_ll_unlink(cmount, root, filename, usercred);
1751 ASSERT_EQ(ceph_ll_create(cmount, root, filename, before_mode,
1752 O_RDWR|O_CREAT|O_EXCL, &in, &fh, &stx, want, 0,
1753 usercred), 0);
1754
1755 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, before_mode);
1756
1757 // write
1758 ASSERT_EQ(ceph_ll_write(cmount, fh, 0, 3, "foo"), 3);
1759 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1760 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1761 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, after_mode);
1762
1763 // reset mode
1764 stx.stx_mode = before_mode;
1765 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_STATX_MODE, usercred), 0);
1766 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1767 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1768 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, before_mode);
1769
1770 // truncate
1771 stx.stx_size = 1;
1772 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_SETATTR_SIZE, usercred), 0);
1773 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1774 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1775 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, after_mode);
1776
1777 // reset mode
1778 stx.stx_mode = before_mode;
1779 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_STATX_MODE, usercred), 0);
1780 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1781 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1782 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, before_mode);
1783
1784 // chown -- for this we need to be "root"
1785 UserPerm *rootcred = ceph_userperm_new(0, 0, 0, NULL);
1786 ASSERT_TRUE(rootcred);
1787 stx.stx_uid++;
1788 stx.stx_gid++;
1789 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_SETATTR_UID|CEPH_SETATTR_GID, rootcred), 0);
1790 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, usercred), 0);
1791 ASSERT_TRUE(stx.stx_mask & CEPH_STATX_MODE);
1792 ASSERT_EQ(stx.stx_mode & (mode_t)ALLPERMS, after_mode);
1793
181888fb
FG
1794 /* test chown with supplementary groups, and chown with/without exe bit */
1795 uid_t u = 65534;
1796 gid_t g = 65534;
1797 gid_t gids[] = {65533,65532};
1798 UserPerm *altcred = ceph_userperm_new(u, g, sizeof gids / sizeof gids[0], gids);
1799 stx.stx_uid = u;
1800 stx.stx_gid = g;
1801 mode_t m = S_ISGID|S_ISUID|S_IRUSR|S_IWUSR;
1802 stx.stx_mode = m;
1803 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_STATX_MODE|CEPH_SETATTR_UID|CEPH_SETATTR_GID, rootcred), 0);
1804 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, altcred), 0);
1805 ASSERT_EQ(stx.stx_mode&(mode_t)ALLPERMS, m);
1806 /* not dropped without exe bit */
1807 stx.stx_gid = gids[0];
1808 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_SETATTR_GID, altcred), 0);
1809 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, altcred), 0);
1810 ASSERT_EQ(stx.stx_mode&(mode_t)ALLPERMS, m);
1811 /* now check dropped with exe bit */
1812 m = S_ISGID|S_ISUID|S_IRWXU;
1813 stx.stx_mode = m;
1814 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_STATX_MODE, altcred), 0);
1815 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, altcred), 0);
1816 ASSERT_EQ(stx.stx_mode&(mode_t)ALLPERMS, m);
1817 stx.stx_gid = gids[1];
1818 ASSERT_EQ(ceph_ll_setattr(cmount, in, &stx, CEPH_SETATTR_GID, altcred), 0);
1819 ASSERT_EQ(ceph_ll_getattr(cmount, in, &stx, CEPH_STATX_MODE, 0, altcred), 0);
1820 ASSERT_EQ(stx.stx_mode&(mode_t)ALLPERMS, m&(S_IRWXU|S_IRWXG|S_IRWXO));
1821 ceph_userperm_destroy(altcred);
1822
7c673cae
FG
1823 ASSERT_EQ(ceph_ll_close(cmount, fh), 0);
1824 ceph_shutdown(cmount);
1825}
1826
1827TEST(LibCephFS, OperationsOnRoot)
1828{
1829 struct ceph_mount_info *cmount;
1830 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1831 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1832 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1833 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1834
1835 char dirname[32];
1836 sprintf(dirname, "/somedir%x", getpid());
1837
1838 ASSERT_EQ(ceph_mkdir(cmount, dirname, 0755), 0);
1839
1840 ASSERT_EQ(ceph_rmdir(cmount, "/"), -EBUSY);
1841
1842 ASSERT_EQ(ceph_link(cmount, "/", "/"), -EEXIST);
1843 ASSERT_EQ(ceph_link(cmount, dirname, "/"), -EEXIST);
1844 ASSERT_EQ(ceph_link(cmount, "nonExisitingDir", "/"), -ENOENT);
1845
1846 ASSERT_EQ(ceph_unlink(cmount, "/"), -EISDIR);
1847
1848 ASSERT_EQ(ceph_rename(cmount, "/", "/"), -EBUSY);
1849 ASSERT_EQ(ceph_rename(cmount, dirname, "/"), -EBUSY);
1850 ASSERT_EQ(ceph_rename(cmount, "nonExistingDir", "/"), -EBUSY);
1851 ASSERT_EQ(ceph_rename(cmount, "/", dirname), -EBUSY);
1852 ASSERT_EQ(ceph_rename(cmount, "/", "nonExistingDir"), -EBUSY);
1853
1854 ASSERT_EQ(ceph_mkdir(cmount, "/", 0777), -EEXIST);
1855
1856 ASSERT_EQ(ceph_mknod(cmount, "/", 0, 0), -EEXIST);
1857
1858 ASSERT_EQ(ceph_symlink(cmount, "/", "/"), -EEXIST);
1859 ASSERT_EQ(ceph_symlink(cmount, dirname, "/"), -EEXIST);
1860 ASSERT_EQ(ceph_symlink(cmount, "nonExistingDir", "/"), -EEXIST);
1861
1862 ceph_shutdown(cmount);
1863}
b32b8144
FG
1864
1865static void shutdown_racer_func()
1866{
1867 const int niter = 32;
1868 struct ceph_mount_info *cmount;
1869 int i;
1870
1871 for (i = 0; i < niter; ++i) {
1872 ASSERT_EQ(ceph_create(&cmount, NULL), 0);
1873 ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
1874 ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
1875 ASSERT_EQ(ceph_mount(cmount, "/"), 0);
1876 ceph_shutdown(cmount);
1877 }
1878}
1879
1880// See tracker #20988
1881TEST(LibCephFS, ShutdownRace)
1882{
1883 const int nthreads = 128;
1884 std::thread threads[nthreads];
1885
1886 // Need a bunch of fd's for this test
1887 struct rlimit rold, rnew;
1888 ASSERT_EQ(getrlimit(RLIMIT_NOFILE, &rold), 0);
1889 rnew = rold;
1890 rnew.rlim_cur = rnew.rlim_max;
1891 ASSERT_EQ(setrlimit(RLIMIT_NOFILE, &rnew), 0);
1892
1893 for (int i = 0; i < nthreads; ++i)
1894 threads[i] = std::thread(shutdown_racer_func);
1895
1896 for (int i = 0; i < nthreads; ++i)
1897 threads[i].join();
1898 ASSERT_EQ(setrlimit(RLIMIT_NOFILE, &rold), 0);
1899}