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

Commit c9a2e4a8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag '5.4-rc5-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:
 "Seven cifs/smb3 fixes, including three for stable"

* tag '5.4-rc5-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: Fix cifsInodeInfo lock_sem deadlock when reconnect occurs
  CIFS: Fix use after free of file info structures
  CIFS: Fix retry mid list corruption on reconnects
  cifs: Fix missed free operations
  CIFS: avoid using MID 0xFFFF
  cifs: clarify comment about timestamp granularity for old servers
  cifs: Handle -EINPROGRESS only when noblockcnt is set
parents 6995a6a5 d46b0da7
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -169,7 +169,13 @@ cifs_read_super(struct super_block *sb)
	else
		sb->s_maxbytes = MAX_NON_LFS;

	/* Some very old servers like DOS and OS/2 used 2 second granularity */
	/*
	 * Some very old servers like DOS and OS/2 used 2 second granularity
	 * (while all current servers use 100ns granularity - see MS-DTYP)
	 * but 1 second is the maximum allowed granularity for the VFS
	 * so for old servers set time granularity to 1 second while for
	 * everything else (current servers) set it to 100ns.
	 */
	if ((tcon->ses->server->vals->protocol_id == SMB10_PROT_ID) &&
	    ((tcon->ses->capabilities &
	      tcon->ses->server->vals->cap_nt_find) == 0) &&
+5 −0
Original line number Diff line number Diff line
@@ -1391,6 +1391,11 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
struct cifsInodeInfo {
	bool can_cache_brlcks;
	struct list_head llist;	/* locks helb by this inode */
	/*
	 * NOTE: Some code paths call down_read(lock_sem) twice, so
	 * we must always use use cifs_down_write() instead of down_write()
	 * for this semaphore to avoid deadlocks.
	 */
	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;
+1 −0
Original line number Diff line number Diff line
@@ -170,6 +170,7 @@ extern int cifs_unlock_range(struct cifsFileInfo *cfile,
			     struct file_lock *flock, const unsigned int xid);
extern int cifs_push_mandatory_locks(struct cifsFileInfo *cfile);

extern void cifs_down_write(struct rw_semaphore *sem);
extern struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid,
					      struct file *file,
					      struct tcon_link *tlink,
+15 −3
Original line number Diff line number Diff line
@@ -564,9 +564,11 @@ cifs_reconnect(struct TCP_Server_Info *server)
	spin_lock(&GlobalMid_Lock);
	list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
		mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
		kref_get(&mid_entry->refcount);
		if (mid_entry->mid_state == MID_REQUEST_SUBMITTED)
			mid_entry->mid_state = MID_RETRY_NEEDED;
		list_move(&mid_entry->qhead, &retry_list);
		mid_entry->mid_flags |= MID_DELETED;
	}
	spin_unlock(&GlobalMid_Lock);
	mutex_unlock(&server->srv_mutex);
@@ -576,6 +578,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
		mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
		list_del_init(&mid_entry->qhead);
		mid_entry->callback(mid_entry);
		cifs_mid_q_entry_release(mid_entry);
	}

	if (cifs_rdma_enabled(server)) {
@@ -895,8 +898,10 @@ dequeue_mid(struct mid_q_entry *mid, bool malformed)
	if (mid->mid_flags & MID_DELETED)
		printk_once(KERN_WARNING
			    "trying to dequeue a deleted mid\n");
	else
	else {
		list_del_init(&mid->qhead);
		mid->mid_flags |= MID_DELETED;
	}
	spin_unlock(&GlobalMid_Lock);
}

@@ -966,8 +971,10 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
		list_for_each_safe(tmp, tmp2, &server->pending_mid_q) {
			mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
			cifs_dbg(FYI, "Clearing mid 0x%llx\n", mid_entry->mid);
			kref_get(&mid_entry->refcount);
			mid_entry->mid_state = MID_SHUTDOWN;
			list_move(&mid_entry->qhead, &dispose_list);
			mid_entry->mid_flags |= MID_DELETED;
		}
		spin_unlock(&GlobalMid_Lock);

@@ -977,6 +984,7 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
			cifs_dbg(FYI, "Callback mid 0x%llx\n", mid_entry->mid);
			list_del_init(&mid_entry->qhead);
			mid_entry->callback(mid_entry);
			cifs_mid_q_entry_release(mid_entry);
		}
		/* 1/8th of sec is more than enough time for them to exit */
		msleep(125);
