diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 55aaddb4047ea9ca01dc9d0ea203e562e58dccd8..3b0abed667c2e79b8cbef7ed654868a70bf91ed3 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) return inode; } +struct inode *ceph_lookup_inode(struct super_block *sb, struct ceph_vino vino) +{ + struct inode *inode; + ino_t t = ceph_vino_to_ino(vino); + inode = ilookup5_nowait(sb, t, ceph_ino_compare, &vino); + return inode; +} + /* * get/constuct snapdir inode for a given directory */ diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 6b40d8112c64080e800ec5e2722dcfca15b76ad5..cbf08203e00dce56e472ca0ac7ff76b3a71bf832 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) { dout("remove_session_caps on %p\n", session); iterate_session_caps(session, remove_session_caps_cb, NULL); + + spin_lock(&session->s_cap_lock); + if (session->s_nr_caps > 0) { + struct super_block *sb = session->s_mdsc->fsc->sb; + struct inode *inode; + struct ceph_cap *cap, *prev = NULL; + struct ceph_vino vino; + /* + * iterate_session_caps() skips inodes that are being + * deleted, we need to wait until deletions are complete. + * __wait_on_freeing_inode() is designed for the job, + * but it is not exported, so use lookup inode function + * to access it. + */ + while (!list_empty(&session->s_caps)) { + cap = list_entry(session->s_caps.next, + struct ceph_cap, session_caps); + if (cap == prev) + break; + prev = cap; + vino = cap->ci->i_vino; + spin_unlock(&session->s_cap_lock); + + inode = ceph_lookup_inode(sb, vino); + iput(inode); + + spin_lock(&session->s_cap_lock); + } + } + spin_unlock(&session->s_cap_lock); + BUG_ON(session->s_nr_caps > 0); BUG_ON(!list_empty(&session->s_cap_flushing)); cleanup_cap_releases(session); diff --git a/fs/ceph/super.h b/fs/ceph/super.h index cbded572345e77a107e539aa4e433d6f6f7964c0..afcd62a68916e358676d4fa4e7b7abf3c94ecb43 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -677,6 +677,8 @@ extern void ceph_destroy_inode(struct inode *inode); extern struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino); +extern struct inode *ceph_lookup_inode(struct super_block *sb, + struct ceph_vino vino); extern struct inode *ceph_get_snapdir(struct inode *parent); extern int ceph_fill_file_size(struct inode *inode, int issued, u32 truncate_seq, u64 truncate_size, u64 size);