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); |