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->uniqueid = 0;
|
||||||
cifs_inode->createtime = 0;
|
cifs_inode->createtime = 0;
|
||||||
cifs_inode->epoch = 0;
|
cifs_inode->epoch = 0;
|
||||||
|
spin_lock_init(&cifs_inode->open_file_lock);
|
||||||
generate_random_uuid(cifs_inode->lease_key);
|
generate_random_uuid(cifs_inode->lease_key);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1377,6 +1377,7 @@ struct cifsInodeInfo {
|
||||||
struct rw_semaphore lock_sem; /* protect the fields above */
|
struct rw_semaphore lock_sem; /* protect the fields above */
|
||||||
/* BB add in lists for dirty pages i.e. write caching info for oplock */
|
/* BB add in lists for dirty pages i.e. write caching info for oplock */
|
||||||
struct list_head openFileList;
|
struct list_head openFileList;
|
||||||
|
spinlock_t open_file_lock; /* protects openFileList */
|
||||||
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
|
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
|
||||||
unsigned int oplock; /* oplock/lease level we have */
|
unsigned int oplock; /* oplock/lease level we have */
|
||||||
unsigned int epoch; /* used to track lease state changes */
|
unsigned int epoch; /* used to track lease state changes */
|
||||||
|
@ -1780,10 +1781,14 @@ require use of the stronger protocol */
|
||||||
* tcp_ses_lock protects:
|
* tcp_ses_lock protects:
|
||||||
* list operations on tcp and SMB session lists
|
* list operations on tcp and SMB session lists
|
||||||
* tcon->open_file_lock protects the list of open files hanging off the tcon
|
* 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
|
* cfile->file_info_lock protects counters and fields in cifs file struct
|
||||||
* f_owner.lock protects certain per file struct operations
|
* f_owner.lock protects certain per file struct operations
|
||||||
* mapping->page_lock protects certain per page 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
|
* Semaphores
|
||||||
* ----------
|
* ----------
|
||||||
* sesSem operations on smb session
|
* 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);
|
atomic_inc(&tcon->num_local_opens);
|
||||||
|
|
||||||
/* if readable file instance put first in list*/
|
/* if readable file instance put first in list*/
|
||||||
|
spin_lock(&cinode->open_file_lock);
|
||||||
if (file->f_mode & FMODE_READ)
|
if (file->f_mode & FMODE_READ)
|
||||||
list_add(&cfile->flist, &cinode->openFileList);
|
list_add(&cfile->flist, &cinode->openFileList);
|
||||||
else
|
else
|
||||||
list_add_tail(&cfile->flist, &cinode->openFileList);
|
list_add_tail(&cfile->flist, &cinode->openFileList);
|
||||||
|
spin_unlock(&cinode->open_file_lock);
|
||||||
spin_unlock(&tcon->open_file_lock);
|
spin_unlock(&tcon->open_file_lock);
|
||||||
|
|
||||||
if (fid->purge_cache)
|
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);
|
cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open);
|
||||||
|
|
||||||
/* remove it from the lists */
|
/* remove it from the lists */
|
||||||
|
spin_lock(&cifsi->open_file_lock);
|
||||||
list_del(&cifs_file->flist);
|
list_del(&cifs_file->flist);
|
||||||
|
spin_unlock(&cifsi->open_file_lock);
|
||||||
list_del(&cifs_file->tlist);
|
list_del(&cifs_file->tlist);
|
||||||
atomic_dec(&tcon->num_local_opens);
|
atomic_dec(&tcon->num_local_opens);
|
||||||
|
|
||||||
|
@ -1950,9 +1954,9 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&tcon->open_file_lock);
|
spin_lock(&cifs_inode->open_file_lock);
|
||||||
list_move_tail(&inv_file->flist, &cifs_inode->openFileList);
|
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);
|
cifsFileInfo_put(inv_file);
|
||||||
++refind;
|
++refind;
|
||||||
inv_file = NULL;
|
inv_file = NULL;
|
||||||
|
|
Loading…
Reference in New Issue