aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph
diff options
context:
space:
mode:
authorYan, Zheng <zheng.z.yan@intel.com>2013-07-24 00:22:11 -0400
committerSage Weil <sage@inktank.com>2013-08-09 20:55:32 -0400
commit6f60f889470aecf747610279545c054a99aadca3 (patch)
tree60f5781c7673d1d0e06ef1b658e652b2738daf24 /fs/ceph
parent4d1829a59de402fc95daf4576c51aa0a7439aee8 (diff)
ceph: fix freeing inode vs removing session caps race
remove_session_caps() uses iterate_session_caps() to remove caps, but iterate_session_caps() skips inodes that are being deleted. So session->s_nr_caps can be non-zero after iterate_session_caps() return. We can fix the issue by waiting until deletions are complete. __wait_on_freeing_inode() is designed for the job, but it is not exported, so we use lookup inode function to access it. Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
Diffstat (limited to 'fs/ceph')
-rw-r--r--fs/ceph/inode.c8
-rw-r--r--fs/ceph/mds_client.c31
-rw-r--r--fs/ceph/super.h2
3 files changed, 41 insertions, 0 deletions
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 55aaddb4047e..3b0abed667c2 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -61,6 +61,14 @@ struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino)
61 return inode; 61 return inode;
62} 62}
63 63
64struct inode *ceph_lookup_inode(struct super_block *sb, struct ceph_vino vino)
65{
66 struct inode *inode;
67 ino_t t = ceph_vino_to_ino(vino);
68 inode = ilookup5_nowait(sb, t, ceph_ino_compare, &vino);
69 return inode;
70}
71
64/* 72/*
65 * get/constuct snapdir inode for a given directory 73 * get/constuct snapdir inode for a given directory
66 */ 74 */
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 6b40d8112c64..cbf08203e00d 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -1031,6 +1031,37 @@ static void remove_session_caps(struct ceph_mds_session *session)
1031{ 1031{
1032 dout("remove_session_caps on %p\n", session); 1032 dout("remove_session_caps on %p\n", session);
1033 iterate_session_caps(session, remove_session_caps_cb, NULL); 1033 iterate_session_caps(session, remove_session_caps_cb, NULL);
1034
1035 spin_lock(&session->s_cap_lock);
1036 if (session->s_nr_caps > 0) {
1037 struct super_block *sb = session->s_mdsc->fsc->sb;
1038 struct inode *inode;
1039 struct ceph_cap *cap, *prev = NULL;
1040 struct ceph_vino vino;
1041 /*
1042 * iterate_session_caps() skips inodes that are being
1043 * deleted, we need to wait until deletions are complete.
1044 * __wait_on_freeing_inode() is designed for the job,
1045 * but it is not exported, so use lookup inode function
1046 * to access it.
1047 */
1048 while (!list_empty(&session->s_caps)) {
1049 cap = list_entry(session->s_caps.next,
1050 struct ceph_cap, session_caps);
1051 if (cap == prev)
1052 break;
1053 prev = cap;
1054 vino = cap->ci->i_vino;
1055 spin_unlock(&session->s_cap_lock);
1056
1057 inode = ceph_lookup_inode(sb, vino);
1058 iput(inode);
1059
1060 spin_lock(&session->s_cap_lock);
1061 }
1062 }
1063 spin_unlock(&session->s_cap_lock);
1064
1034 BUG_ON(session->s_nr_caps > 0); 1065 BUG_ON(session->s_nr_caps > 0);
1035 BUG_ON(!list_empty(&session->s_cap_flushing)); 1066 BUG_ON(!list_empty(&session->s_cap_flushing));
1036 cleanup_cap_releases(session); 1067 cleanup_cap_releases(session);
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index cbded572345e..afcd62a68916 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -677,6 +677,8 @@ extern void ceph_destroy_inode(struct inode *inode);
677 677
678extern struct inode *ceph_get_inode(struct super_block *sb, 678extern struct inode *ceph_get_inode(struct super_block *sb,
679 struct ceph_vino vino); 679 struct ceph_vino vino);
680extern struct inode *ceph_lookup_inode(struct super_block *sb,
681 struct ceph_vino vino);
680extern struct inode *ceph_get_snapdir(struct inode *parent); 682extern struct inode *ceph_get_snapdir(struct inode *parent);
681extern int ceph_fill_file_size(struct inode *inode, int issued, 683extern int ceph_fill_file_size(struct inode *inode, int issued,
682 u32 truncate_seq, u64 truncate_size, u64 size); 684 u32 truncate_seq, u64 truncate_size, u64 size);