|
Lines 323-334
Link Here
|
| 323 |
EXPECT_EQ(0, (intptr_t)thr0_value); |
323 |
EXPECT_EQ(0, (intptr_t)thr0_value); |
| 324 |
} |
324 |
} |
| 325 |
|
325 |
|
| 326 |
TEST_F(Notify, inval_inode_with_clean_cache) |
326 |
/* Invalidate I/O in the pattern generated by cephfs */ |
|
|
327 |
TEST_F(Notify, inval_inode_like_cephfs) |
| 327 |
{ |
328 |
{ |
| 328 |
const static char FULLPATH[] = "mountpoint/foo"; |
329 |
const static char FULLPATH[] = "mountpoint/foo"; |
| 329 |
const static char RELPATH[] = "foo"; |
330 |
const static char RELPATH[] = "foo"; |
| 330 |
const char CONTENTS0[] = "abcdefgh"; |
331 |
const char CONTENTS0[] = "0123456789"; |
| 331 |
const char CONTENTS1[] = "ijklmnopqrstuvwxyz"; |
332 |
const char CONTENTS1[] = "0123456789Singapore"; |
| 332 |
struct inval_inode_args iia; |
333 |
struct inval_inode_args iia; |
| 333 |
struct stat sb; |
334 |
struct stat sb; |
| 334 |
ino_t ino = 42; |
335 |
ino_t ino = 42; |
|
Lines 343-348
Link Here
|
| 343 |
|
344 |
|
| 344 |
expect_lookup(FUSE_ROOT_ID, RELPATH, ino, size0, seq); |
345 |
expect_lookup(FUSE_ROOT_ID, RELPATH, ino, size0, seq); |
| 345 |
expect_open(ino, 0, 1); |
346 |
expect_open(ino, 0, 1); |
|
|
347 |
expect_read(ino, 0, size0, size0, CONTENTS0); |
| 348 |
|
| 349 |
/* Fill the data cache */ |
| 350 |
fd = open(FULLPATH, O_RDWR); |
| 351 |
ASSERT_LE(0, fd) << strerror(errno); |
| 352 |
ASSERT_EQ(size0, read(fd, buf, sizeof(buf))) << strerror(errno); |
| 353 |
EXPECT_EQ(0, memcmp(buf, CONTENTS0, size0)); |
| 354 |
|
| 355 |
/* Evict the data cache */ |
| 356 |
iia.mock = m_mock; |
| 357 |
iia.ino = ino; |
| 358 |
iia.off = 0; |
| 359 |
iia.len = 0; |
| 360 |
ASSERT_EQ(0, pthread_create(&th0, NULL, inval_inode, &iia)) |
| 361 |
<< strerror(errno); |
| 362 |
pthread_join(th0, &thr0_value); |
| 363 |
EXPECT_EQ(0, (intptr_t)thr0_value); |
| 364 |
|
| 365 |
/* cache attributes were purged; this will trigger a new GETATTR */ |
| 346 |
EXPECT_CALL(*m_mock, process( |
366 |
EXPECT_CALL(*m_mock, process( |
| 347 |
ResultOf([=](auto in) { |
367 |
ResultOf([=](auto in) { |
| 348 |
return (in.header.opcode == FUSE_GETATTR && |
368 |
return (in.header.opcode == FUSE_GETATTR && |
|
Lines 356-368
Link Here
|
| 356 |
out.body.attr.attr.size = size1; |
376 |
out.body.attr.attr.size = size1; |
| 357 |
out.body.attr.attr.uid = uid; |
377 |
out.body.attr.attr.uid = uid; |
| 358 |
}))); |
378 |
}))); |
| 359 |
expect_read(ino, 0, size0, size0, CONTENTS0); |
|
|
| 360 |
expect_read(ino, 0, size1, size1, CONTENTS1); |
379 |
expect_read(ino, 0, size1, size1, CONTENTS1); |
|
|
380 |
ASSERT_EQ(0, stat(FULLPATH, &sb)) << strerror(errno); |
| 381 |
EXPECT_EQ(uid, sb.st_uid); |
| 382 |
EXPECT_EQ(size1, sb.st_size); |
| 361 |
|
383 |
|
|
|
384 |
/* This read should not be serviced by cache */ |
| 385 |
ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno); |
| 386 |
ASSERT_EQ(size1, read(fd, buf, sizeof(buf))) << strerror(errno); |
| 387 |
EXPECT_EQ(0, memcmp(buf, CONTENTS1, size1)); |
| 388 |
|
| 389 |
leak(fd); |
| 390 |
} |
| 391 |
|
| 392 |
TEST_F(Notify, inval_inode_with_clean_cache) |
| 393 |
{ |
| 394 |
const static char FULLPATH[] = "mountpoint/foo"; |
| 395 |
const static char RELPATH[] = "foo"; |
| 396 |
const char CONTENTS0[] = "abcdefgh"; |
| 397 |
const char CONTENTS1[] = "ijklmnopqrstuvwxyz"; |
| 398 |
struct inval_inode_args iia; |
| 399 |
struct stat sb; |
| 400 |
ino_t ino = 42; |
| 401 |
void *thr0_value; |
| 402 |
Sequence seq; |
| 403 |
uid_t uid = 12345; |
| 404 |
pthread_t th0; |
| 405 |
ssize_t size0 = sizeof(CONTENTS0); |
| 406 |
ssize_t size1 = sizeof(CONTENTS1); |
| 407 |
char buf[80]; |
| 408 |
int fd; |
| 409 |
|
| 410 |
expect_lookup(FUSE_ROOT_ID, RELPATH, ino, size0, seq); |
| 411 |
expect_open(ino, 0, 1); |
| 412 |
expect_read(ino, 0, size0, size0, CONTENTS0); |
| 413 |
|
| 362 |
/* Fill the data cache */ |
414 |
/* Fill the data cache */ |
| 363 |
fd = open(FULLPATH, O_RDWR); |
415 |
fd = open(FULLPATH, O_RDWR); |
| 364 |
ASSERT_LE(0, fd) << strerror(errno); |
416 |
ASSERT_LE(0, fd) << strerror(errno); |
| 365 |
ASSERT_EQ(size0, read(fd, buf, size0)) << strerror(errno); |
417 |
ASSERT_EQ(size0, read(fd, buf, sizeof(buf))) << strerror(errno); |
| 366 |
EXPECT_EQ(0, memcmp(buf, CONTENTS0, size0)); |
418 |
EXPECT_EQ(0, memcmp(buf, CONTENTS0, size0)); |
| 367 |
|
419 |
|
| 368 |
/* Evict the data cache */ |
420 |
/* Evict the data cache */ |
|
Lines 376-381
Link Here
|
| 376 |
EXPECT_EQ(0, (intptr_t)thr0_value); |
428 |
EXPECT_EQ(0, (intptr_t)thr0_value); |
| 377 |
|
429 |
|
| 378 |
/* cache attributes were purged; this will trigger a new GETATTR */ |
430 |
/* cache attributes were purged; this will trigger a new GETATTR */ |
|
|
431 |
EXPECT_CALL(*m_mock, process( |
| 432 |
ResultOf([=](auto in) { |
| 433 |
return (in.header.opcode == FUSE_GETATTR && |
| 434 |
in.header.nodeid == ino); |
| 435 |
}, Eq(true)), |
| 436 |
_) |
| 437 |
).WillOnce(Invoke(ReturnImmediate([=](auto i __unused, auto& out) { |
| 438 |
SET_OUT_HEADER_LEN(out, attr); |
| 439 |
out.body.attr.attr.mode = S_IFREG | 0644; |
| 440 |
out.body.attr.attr_valid = UINT64_MAX; |
| 441 |
out.body.attr.attr.size = size1; |
| 442 |
out.body.attr.attr.uid = uid; |
| 443 |
}))); |
| 444 |
expect_read(ino, 0, size1, size1, CONTENTS1); |
| 379 |
ASSERT_EQ(0, stat(FULLPATH, &sb)) << strerror(errno); |
445 |
ASSERT_EQ(0, stat(FULLPATH, &sb)) << strerror(errno); |
| 380 |
EXPECT_EQ(uid, sb.st_uid); |
446 |
EXPECT_EQ(uid, sb.st_uid); |
| 381 |
EXPECT_EQ(size1, sb.st_size); |
447 |
EXPECT_EQ(size1, sb.st_size); |
|
Lines 382-388
Link Here
|
| 382 |
|
448 |
|
| 383 |
/* This read should not be serviced by cache */ |
449 |
/* This read should not be serviced by cache */ |
| 384 |
ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno); |
450 |
ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno); |
| 385 |
ASSERT_EQ(size1, read(fd, buf, size1)) << strerror(errno); |
451 |
ASSERT_EQ(size1, read(fd, buf, sizeof(buf))) << strerror(errno); |
| 386 |
EXPECT_EQ(0, memcmp(buf, CONTENTS1, size1)); |
452 |
EXPECT_EQ(0, memcmp(buf, CONTENTS1, size1)); |
| 387 |
|
453 |
|
| 388 |
leak(fd); |
454 |
leak(fd); |
|
Lines 441-447
Link Here
|
| 441 |
EXPECT_EQ(0, (intptr_t)thr0_value); |
507 |
EXPECT_EQ(0, (intptr_t)thr0_value); |
| 442 |
|
508 |
|
| 443 |
/* This read should be serviced by cache */ |
509 |
/* This read should be serviced by cache */ |
| 444 |
ASSERT_EQ(size1, read(fd, buf, size1)) << strerror(errno); |
510 |
ASSERT_EQ(size1, read(fd, buf, sizeof(buf))) << strerror(errno); |
| 445 |
EXPECT_EQ(0, memcmp(buf, CONTENTS1, size1)); |
511 |
EXPECT_EQ(0, memcmp(buf, CONTENTS1, size1)); |
| 446 |
|
512 |
|
| 447 |
leak(fd); |
513 |
leak(fd); |
|
Lines 451-463
Link Here
|
| 451 |
{ |
517 |
{ |
| 452 |
const static char FULLPATH[] = "mountpoint/foo"; |
518 |
const static char FULLPATH[] = "mountpoint/foo"; |
| 453 |
const static char RELPATH[] = "foo"; |
519 |
const static char RELPATH[] = "foo"; |
| 454 |
const char CONTENTS[] = "abcdefgh"; |
520 |
const char CONTENTS0[] = "abcdefgh"; |
|
|
521 |
const char CONTENTS1[] = "ijklmnop"; |
| 455 |
struct inval_inode_args iia; |
522 |
struct inval_inode_args iia; |
| 456 |
ino_t ino = 42; |
523 |
ino_t ino = 42; |
| 457 |
void *thr0_value; |
524 |
void *thr0_value; |
| 458 |
Sequence seq; |
525 |
Sequence seq; |
| 459 |
pthread_t th0; |
526 |
pthread_t th0; |
| 460 |
ssize_t bufsize = sizeof(CONTENTS); |
527 |
ssize_t size0 = sizeof(CONTENTS0); |
|
|
528 |
ssize_t size1 = sizeof(CONTENTS1); |
| 529 |
char buf[80]; |
| 461 |
int fd; |
530 |
int fd; |
| 462 |
|
531 |
|
| 463 |
expect_lookup(FUSE_ROOT_ID, RELPATH, ino, 0, seq); |
532 |
expect_lookup(FUSE_ROOT_ID, RELPATH, ino, 0, seq); |
|
Lines 466-474
Link Here
|
| 466 |
/* Fill the data cache */ |
535 |
/* Fill the data cache */ |
| 467 |
fd = open(FULLPATH, O_RDWR); |
536 |
fd = open(FULLPATH, O_RDWR); |
| 468 |
ASSERT_LE(0, fd); |
537 |
ASSERT_LE(0, fd); |
| 469 |
ASSERT_EQ(bufsize, write(fd, CONTENTS, bufsize)) << strerror(errno); |
538 |
ASSERT_EQ(size0, write(fd, CONTENTS0, size0)) << strerror(errno); |
| 470 |
|
539 |
|
| 471 |
expect_write(ino, 0, bufsize, CONTENTS); |
540 |
expect_write(ino, 0, size0, CONTENTS0); |
| 472 |
/* |
541 |
/* |
| 473 |
* The FUSE protocol does not require an fsync here, but FreeBSD's |
542 |
* The FUSE protocol does not require an fsync here, but FreeBSD's |
| 474 |
* bufobj_invalbuf sends it anyway |
543 |
* bufobj_invalbuf sends it anyway |
|
Lines 485-490
Link Here
|
| 485 |
pthread_join(th0, &thr0_value); |
554 |
pthread_join(th0, &thr0_value); |
| 486 |
EXPECT_EQ(0, (intptr_t)thr0_value); |
555 |
EXPECT_EQ(0, (intptr_t)thr0_value); |
| 487 |
|
556 |
|
|
|
557 |
/* |
| 558 |
* Reading again should trigger another FUSE_READ because the cache |
| 559 |
* is empty. |
| 560 |
*/ |
| 561 |
EXPECT_CALL(*m_mock, process( |
| 562 |
ResultOf([=](auto in) { |
| 563 |
return (in.header.opcode == FUSE_GETATTR && |
| 564 |
in.header.nodeid == ino); |
| 565 |
}, Eq(true)), |
| 566 |
_) |
| 567 |
).WillOnce(Invoke(ReturnImmediate([=](auto i __unused, auto& out) { |
| 568 |
SET_OUT_HEADER_LEN(out, attr); |
| 569 |
out.body.attr.attr.mode = S_IFREG | 0644; |
| 570 |
out.body.attr.attr_valid = UINT64_MAX; |
| 571 |
out.body.attr.attr.size = size1; |
| 572 |
}))); |
| 573 |
expect_read(ino, 0, size1, size1, CONTENTS1); |
| 574 |
ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno); |
| 575 |
ASSERT_EQ(size1, read(fd, buf, sizeof(buf))) << strerror(errno); |
| 576 |
|
| 488 |
leak(fd); |
577 |
leak(fd); |
| 489 |
} |
578 |
} |
| 490 |
|
579 |
|