aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph/snap.c
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2014-11-06 02:09:41 -0500
committerIlya Dryomov <idryomov@redhat.com>2014-12-17 12:09:51 -0500
commit97c85a828f36bbfffe9d77b977b65a5872b6cad4 (patch)
treedd432537785a075981f8e1ea5525b5f4f0006cf3 /fs/ceph/snap.c
parent7cfa0313d0dc52e4da9f196f8ad5bfdf266fc1fb (diff)
ceph: introduce global empty snap context
Current snaphost code does not properly handle moving inode from one empty snap realm to another empty snap realm. After changing inode's snap realm, some dirty pages' snap context can be not equal to inode's i_head_snap. This can trigger BUG() in ceph_put_wrbuffer_cap_refs() The fix is introduce a global empty snap context for all empty snap realm. This avoids triggering the BUG() for filesystem with no snapshot. Fixes: http://tracker.ceph.com/issues/9928 Signed-off-by: Yan, Zheng <zyan@redhat.com> Reviewed-by: Ilya Dryomov <idryomov@redhat.com>
Diffstat (limited to 'fs/ceph/snap.c')
-rw-r--r--fs/ceph/snap.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c
index c1cc993225e3..f64576e72b79 100644
--- a/fs/ceph/snap.c
+++ b/fs/ceph/snap.c
@@ -288,6 +288,9 @@ static int cmpu64_rev(const void *a, const void *b)
288 return 0; 288 return 0;
289} 289}
290 290
291
292static struct ceph_snap_context *empty_snapc;
293
291/* 294/*
292 * build the snap context for a given realm. 295 * build the snap context for a given realm.
293 */ 296 */
@@ -328,6 +331,12 @@ static int build_snap_context(struct ceph_snap_realm *realm)
328 return 0; 331 return 0;
329 } 332 }
330 333
334 if (num == 0 && realm->seq == empty_snapc->seq) {
335 ceph_get_snap_context(empty_snapc);
336 snapc = empty_snapc;
337 goto done;
338 }
339
331 /* alloc new snap context */ 340 /* alloc new snap context */
332 err = -ENOMEM; 341 err = -ENOMEM;
333 if (num > (SIZE_MAX - sizeof(*snapc)) / sizeof(u64)) 342 if (num > (SIZE_MAX - sizeof(*snapc)) / sizeof(u64))
@@ -365,6 +374,7 @@ static int build_snap_context(struct ceph_snap_realm *realm)
365 realm->ino, realm, snapc, snapc->seq, 374 realm->ino, realm, snapc, snapc->seq,
366 (unsigned int) snapc->num_snaps); 375 (unsigned int) snapc->num_snaps);
367 376
377done:
368 ceph_put_snap_context(realm->cached_context); 378 ceph_put_snap_context(realm->cached_context);
369 realm->cached_context = snapc; 379 realm->cached_context = snapc;
370 return 0; 380 return 0;
@@ -465,6 +475,9 @@ void ceph_queue_cap_snap(struct ceph_inode_info *ci)
465 cap_snap. lucky us. */ 475 cap_snap. lucky us. */
466 dout("queue_cap_snap %p already pending\n", inode); 476 dout("queue_cap_snap %p already pending\n", inode);
467 kfree(capsnap); 477 kfree(capsnap);
478 } else if (ci->i_snap_realm->cached_context == empty_snapc) {
479 dout("queue_cap_snap %p empty snapc\n", inode);
480 kfree(capsnap);
468 } else if (dirty & (CEPH_CAP_AUTH_EXCL|CEPH_CAP_XATTR_EXCL| 481 } else if (dirty & (CEPH_CAP_AUTH_EXCL|CEPH_CAP_XATTR_EXCL|
469 CEPH_CAP_FILE_EXCL|CEPH_CAP_FILE_WR)) { 482 CEPH_CAP_FILE_EXCL|CEPH_CAP_FILE_WR)) {
470 struct ceph_snap_context *snapc = ci->i_head_snapc; 483 struct ceph_snap_context *snapc = ci->i_head_snapc;
@@ -925,5 +938,16 @@ out:
925 return; 938 return;
926} 939}
927 940
941int __init ceph_snap_init(void)
942{
943 empty_snapc = ceph_create_snap_context(0, GFP_NOFS);
944 if (!empty_snapc)
945 return -ENOMEM;
946 empty_snapc->seq = 1;
947 return 0;
948}
928 949
929 950void ceph_snap_exit(void)
951{
952 ceph_put_snap_context(empty_snapc);
953}