]>
git.proxmox.com Git - ceph.git/blob - ceph/src/test/libcephfs/deleg.cc
52ddfe8a3ae42c1b934de7ed77625e466ac6a074
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Tests for Ceph delegation handling
6 * (c) 2017, Jeff Layton <jlayton@redhat.com>
9 #include "gtest/gtest.h"
10 #include "include/cephfs/libcephfs.h"
11 #include "include/stat.h"
15 #include <sys/types.h>
22 #include <sys/xattr.h>
30 #include "include/ceph_assert.h"
32 /* in ms -- 1 minute */
33 #define MAX_WAIT (60 * 1000)
35 static void wait_for_atomic_bool(std::atomic_bool
&recalled
)
39 while (!recalled
.load()) {
40 ASSERT_LT(i
++, MAX_WAIT
);
45 static int ceph_ll_delegation_wait(struct ceph_mount_info
*cmount
, Fh
*fh
,
46 unsigned cmd
, ceph_deleg_cb_t cb
, void *priv
)
50 /* Wait 10s at most */
52 ret
= ceph_ll_delegation(cmount
, fh
, cmd
, cb
, priv
);
54 } while (ret
== -EAGAIN
&& retry
++ < 1000);
59 static int set_default_deleg_timeout(struct ceph_mount_info
*cmount
)
61 uint32_t session_timeout
= ceph_get_cap_return_timeout(cmount
);
62 return ceph_set_deleg_timeout(cmount
, session_timeout
- 1);
65 static void dummy_deleg_cb(Fh
*fh
, void *priv
)
67 std::atomic_bool
*recalled
= (std::atomic_bool
*)priv
;
68 recalled
->store(true);
71 static void open_breaker_func(struct ceph_mount_info
*cmount
, const char *filename
, int flags
, std::atomic_bool
*opened
)
73 bool do_shutdown
= false;
76 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
77 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
78 ASSERT_EQ(ceph_conf_parse_env(cmount
, NULL
), 0);
79 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
80 ASSERT_EQ(set_default_deleg_timeout(cmount
), 0);
85 ASSERT_EQ(ceph_ll_lookup_root(cmount
, &root
), 0);
88 struct ceph_statx stx
;
89 UserPerm
*perms
= ceph_mount_perms(cmount
);
91 ASSERT_EQ(ceph_ll_lookup(cmount
, root
, filename
, &file
, &stx
, CEPH_STATX_ALL_STATS
, 0, perms
), 0);
94 ASSERT_EQ(ceph_ll_getattr(cmount
, file
, &stx
, CEPH_STATX_ALL_STATS
, 0, perms
), 0);
95 ret
= ceph_ll_open(cmount
, file
, flags
, &fh
, perms
);
98 ASSERT_LT(i
++, MAX_WAIT
);
103 ASSERT_EQ(ceph_ll_close(cmount
, fh
), 0);
106 ceph_shutdown(cmount
);
115 static void namespace_breaker_func(struct ceph_mount_info
*cmount
, int cmd
, const char *oldname
, const char *newname
)
117 bool do_shutdown
= false;
120 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
121 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
122 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
123 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
124 ASSERT_EQ(set_default_deleg_timeout(cmount
), 0);
128 Inode
*root
, *file
= nullptr;
129 ASSERT_EQ(ceph_ll_lookup_root(cmount
, &root
), 0);
131 struct ceph_statx stx
;
132 UserPerm
*perms
= ceph_mount_perms(cmount
);
137 case DelegTestRename
:
138 ret
= ceph_ll_rename(cmount
, root
, oldname
, root
, newname
, perms
);
142 ASSERT_EQ(ceph_ll_lookup(cmount
, root
, oldname
, &file
, &stx
, 0, 0, perms
), 0);
144 ret
= ceph_ll_link(cmount
, file
, root
, newname
, perms
);
146 case DelegTestUnlink
:
147 ret
= ceph_ll_unlink(cmount
, root
, oldname
, perms
);
155 ASSERT_LT(i
++, MAX_WAIT
);
161 ceph_shutdown(cmount
);
164 static void simple_deleg_test(struct ceph_mount_info
*cmount
, struct ceph_mount_info
*tcmount
)
168 ASSERT_EQ(ceph_ll_lookup_root(cmount
, &root
), 0);
173 struct ceph_statx stx
;
174 UserPerm
*perms
= ceph_mount_perms(cmount
);
176 std::atomic_bool
recalled(false);
177 std::atomic_bool
opened(false);
179 // ensure r/w open breaks a r/w delegation
180 sprintf(filename
, "deleg.rwrw.%x", getpid());
181 ASSERT_EQ(ceph_ll_create(cmount
, root
, filename
, 0666,
182 O_RDWR
|O_CREAT
|O_EXCL
, &file
, &fh
, &stx
, 0, 0, perms
), 0);
183 ASSERT_EQ(ceph_ll_delegation_wait(cmount
, fh
, CEPH_DELEGATION_WR
, dummy_deleg_cb
, &recalled
), 0);
184 std::thread
breaker1(open_breaker_func
, tcmount
, filename
, O_RDWR
, &opened
);
186 wait_for_atomic_bool(recalled
);
187 ASSERT_EQ(opened
.load(), false);
188 ASSERT_EQ(ceph_ll_delegation(cmount
, fh
, CEPH_DELEGATION_NONE
, dummy_deleg_cb
, &recalled
), 0);
190 ASSERT_EQ(ceph_ll_close(cmount
, fh
), 0);
191 ASSERT_EQ(ceph_ll_unlink(cmount
, root
, filename
, perms
), 0);
193 // ensure r/o open breaks a r/w delegation
194 recalled
.store(false);
196 sprintf(filename
, "deleg.rorw.%x", getpid());
197 ASSERT_EQ(ceph_ll_create(cmount
, root
, filename
, 0666,
198 O_RDWR
|O_CREAT
|O_EXCL
, &file
, &fh
, &stx
, 0, 0, perms
), 0);
199 ASSERT_EQ(ceph_ll_delegation_wait(cmount
, fh
, CEPH_DELEGATION_WR
, dummy_deleg_cb
, &recalled
), 0);
200 std::thread
breaker2(open_breaker_func
, tcmount
, filename
, O_RDONLY
, &opened
);
201 wait_for_atomic_bool(recalled
);
202 ASSERT_EQ(opened
.load(), false);
203 ASSERT_EQ(ceph_ll_delegation(cmount
, fh
, CEPH_DELEGATION_NONE
, dummy_deleg_cb
, &recalled
), 0);
205 ASSERT_EQ(ceph_ll_close(cmount
, fh
), 0);
206 ASSERT_EQ(ceph_ll_unlink(cmount
, root
, filename
, perms
), 0);
208 // ensure r/o open does not break a r/o delegation
209 sprintf(filename
, "deleg.rwro.%x", getpid());
210 ASSERT_EQ(ceph_ll_create(cmount
, root
, filename
, 0666,
211 O_RDONLY
|O_CREAT
|O_EXCL
, &file
, &fh
, &stx
, 0, 0, perms
), 0);
212 recalled
.store(false);
213 ASSERT_EQ(ceph_ll_delegation_wait(cmount
, fh
, CEPH_DELEGATION_RD
, dummy_deleg_cb
, &recalled
), 0);
214 std::thread
breaker3(open_breaker_func
, tcmount
, filename
, O_RDONLY
, &opened
);
216 ASSERT_EQ(recalled
.load(), false);
218 // ensure that r/w open breaks r/o delegation
220 std::thread
breaker4(open_breaker_func
, tcmount
, filename
, O_WRONLY
, &opened
);
221 wait_for_atomic_bool(recalled
);
223 ASSERT_EQ(opened
.load(), false);
224 ASSERT_EQ(ceph_ll_delegation(cmount
, fh
, CEPH_DELEGATION_NONE
, dummy_deleg_cb
, &recalled
), 0);
226 ASSERT_EQ(ceph_ll_close(cmount
, fh
), 0);
227 ASSERT_EQ(ceph_ll_unlink(cmount
, root
, filename
, perms
), 0);
229 // ensure hardlinking breaks a r/w delegation
230 recalled
.store(false);
232 sprintf(filename
, "deleg.old.%x", getpid());
233 sprintf(newname
, "deleg.new.%x", getpid());
234 ASSERT_EQ(ceph_ll_create(cmount
, root
, filename
, 0666,
235 O_RDWR
|O_CREAT
|O_EXCL
, &file
, &fh
, &stx
, 0, 0, perms
), 0);
236 ASSERT_EQ(ceph_ll_delegation_wait(cmount
, fh
, CEPH_DELEGATION_WR
, dummy_deleg_cb
, &recalled
), 0);
237 std::thread
breaker5(namespace_breaker_func
, tcmount
, DelegTestLink
, filename
, newname
);
238 wait_for_atomic_bool(recalled
);
239 ASSERT_EQ(ceph_ll_delegation(cmount
, fh
, CEPH_DELEGATION_NONE
, dummy_deleg_cb
, &recalled
), 0);
241 ASSERT_EQ(ceph_ll_close(cmount
, fh
), 0);
242 ASSERT_EQ(ceph_ll_unlink(cmount
, root
, filename
, perms
), 0);
243 ASSERT_EQ(ceph_ll_unlink(cmount
, root
, newname
, perms
), 0);
245 // ensure renaming breaks a r/w delegation
246 recalled
.store(false);
247 ASSERT_EQ(ceph_ll_create(cmount
, root
, filename
, 0666,
248 O_RDWR
|O_CREAT
|O_EXCL
, &file
, &fh
, &stx
, 0, 0, perms
), 0);
249 ASSERT_EQ(ceph_ll_delegation_wait(cmount
, fh
, CEPH_DELEGATION_WR
, dummy_deleg_cb
, &recalled
), 0);
250 std::thread
breaker6(namespace_breaker_func
, tcmount
, DelegTestRename
, filename
, newname
);
251 wait_for_atomic_bool(recalled
);
252 ASSERT_EQ(ceph_ll_delegation(cmount
, fh
, CEPH_DELEGATION_NONE
, dummy_deleg_cb
, &recalled
), 0);
254 ASSERT_EQ(ceph_ll_close(cmount
, fh
), 0);
255 ASSERT_EQ(ceph_ll_unlink(cmount
, root
, newname
, perms
), 0);
257 // ensure unlinking breaks a r/w delegation
258 recalled
.store(false);
259 ASSERT_EQ(ceph_ll_create(cmount
, root
, filename
, 0666,
260 O_RDWR
|O_CREAT
|O_EXCL
, &file
, &fh
, &stx
, 0, 0, perms
), 0);
261 ASSERT_EQ(ceph_ll_delegation_wait(cmount
, fh
, CEPH_DELEGATION_WR
, dummy_deleg_cb
, &recalled
), 0);
262 std::thread
breaker7(namespace_breaker_func
, tcmount
, DelegTestUnlink
, filename
, nullptr);
263 wait_for_atomic_bool(recalled
);
264 ASSERT_EQ(ceph_ll_delegation(cmount
, fh
, CEPH_DELEGATION_NONE
, dummy_deleg_cb
, &recalled
), 0);
266 ASSERT_EQ(ceph_ll_close(cmount
, fh
), 0);
269 TEST(LibCephFS
, DelegMultiClient
) {
270 struct ceph_mount_info
*cmount
;
272 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
273 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
274 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
275 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
276 ASSERT_EQ(set_default_deleg_timeout(cmount
), 0);
278 simple_deleg_test(cmount
, nullptr);
280 ceph_shutdown(cmount
);
283 TEST(LibCephFS
, DelegSingleClient
) {
284 struct ceph_mount_info
*cmount
;
286 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
287 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
288 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
289 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
290 ASSERT_EQ(set_default_deleg_timeout(cmount
), 0);
292 simple_deleg_test(cmount
, cmount
);
294 ceph_shutdown(cmount
);
297 TEST(LibCephFS
, DelegTimeout
) {
298 struct ceph_mount_info
*cmount
;
299 ASSERT_EQ(ceph_create(&cmount
, NULL
), 0);
300 ASSERT_EQ(ceph_conf_read_file(cmount
, NULL
), 0);
301 ASSERT_EQ(0, ceph_conf_parse_env(cmount
, NULL
));
302 ASSERT_EQ(ceph_mount(cmount
, "/"), 0);
303 // tweak timeout to run quickly, since we don't plan to return it anyway
304 ASSERT_EQ(ceph_set_deleg_timeout(cmount
, 2), 0);
307 ASSERT_EQ(ceph_ll_lookup_root(cmount
, &root
), 0);
310 sprintf(filename
, "delegtimeo%x", getpid());
313 struct ceph_statx stx
;
314 UserPerm
*perms
= ceph_mount_perms(cmount
);
316 ASSERT_EQ(ceph_ll_create(cmount
, root
, filename
, 0666,
317 O_RDWR
|O_CREAT
|O_EXCL
, &file
, &fh
, &stx
, 0, 0, perms
), 0);
319 /* Reopen read-only */
320 ASSERT_EQ(ceph_ll_close(cmount
, fh
), 0);
321 ASSERT_EQ(ceph_ll_open(cmount
, file
, O_RDONLY
, &fh
, perms
), 0);
323 std::atomic_bool
recalled(false);
324 ASSERT_EQ(ceph_ll_delegation_wait(cmount
, fh
, CEPH_DELEGATION_RD
, dummy_deleg_cb
, &recalled
), 0);
325 std::atomic_bool
opened(false);
326 std::thread
breaker1(open_breaker_func
, nullptr, filename
, O_RDWR
, &opened
);
328 ASSERT_EQ(recalled
.load(), true);
329 ASSERT_EQ(ceph_ll_getattr(cmount
, root
, &stx
, 0, 0, perms
), -ENOTCONN
);
330 ceph_release(cmount
);
333 TEST(LibCephFS
, RecalledGetattr
) {
334 struct ceph_mount_info
*cmount1
;
335 ASSERT_EQ(ceph_create(&cmount1
, NULL
), 0);
336 ASSERT_EQ(ceph_conf_read_file(cmount1
, NULL
), 0);
337 ASSERT_EQ(0, ceph_conf_parse_env(cmount1
, NULL
));
338 ASSERT_EQ(ceph_mount(cmount1
, "/"), 0);
339 ASSERT_EQ(set_default_deleg_timeout(cmount1
), 0);
342 ASSERT_EQ(ceph_ll_lookup_root(cmount1
, &root
), 0);
345 sprintf(filename
, "recalledgetattr%x", getpid());
348 struct ceph_statx stx
;
349 UserPerm
*perms
= ceph_mount_perms(cmount1
);
351 ASSERT_EQ(ceph_ll_create(cmount1
, root
, filename
, 0666,
352 O_RDWR
|O_CREAT
|O_EXCL
, &file
, &fh
, &stx
, 0, 0, perms
), 0);
353 ASSERT_EQ(ceph_ll_write(cmount1
, fh
, 0, sizeof(filename
), filename
),
354 static_cast<int>(sizeof(filename
)));
355 ASSERT_EQ(ceph_ll_close(cmount1
, fh
), 0);
357 /* New mount for read delegation */
358 struct ceph_mount_info
*cmount2
;
359 ASSERT_EQ(ceph_create(&cmount2
, NULL
), 0);
360 ASSERT_EQ(ceph_conf_read_file(cmount2
, NULL
), 0);
361 ASSERT_EQ(0, ceph_conf_parse_env(cmount2
, NULL
));
362 ASSERT_EQ(ceph_mount(cmount2
, "/"), 0);
363 ASSERT_EQ(set_default_deleg_timeout(cmount2
), 0);
365 ASSERT_EQ(ceph_ll_lookup_root(cmount2
, &root
), 0);
366 perms
= ceph_mount_perms(cmount2
);
367 ASSERT_EQ(ceph_ll_lookup(cmount2
, root
, filename
, &file
, &stx
, 0, 0, perms
), 0);
369 ASSERT_EQ(ceph_ll_open(cmount2
, file
, O_WRONLY
, &fh
, perms
), 0);
370 ASSERT_EQ(ceph_ll_write(cmount2
, fh
, 0, sizeof(filename
), filename
),
371 static_cast<int>(sizeof(filename
)));
372 ASSERT_EQ(ceph_ll_close(cmount2
, fh
), 0);
374 ASSERT_EQ(ceph_ll_open(cmount2
, file
, O_RDONLY
, &fh
, perms
), 0);
376 /* Break delegation */
377 std::atomic_bool
recalled(false);
378 ASSERT_EQ(ceph_ll_delegation_wait(cmount2
, fh
, CEPH_DELEGATION_RD
, dummy_deleg_cb
, &recalled
), 0);
379 ASSERT_EQ(ceph_ll_read(cmount2
, fh
, 0, sizeof(filename
), filename
),
380 static_cast<int>(sizeof(filename
)));
381 ASSERT_EQ(ceph_ll_getattr(cmount2
, file
, &stx
, CEPH_STATX_ALL_STATS
, 0, perms
), 0);
382 std::atomic_bool
opened(false);
383 std::thread
breaker1(open_breaker_func
, cmount1
, filename
, O_WRONLY
, &opened
);
386 ASSERT_EQ(ceph_ll_getattr(cmount2
, file
, &stx
, CEPH_STATX_ALL_STATS
, 0, perms
), 0);
387 ASSERT_LT(i
++, MAX_WAIT
);
389 } while (!recalled
.load());
390 ASSERT_EQ(opened
.load(), false);
391 ASSERT_EQ(ceph_ll_getattr(cmount2
, file
, &stx
, CEPH_STATX_ALL_STATS
, 0, perms
), 0);
392 ASSERT_EQ(ceph_ll_delegation(cmount2
, fh
, CEPH_DELEGATION_NONE
, dummy_deleg_cb
, nullptr), 0);
394 ASSERT_EQ(ceph_ll_close(cmount2
, fh
), 0);
395 ceph_unmount(cmount2
);
396 ceph_release(cmount2
);
397 ceph_unmount(cmount1
);
398 ceph_release(cmount1
);