diff options
author | Yan, Zheng <zyan@redhat.com> | 2017-08-28 04:36:53 -0400 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2017-09-06 13:56:54 -0400 |
commit | 3ae0bebc49b3fb3c9fa9b62b95c5119a04aa7282 (patch) | |
tree | f98801c0cb9e80a22fee86c0001ec0a4e3153f0a | |
parent | c8fd0d37f81dd38e3f319f4938b45a5aaf0dfc58 (diff) |
ceph: queue cap snap only when snap realm's context changes
If we create capsnap when snap realm's context does not change, the
new capsnap's snapc is equal to ci->i_head_snapc. Page writeback code
can't differentiates dirty pages associated with the new capsnap from
dirty pages associated with i_head_snapc.
Signed-off-by: "Yan, Zheng" <zyan@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
-rw-r--r-- | fs/ceph/snap.c | 37 |
1 files changed, 16 insertions, 21 deletions
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index dab5d6732345..1ffc8b426c1c 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c | |||
@@ -299,7 +299,8 @@ static int cmpu64_rev(const void *a, const void *b) | |||
299 | /* | 299 | /* |
300 | * build the snap context for a given realm. | 300 | * build the snap context for a given realm. |
301 | */ | 301 | */ |
302 | static int build_snap_context(struct ceph_snap_realm *realm) | 302 | static int build_snap_context(struct ceph_snap_realm *realm, |
303 | struct list_head* dirty_realms) | ||
303 | { | 304 | { |
304 | struct ceph_snap_realm *parent = realm->parent; | 305 | struct ceph_snap_realm *parent = realm->parent; |
305 | struct ceph_snap_context *snapc; | 306 | struct ceph_snap_context *snapc; |
@@ -313,7 +314,7 @@ static int build_snap_context(struct ceph_snap_realm *realm) | |||
313 | */ | 314 | */ |
314 | if (parent) { | 315 | if (parent) { |
315 | if (!parent->cached_context) { | 316 | if (!parent->cached_context) { |
316 | err = build_snap_context(parent); | 317 | err = build_snap_context(parent, dirty_realms); |
317 | if (err) | 318 | if (err) |
318 | goto fail; | 319 | goto fail; |
319 | } | 320 | } |
@@ -332,7 +333,7 @@ static int build_snap_context(struct ceph_snap_realm *realm) | |||
332 | " (unchanged)\n", | 333 | " (unchanged)\n", |
333 | realm->ino, realm, realm->cached_context, | 334 | realm->ino, realm, realm->cached_context, |
334 | realm->cached_context->seq, | 335 | realm->cached_context->seq, |
335 | (unsigned int) realm->cached_context->num_snaps); | 336 | (unsigned int)realm->cached_context->num_snaps); |
336 | return 0; | 337 | return 0; |
337 | } | 338 | } |
338 | 339 | ||
@@ -373,7 +374,11 @@ static int build_snap_context(struct ceph_snap_realm *realm) | |||
373 | realm->ino, realm, snapc, snapc->seq, | 374 | realm->ino, realm, snapc, snapc->seq, |
374 | (unsigned int) snapc->num_snaps); | 375 | (unsigned int) snapc->num_snaps); |
375 | 376 | ||
376 | ceph_put_snap_context(realm->cached_context); | 377 | if (realm->cached_context) { |
378 | ceph_put_snap_context(realm->cached_context); | ||
379 | /* queue realm for cap_snap creation */ | ||
380 | list_add_tail(&realm->dirty_item, dirty_realms); | ||
381 | } | ||
377 | realm->cached_context = snapc; | 382 | realm->cached_context = snapc; |
378 | return 0; | 383 | return 0; |
379 | 384 | ||
@@ -394,15 +399,16 @@ fail: | |||
394 | /* | 399 | /* |
395 | * rebuild snap context for the given realm and all of its children. | 400 | * rebuild snap context for the given realm and all of its children. |
396 | */ | 401 | */ |
397 | static void rebuild_snap_realms(struct ceph_snap_realm *realm) | 402 | static void rebuild_snap_realms(struct ceph_snap_realm *realm, |
403 | struct list_head *dirty_realms) | ||
398 | { | 404 | { |
399 | struct ceph_snap_realm *child; | 405 | struct ceph_snap_realm *child; |
400 | 406 | ||
401 | dout("rebuild_snap_realms %llx %p\n", realm->ino, realm); | 407 | dout("rebuild_snap_realms %llx %p\n", realm->ino, realm); |
402 | build_snap_context(realm); | 408 | build_snap_context(realm, dirty_realms); |
403 | 409 | ||
404 | list_for_each_entry(child, &realm->children, child_item) | 410 | list_for_each_entry(child, &realm->children, child_item) |
405 | rebuild_snap_realms(child); | 411 | rebuild_snap_realms(child, dirty_realms); |
406 | } | 412 | } |
407 | 413 | ||
408 | 414 | ||
@@ -624,13 +630,11 @@ static void queue_realm_cap_snaps(struct ceph_snap_realm *realm) | |||
624 | { | 630 | { |
625 | struct ceph_inode_info *ci; | 631 | struct ceph_inode_info *ci; |
626 | struct inode *lastinode = NULL; | 632 | struct inode *lastinode = NULL; |
627 | struct ceph_snap_realm *child; | ||
628 | 633 | ||
629 | dout("queue_realm_cap_snaps %p %llx inodes\n", realm, realm->ino); | 634 | dout("queue_realm_cap_snaps %p %llx inodes\n", realm, realm->ino); |
630 | 635 | ||
631 | spin_lock(&realm->inodes_with_caps_lock); | 636 | spin_lock(&realm->inodes_with_caps_lock); |
632 | list_for_each_entry(ci, &realm->inodes_with_caps, | 637 | list_for_each_entry(ci, &realm->inodes_with_caps, i_snap_realm_item) { |
633 | i_snap_realm_item) { | ||
634 | struct inode *inode = igrab(&ci->vfs_inode); | 638 | struct inode *inode = igrab(&ci->vfs_inode); |
635 | if (!inode) | 639 | if (!inode) |
636 | continue; | 640 | continue; |
@@ -643,14 +647,6 @@ static void queue_realm_cap_snaps(struct ceph_snap_realm *realm) | |||
643 | spin_unlock(&realm->inodes_with_caps_lock); | 647 | spin_unlock(&realm->inodes_with_caps_lock); |
644 | iput(lastinode); | 648 | iput(lastinode); |
645 | 649 | ||
646 | list_for_each_entry(child, &realm->children, child_item) { | ||
647 | dout("queue_realm_cap_snaps %p %llx queue child %p %llx\n", | ||
648 | realm, realm->ino, child, child->ino); | ||
649 | list_del_init(&child->dirty_item); | ||
650 | list_add(&child->dirty_item, &realm->dirty_item); | ||
651 | } | ||
652 | |||
653 | list_del_init(&realm->dirty_item); | ||
654 | dout("queue_realm_cap_snaps %p %llx done\n", realm, realm->ino); | 650 | dout("queue_realm_cap_snaps %p %llx done\n", realm, realm->ino); |
655 | } | 651 | } |
656 | 652 | ||
@@ -721,8 +717,6 @@ more: | |||
721 | if (err < 0) | 717 | if (err < 0) |
722 | goto fail; | 718 | goto fail; |
723 | 719 | ||
724 | /* queue realm for cap_snap creation */ | ||
725 | list_add(&realm->dirty_item, &dirty_realms); | ||
726 | if (realm->seq > mdsc->last_snap_seq) | 720 | if (realm->seq > mdsc->last_snap_seq) |
727 | mdsc->last_snap_seq = realm->seq; | 721 | mdsc->last_snap_seq = realm->seq; |
728 | 722 | ||
@@ -741,7 +735,7 @@ more: | |||
741 | 735 | ||
742 | /* invalidate when we reach the _end_ (root) of the trace */ | 736 | /* invalidate when we reach the _end_ (root) of the trace */ |
743 | if (invalidate && p >= e) | 737 | if (invalidate && p >= e) |
744 | rebuild_snap_realms(realm); | 738 | rebuild_snap_realms(realm, &dirty_realms); |
745 | 739 | ||
746 | if (!first_realm) | 740 | if (!first_realm) |
747 | first_realm = realm; | 741 | first_realm = realm; |
@@ -758,6 +752,7 @@ more: | |||
758 | while (!list_empty(&dirty_realms)) { | 752 | while (!list_empty(&dirty_realms)) { |
759 | realm = list_first_entry(&dirty_realms, struct ceph_snap_realm, | 753 | realm = list_first_entry(&dirty_realms, struct ceph_snap_realm, |
760 | dirty_item); | 754 | dirty_item); |
755 | list_del_init(&realm->dirty_item); | ||
761 | queue_realm_cap_snaps(realm); | 756 | queue_realm_cap_snaps(realm); |
762 | } | 757 | } |
763 | 758 | ||