diff options
Diffstat (limited to 'fs/ceph/snap.c')
| -rw-r--r-- | fs/ceph/snap.c | 89 |
1 files changed, 58 insertions, 31 deletions
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index c0b26b6badba..4868b9dcac5a 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c | |||
| @@ -435,7 +435,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) | |||
| 435 | { | 435 | { |
| 436 | struct inode *inode = &ci->vfs_inode; | 436 | struct inode *inode = &ci->vfs_inode; |
| 437 | struct ceph_cap_snap *capsnap; | 437 | struct ceph_cap_snap *capsnap; |
| 438 | int used; | 438 | int used, dirty; |
| 439 | 439 | ||
| 440 | capsnap = kzalloc(sizeof(*capsnap), GFP_NOFS); | 440 | capsnap = kzalloc(sizeof(*capsnap), GFP_NOFS); |
| 441 | if (!capsnap) { | 441 | if (!capsnap) { |
| @@ -445,6 +445,7 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) | |||
| 445 | 445 | ||
| 446 | spin_lock(&inode->i_lock); | 446 | spin_lock(&inode->i_lock); |
| 447 | used = __ceph_caps_used(ci); | 447 | used = __ceph_caps_used(ci); |
| 448 | dirty = __ceph_caps_dirty(ci); | ||
| 448 | if (__ceph_have_pending_cap_snap(ci)) { | 449 | if (__ceph_have_pending_cap_snap(ci)) { |
| 449 | /* there is no point in queuing multiple "pending" cap_snaps, | 450 | /* there is no point in queuing multiple "pending" cap_snaps, |
| 450 | as no new writes are allowed to start when pending, so any | 451 | as no new writes are allowed to start when pending, so any |
| @@ -452,11 +453,15 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) | |||
| 452 | cap_snap. lucky us. */ | 453 | cap_snap. lucky us. */ |
| 453 | dout("queue_cap_snap %p already pending\n", inode); | 454 | dout("queue_cap_snap %p already pending\n", inode); |
| 454 | kfree(capsnap); | 455 | kfree(capsnap); |
| 455 | } else if (ci->i_wrbuffer_ref_head || (used & CEPH_CAP_FILE_WR)) { | 456 | } else if (ci->i_wrbuffer_ref_head || (used & CEPH_CAP_FILE_WR) || |
| 457 | (dirty & (CEPH_CAP_AUTH_EXCL|CEPH_CAP_XATTR_EXCL| | ||
| 458 | CEPH_CAP_FILE_EXCL|CEPH_CAP_FILE_WR))) { | ||
| 456 | struct ceph_snap_context *snapc = ci->i_head_snapc; | 459 | struct ceph_snap_context *snapc = ci->i_head_snapc; |
| 457 | 460 | ||
| 461 | dout("queue_cap_snap %p cap_snap %p queuing under %p\n", inode, | ||
| 462 | capsnap, snapc); | ||
| 458 | igrab(inode); | 463 | igrab(inode); |
| 459 | 464 | ||
| 460 | atomic_set(&capsnap->nref, 1); | 465 | atomic_set(&capsnap->nref, 1); |
| 461 | capsnap->ci = ci; | 466 | capsnap->ci = ci; |
| 462 | INIT_LIST_HEAD(&capsnap->ci_item); | 467 | INIT_LIST_HEAD(&capsnap->ci_item); |
| @@ -464,15 +469,21 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) | |||
| 464 | 469 | ||
| 465 | capsnap->follows = snapc->seq - 1; | 470 | capsnap->follows = snapc->seq - 1; |
| 466 | capsnap->issued = __ceph_caps_issued(ci, NULL); | 471 | capsnap->issued = __ceph_caps_issued(ci, NULL); |
| 467 | capsnap->dirty = __ceph_caps_dirty(ci); | 472 | capsnap->dirty = dirty; |
| 468 | 473 | ||
| 469 | capsnap->mode = inode->i_mode; | 474 | capsnap->mode = inode->i_mode; |
| 470 | capsnap->uid = inode->i_uid; | 475 | capsnap->uid = inode->i_uid; |
| 471 | capsnap->gid = inode->i_gid; | 476 | capsnap->gid = inode->i_gid; |
| 472 | 477 | ||
| 473 | /* fixme? */ | 478 | if (dirty & CEPH_CAP_XATTR_EXCL) { |
| 474 | capsnap->xattr_blob = NULL; | 479 | __ceph_build_xattrs_blob(ci); |
| 475 | capsnap->xattr_len = 0; | 480 | capsnap->xattr_blob = |
| 481 | ceph_buffer_get(ci->i_xattrs.blob); | ||
| 482 | capsnap->xattr_version = ci->i_xattrs.version; | ||
| 483 | } else { | ||
| 484 | capsnap->xattr_blob = NULL; | ||
| 485 | capsnap->xattr_version = 0; | ||
| 486 | } | ||
| 476 | 487 | ||
| 477 | /* dirty page count moved from _head to this cap_snap; | 488 | /* dirty page count moved from _head to this cap_snap; |
| 478 | all subsequent writes page dirties occur _after_ this | 489 | all subsequent writes page dirties occur _after_ this |
| @@ -480,7 +491,9 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci) | |||
| 480 | capsnap->dirty_pages = ci->i_wrbuffer_ref_head; | 491 | capsnap->dirty_pages = ci->i_wrbuffer_ref_head; |
| 481 | ci->i_wrbuffer_ref_head = 0; | 492 | ci->i_wrbuffer_ref_head = 0; |
| 482 | capsnap->context = snapc; | 493 | capsnap->context = snapc; |
| 483 | ci->i_head_snapc = NULL; | 494 | ci->i_head_snapc = |
| 495 | ceph_get_snap_context(ci->i_snap_realm->cached_context); | ||
| 496 | dout(" new snapc is %p\n", ci->i_head_snapc); | ||
| 484 | list_add_tail(&capsnap->ci_item, &ci->i_cap_snaps); | 497 | list_add_tail(&capsnap->ci_item, &ci->i_cap_snaps); |
| 485 | 498 | ||
| 486 | if (used & CEPH_CAP_FILE_WR) { | 499 | if (used & CEPH_CAP_FILE_WR) { |
| @@ -539,6 +552,41 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci, | |||
| 539 | return 1; /* caller may want to ceph_flush_snaps */ | 552 | return 1; /* caller may want to ceph_flush_snaps */ |
| 540 | } | 553 | } |
| 541 | 554 | ||
| 555 | /* | ||
| 556 | * Queue cap_snaps for snap writeback for this realm and its children. | ||
| 557 | * Called under snap_rwsem, so realm topology won't change. | ||
| 558 | */ | ||
| 559 | static void queue_realm_cap_snaps(struct ceph_snap_realm *realm) | ||
| 560 | { | ||
| 561 | struct ceph_inode_info *ci; | ||
| 562 | struct inode *lastinode = NULL; | ||
| 563 | struct ceph_snap_realm *child; | ||
| 564 | |||
| 565 | dout("queue_realm_cap_snaps %p %llx inodes\n", realm, realm->ino); | ||
| 566 | |||
| 567 | spin_lock(&realm->inodes_with_caps_lock); | ||
| 568 | list_for_each_entry(ci, &realm->inodes_with_caps, | ||
| 569 | i_snap_realm_item) { | ||
| 570 | struct inode *inode = igrab(&ci->vfs_inode); | ||
| 571 | if (!inode) | ||
| 572 | continue; | ||
| 573 | spin_unlock(&realm->inodes_with_caps_lock); | ||
| 574 | if (lastinode) | ||
| 575 | iput(lastinode); | ||
| 576 | lastinode = inode; | ||
| 577 | ceph_queue_cap_snap(ci); | ||
| 578 | spin_lock(&realm->inodes_with_caps_lock); | ||
| 579 | } | ||
| 580 | spin_unlock(&realm->inodes_with_caps_lock); | ||
| 581 | if (lastinode) | ||
| 582 | iput(lastinode); | ||
| 583 | |||
| 584 | dout("queue_realm_cap_snaps %p %llx children\n", realm, realm->ino); | ||
| 585 | list_for_each_entry(child, &realm->children, child_item) | ||
| 586 | queue_realm_cap_snaps(child); | ||
| 587 | |||
| 588 | dout("queue_realm_cap_snaps %p %llx done\n", realm, realm->ino); | ||
| 589 | } | ||
| 542 | 590 | ||
| 543 | /* | 591 | /* |
| 544 | * Parse and apply a snapblob "snap trace" from the MDS. This specifies | 592 | * Parse and apply a snapblob "snap trace" from the MDS. This specifies |
| @@ -589,29 +637,8 @@ more: | |||
| 589 | * | 637 | * |
| 590 | * ...unless it's a snap deletion! | 638 | * ...unless it's a snap deletion! |
| 591 | */ | 639 | */ |
| 592 | if (!deletion) { | 640 | if (!deletion) |
| 593 | struct ceph_inode_info *ci; | 641 | queue_realm_cap_snaps(realm); |
| 594 | struct inode *lastinode = NULL; | ||
| 595 | |||
| 596 | spin_lock(&realm->inodes_with_caps_lock); | ||
| 597 | list_for_each_entry(ci, &realm->inodes_with_caps, | ||
| 598 | i_snap_realm_item) { | ||
| 599 | struct inode *inode = igrab(&ci->vfs_inode); | ||
| 600 | if (!inode) | ||
| 601 | continue; | ||
| 602 | spin_unlock(&realm->inodes_with_caps_lock); | ||
| 603 | if (lastinode) | ||
| 604 | iput(lastinode); | ||
| 605 | lastinode = inode; | ||
| 606 | ceph_queue_cap_snap(ci); | ||
| 607 | spin_lock(&realm->inodes_with_caps_lock); | ||
| 608 | } | ||
| 609 | spin_unlock(&realm->inodes_with_caps_lock); | ||
| 610 | if (lastinode) | ||
| 611 | iput(lastinode); | ||
| 612 | dout("update_snap_trace cap_snaps queued\n"); | ||
| 613 | } | ||
| 614 | |||
| 615 | } else { | 642 | } else { |
| 616 | dout("update_snap_trace %llx %p seq %lld unchanged\n", | 643 | dout("update_snap_trace %llx %p seq %lld unchanged\n", |
| 617 | realm->ino, realm, realm->seq); | 644 | realm->ino, realm, realm->seq); |
