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>
This commit is contained in:
		
					parent
					
						
							
								4d1829a59d
							
						
					
				
			
			
				commit
				
					
						6f60f88947
					
				
			
		
					 3 changed files with 41 additions and 0 deletions
				
			
		|  | @ -61,6 +61,14 @@ struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino) | ||||||
| 	return inode; | 	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 |  * get/constuct snapdir inode for a given directory | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | @ -1031,6 +1031,37 @@ static void remove_session_caps(struct ceph_mds_session *session) | ||||||
| { | { | ||||||
| 	dout("remove_session_caps on %p\n", session); | 	dout("remove_session_caps on %p\n", session); | ||||||
| 	iterate_session_caps(session, remove_session_caps_cb, NULL); | 	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(session->s_nr_caps > 0); | ||||||
| 	BUG_ON(!list_empty(&session->s_cap_flushing)); | 	BUG_ON(!list_empty(&session->s_cap_flushing)); | ||||||
| 	cleanup_cap_releases(session); | 	cleanup_cap_releases(session); | ||||||
|  |  | ||||||
|  | @ -677,6 +677,8 @@ extern void ceph_destroy_inode(struct inode *inode); | ||||||
| 
 | 
 | ||||||
| extern struct inode *ceph_get_inode(struct super_block *sb, | extern struct inode *ceph_get_inode(struct super_block *sb, | ||||||
| 				    struct ceph_vino vino); | 				    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 struct inode *ceph_get_snapdir(struct inode *parent); | ||||||
| extern int ceph_fill_file_size(struct inode *inode, int issued, | extern int ceph_fill_file_size(struct inode *inode, int issued, | ||||||
| 			       u32 truncate_seq, u64 truncate_size, u64 size); | 			       u32 truncate_seq, u64 truncate_size, u64 size); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Yan, Zheng
				Yan, Zheng