cifs: add spinlock for the openFileList to cifsInodeInfo
We can not depend on the tcon->open_file_lock here since in multiuser mode we may have the same file/inode open via multiple different tcons. The current code is race prone and will crash if one user deletes a file at the same time a different user opens/create the file. To avoid this we need to have a spinlock attached to the inode and not the tcon. RHBZ: 1580165 CC: Stable <stable@vger.kernel.org> Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
This commit is contained in:
		
							parent
							
								
									0ff2b018b0
								
							
						
					
					
						commit
						487317c994
					
				| @ -303,6 +303,7 @@ cifs_alloc_inode(struct super_block *sb) | ||||
| 	cifs_inode->uniqueid = 0; | ||||
| 	cifs_inode->createtime = 0; | ||||
| 	cifs_inode->epoch = 0; | ||||
| 	spin_lock_init(&cifs_inode->open_file_lock); | ||||
| 	generate_random_uuid(cifs_inode->lease_key); | ||||
| 
 | ||||
| 	/*
 | ||||
|  | ||||
| @ -1377,6 +1377,7 @@ struct cifsInodeInfo { | ||||
| 	struct rw_semaphore lock_sem;	/* protect the fields above */ | ||||
| 	/* BB add in lists for dirty pages i.e. write caching info for oplock */ | ||||
| 	struct list_head openFileList; | ||||
| 	spinlock_t	open_file_lock;	/* protects openFileList */ | ||||
| 	__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ | ||||
| 	unsigned int oplock;		/* oplock/lease level we have */ | ||||
| 	unsigned int epoch;		/* used to track lease state changes */ | ||||
| @ -1780,10 +1781,14 @@ require use of the stronger protocol */ | ||||
|  *  tcp_ses_lock protects: | ||||
|  *	list operations on tcp and SMB session lists | ||||
|  *  tcon->open_file_lock protects the list of open files hanging off the tcon | ||||
|  *  inode->open_file_lock protects the openFileList hanging off the inode | ||||
|  *  cfile->file_info_lock protects counters and fields in cifs file struct | ||||
|  *  f_owner.lock protects certain per file struct operations | ||||
|  *  mapping->page_lock protects certain per page operations | ||||
|  * | ||||
|  *  Note that the cifs_tcon.open_file_lock should be taken before | ||||
|  *  not after the cifsInodeInfo.open_file_lock | ||||
|  * | ||||
|  *  Semaphores | ||||
|  *  ---------- | ||||
|  *  sesSem     operations on smb session | ||||
|  | ||||
| @ -338,10 +338,12 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, | ||||
| 	atomic_inc(&tcon->num_local_opens); | ||||
| 
 | ||||
| 	/* if readable file instance put first in list*/ | ||||
| 	spin_lock(&cinode->open_file_lock); | ||||
| 	if (file->f_mode & FMODE_READ) | ||||
| 		list_add(&cfile->flist, &cinode->openFileList); | ||||
| 	else | ||||
| 		list_add_tail(&cfile->flist, &cinode->openFileList); | ||||
| 	spin_unlock(&cinode->open_file_lock); | ||||
| 	spin_unlock(&tcon->open_file_lock); | ||||
| 
 | ||||
| 	if (fid->purge_cache) | ||||
| @ -413,7 +415,9 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler) | ||||
| 	cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open); | ||||
| 
 | ||||
| 	/* remove it from the lists */ | ||||
| 	spin_lock(&cifsi->open_file_lock); | ||||
| 	list_del(&cifs_file->flist); | ||||
| 	spin_unlock(&cifsi->open_file_lock); | ||||
| 	list_del(&cifs_file->tlist); | ||||
| 	atomic_dec(&tcon->num_local_opens); | ||||
| 
 | ||||
| @ -1950,9 +1954,9 @@ refind_writable: | ||||
| 			return 0; | ||||
| 		} | ||||
| 
 | ||||
| 		spin_lock(&tcon->open_file_lock); | ||||
| 		spin_lock(&cifs_inode->open_file_lock); | ||||
| 		list_move_tail(&inv_file->flist, &cifs_inode->openFileList); | ||||
| 		spin_unlock(&tcon->open_file_lock); | ||||
| 		spin_unlock(&cifs_inode->open_file_lock); | ||||
| 		cifsFileInfo_put(inv_file); | ||||
| 		++refind; | ||||
| 		inv_file = NULL; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user