@@ -3882,8 +3890,12 @@ generic_ip_connect(struct TCP_Server_Info *server)

	rc = socket->ops->connect(socket, saddr, slen,
				  server->noblockcnt ? O_NONBLOCK : 0);

	if (rc == -EINPROGRESS)
	/*
	 * When mounting SMB root file systems, we do not want to block in
	 * connect. Otherwise bail out and then let cifs_reconnect() perform
	 * reconnect failover - if possible.
	 */
	if (server->noblockcnt && rc == -EINPROGRESS)
		rc = 0;
	if (rc < 0) {
		cifs_dbg(FYI, "Error %d connecting to server\n", rc);
+18 −11
Original line number Diff line number Diff line
@@ -281,6 +281,13 @@ cifs_has_mand_locks(struct cifsInodeInfo *cinode)
	return has_locks;
}

void
cifs_down_write(struct rw_semaphore *sem)
{
	while (!down_write_trylock(sem))
		msleep(10);
}

struct cifsFileInfo *
cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
		  struct tcon_link *tlink, __u32 oplock)
@@ -306,7 +313,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
	INIT_LIST_HEAD(&fdlocks->locks);
	fdlocks->cfile = cfile;
	cfile->llist = fdlocks;
	down_write(&cinode->lock_sem);
	cifs_down_write(&cinode->lock_sem);
	list_add(&fdlocks->llist, &cinode->llist);
	up_write(&cinode->lock_sem);

@@ -405,10 +412,11 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler)
	bool oplock_break_cancelled;

	spin_lock(&tcon->open_file_lock);

	spin_lock(&cifsi->open_file_lock);
	spin_lock(&cifs_file->file_info_lock);
	if (--cifs_file->count > 0) {
		spin_unlock(&cifs_file->file_info_lock);
		spin_unlock(&cifsi->open_file_lock);
		spin_unlock(&tcon->open_file_lock);
		return;
	}
@@ -421,9 +429,7 @@ 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);

@@ -440,6 +446,7 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler)
		cifs_set_oplock_level(cifsi, 0);
	}

	spin_unlock(&cifsi->open_file_lock);
	spin_unlock(&tcon->open_file_lock);

	oplock_break_cancelled = wait_oplock_handler ?
@@ -464,7 +471,7 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler)
	 * Delete any outstanding lock records. We'll lose them when the file
	 * is closed anyway.
	 */
	down_write(&cifsi->lock_sem);
	cifs_down_write(&cifsi->lock_sem);
	list_for_each_entry_safe(li, tmp, &cifs_file->llist->locks, llist) {
		list_del(&li->llist);
		cifs_del_lock_waiters(li);
@@ -1027,7 +1034,7 @@ static void
cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock)
{
	struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
	down_write(&cinode->lock_sem);
	cifs_down_write(&cinode->lock_sem);
	list_add_tail(&lock->llist, &cfile->llist->locks);
	up_write(&cinode->lock_sem);
}
@@ -1049,7 +1056,7 @@ cifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock,

try_again:
	exist = false;
	down_write(&cinode->lock_sem);
	cifs_down_write(&cinode->lock_sem);

	exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length,
					lock->type, lock->flags, &conf_lock,
@@ -1072,7 +1079,7 @@ cifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock,
					(lock->blist.next == &lock->blist));
		if (!rc)
			goto try_again;
		down_write(&cinode->lock_sem);
		cifs_down_write(&cinode->lock_sem);
		list_del_init(&lock->blist);
	}

@@ -1125,7 +1132,7 @@ cifs_posix_lock_set(struct file *file, struct file_lock *flock)
		return rc;

try_again:
	down_write(&cinode->lock_sem);
	cifs_down_write(&cinode->lock_sem);
	if (!cinode->can_cache_brlcks) {
		up_write(&cinode->lock_sem);
		return rc;
@@ -1331,7 +1338,7 @@ cifs_push_locks(struct cifsFileInfo *cfile)
	int rc = 0;

	/* we are going to update can_cache_brlcks here - need a write access */
	down_write(&cinode->lock_sem);
	cifs_down_write(&cinode->lock_sem);
	if (!cinode->can_cache_brlcks) {
		up_write(&cinode->lock_sem);
		return rc;
@@ -1522,7 +1529,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
	if (!buf)
		return -ENOMEM;

	down_write(&cinode->lock_sem);
	cifs_down_write(&cinode->lock_sem);
	for (i = 0; i < 2; i++) {
		cur = buf;
		num = 0;
Loading