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>
This commit is contained in:
Yan, Zheng 2017-08-28 16:36:53 +08:00 committed by Ilya Dryomov
parent c8fd0d37f8
commit 3ae0bebc49

View file

@ -299,7 +299,8 @@ static int cmpu64_rev(const void *a, const void *b)
/*
* build the snap context for a given realm.
*/
static int build_snap_context(struct ceph_snap_realm *realm)
static int build_snap_context(struct ceph_snap_realm *realm,
struct list_head* dirty_realms)
{
struct ceph_snap_realm *parent = realm->parent;
struct ceph_snap_context *snapc;
@ -313,7 +314,7 @@ static int build_snap_context(struct ceph_snap_realm *realm)
*/
if (parent) {
if (!parent->cached_context) {
err = build_snap_context(parent);
err = build_snap_context(parent, dirty_realms);
if (err)
goto fail;
}
@ -332,7 +333,7 @@ static int build_snap_context(struct ceph_snap_realm *realm)
" (unchanged)\n",
realm->ino, realm, realm->cached_context,
realm->cached_context->seq,
(unsigned int) realm->cached_context->num_snaps);
(unsigned int)realm->cached_context->num_snaps);
return 0;
}
@ -373,7 +374,11 @@ static int build_snap_context(struct ceph_snap_realm *realm)
realm->ino, realm, snapc, snapc->seq,
(unsigned int) snapc->num_snaps);
ceph_put_snap_context(realm->cached_context);
if (realm->cached_context) {
ceph_put_snap_context(realm->cached_context);
/* queue realm for cap_snap creation */
list_add_tail(&realm->dirty_item, dirty_realms);
}
realm->cached_context = snapc;
return 0;
@ -394,15 +399,16 @@ fail:
/*
* rebuild snap context for the given realm and all of its children.
*/
static void rebuild_snap_realms(struct ceph_snap_realm *realm)
static void rebuild_snap_realms(struct ceph_snap_realm *realm,
struct list_head *dirty_realms)
{
struct ceph_snap_realm *child;
dout("rebuild_snap_realms %llx %p\n", realm->ino, realm);
build_snap_context(realm);
build_snap_context(realm, dirty_realms);
list_for_each_entry(child, &realm->children, child_item)
rebuild_snap_realms(child);
rebuild_snap_realms(child, dirty_realms);
}
@ -624,13 +630,11 @@ static void queue_realm_cap_snaps(struct ceph_snap_realm *realm)
{
struct ceph_inode_info *ci;
struct inode *lastinode = NULL;
struct ceph_snap_realm *child;
dout("queue_realm_cap_snaps %p %llx inodes\n", realm, realm->ino);
spin_lock(&realm->inodes_with_caps_lock);
list_for_each_entry(ci, &realm->inodes_with_caps,
i_snap_realm_item) {
list_for_each_entry(ci, &realm->inodes_with_caps, i_snap_realm_item) {
struct inode *inode = igrab(&ci->vfs_inode);
if (!inode)
continue;
@ -643,14 +647,6 @@ static void queue_realm_cap_snaps(struct ceph_snap_realm *realm)
spin_unlock(&realm->inodes_with_caps_lock);
iput(lastinode);
list_for_each_entry(child, &realm->children, child_item) {
dout("queue_realm_cap_snaps %p %llx queue child %p %llx\n",
realm, realm->ino, child, child->ino);
list_del_init(&child->dirty_item);
list_add(&child->dirty_item, &realm->dirty_item);
}
list_del_init(&realm->dirty_item);
dout("queue_realm_cap_snaps %p %llx done\n", realm, realm->ino);
}
@ -721,8 +717,6 @@ more:
if (err < 0)
goto fail;
/* queue realm for cap_snap creation */
list_add(&realm->dirty_item, &dirty_realms);
if (realm->seq > mdsc->last_snap_seq)
mdsc->last_snap_seq = realm->seq;
@ -741,7 +735,7 @@ more:
/* invalidate when we reach the _end_ (root) of the trace */
if (invalidate && p >= e)
rebuild_snap_realms(realm);
rebuild_snap_realms(realm, &dirty_realms);
if (!first_realm)
first_realm = realm;
@ -758,6 +752,7 @@ more:
while (!list_empty(&dirty_realms)) {
realm = list_first_entry(&dirty_realms, struct ceph_snap_realm,
dirty_item);
list_del_init(&realm->dirty_item);
queue_realm_cap_snaps(realm);
}