aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph
diff options
context:
space:
mode:
authorSage Weil <sage@newdream.net>2010-05-10 19:12:25 -0400
committerSage Weil <sage@newdream.net>2010-05-17 18:25:37 -0400
commit6c99f2545dbb9e53afe0d1d037c51ab04ef1ff4e (patch)
tree0f6dae93a1970751ffd144431664ac9ed9141014 /fs/ceph
parent7e70f0ed9f3ee47394576be86c593f66832413e9 (diff)
ceph: throw out dirty caps metadata, data on session teardown
The remove_session_caps() helper is called when an MDS closes out our session (either normally, or as a result of a failed reconnect), and when we tear down state for umount. If we remove the last cap, and there are no cap migrations in progress, then there is little hope of us flushing out that data to the mds (without heroic efforts to reconnect and flush). So, to avoid leaving inodes pinned (due to dirty state) and crashing after umount, throw out dirty caps state and unpin the inodes. Print a warning to the console so we know something was lost. NOTE: Although we drop wrbuffer refs, we don't actually mark pages clean; maybe a truncate should be queued? Signed-off-by: Sage Weil <sage@newdream.net>
Diffstat (limited to 'fs/ceph')
-rw-r--r--fs/ceph/mds_client.c44
1 files changed, 41 insertions, 3 deletions
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 525085f36db9..114bada97c16 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -799,12 +799,49 @@ out:
799} 799}
800 800
801static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, 801static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
802 void *arg) 802 void *arg)
803{ 803{
804 struct ceph_inode_info *ci = ceph_inode(inode); 804 struct ceph_inode_info *ci = ceph_inode(inode);
805 int drop = 0;
806
805 dout("removing cap %p, ci is %p, inode is %p\n", 807 dout("removing cap %p, ci is %p, inode is %p\n",
806 cap, ci, &ci->vfs_inode); 808 cap, ci, &ci->vfs_inode);
807 ceph_remove_cap(cap); 809 spin_lock(&inode->i_lock);
810 __ceph_remove_cap(cap);
811 if (!__ceph_is_any_real_caps(ci)) {
812 struct ceph_mds_client *mdsc =
813 &ceph_sb_to_client(inode->i_sb)->mdsc;
814
815 spin_lock(&mdsc->cap_dirty_lock);
816 if (!list_empty(&ci->i_dirty_item)) {
817 pr_info(" dropping dirty %s state for %p %lld\n",
818 ceph_cap_string(ci->i_dirty_caps),
819 inode, ceph_ino(inode));
820 ci->i_dirty_caps = 0;
821 list_del_init(&ci->i_dirty_item);
822 drop = 1;
823 }
824 if (!list_empty(&ci->i_flushing_item)) {
825 pr_info(" dropping dirty+flushing %s state for %p %lld\n",
826 ceph_cap_string(ci->i_flushing_caps),
827 inode, ceph_ino(inode));
828 ci->i_flushing_caps = 0;
829 list_del_init(&ci->i_flushing_item);
830 mdsc->num_cap_flushing--;
831 drop = 1;
832 }
833 if (drop && ci->i_wrbuffer_ref) {
834 pr_info(" dropping dirty data for %p %lld\n",
835 inode, ceph_ino(inode));
836 ci->i_wrbuffer_ref = 0;
837 ci->i_wrbuffer_ref_head = 0;
838 drop++;
839 }
840 spin_unlock(&mdsc->cap_dirty_lock);
841 }
842 spin_unlock(&inode->i_lock);
843 while (drop--)
844 iput(inode);
808 return 0; 845 return 0;
809} 846}
810 847
@@ -816,6 +853,7 @@ static void remove_session_caps(struct ceph_mds_session *session)
816 dout("remove_session_caps on %p\n", session); 853 dout("remove_session_caps on %p\n", session);
817 iterate_session_caps(session, remove_session_caps_cb, NULL); 854 iterate_session_caps(session, remove_session_caps_cb, NULL);
818 BUG_ON(session->s_nr_caps > 0); 855 BUG_ON(session->s_nr_caps > 0);
856 BUG_ON(!list_empty(&session->s_cap_flushing));
819 cleanup_cap_releases(session); 857 cleanup_cap_releases(session);
820} 858}
821 859
@@ -1281,7 +1319,7 @@ retry:
1281 len += 1 + temp->d_name.len; 1319 len += 1 + temp->d_name.len;
1282 temp = temp->d_parent; 1320 temp = temp->d_parent;
1283 if (temp == NULL) { 1321 if (temp == NULL) {
1284 pr_err("build_path_dentry corrupt dentry %p\n", dentry); 1322 pr_err("build_path corrupt dentry %p\n", dentry);
1285 return ERR_PTR(-EINVAL); 1323 return ERR_PTR(-EINVAL);
1286 } 1324 }
1287 } 1325 }