Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 487317c9 authored by Ronnie Sahlberg's avatar Ronnie Sahlberg Committed by Steve French
Browse files

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: default avatarRonnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
Reviewed-by: default avatarPavel Shilovsky <pshilov@microsoft.com>
parent 0ff2b018
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);

	/*
+5 −0
Original line number Diff line number Diff line
@@ -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
+6 −2
Original line number Diff line number Diff line
@@ -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 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
			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;