mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	cifs: Fix locking in cifs_strict_readv()
Fix to take the i_rwsem (through the netfs locking wrappers) before taking
cinode->lock_sem.
Fixes: 3ee1a1fc39 ("cifs: Cut over to using netfslib")
Reported-by: Enzo Matsumiya <ematsumiya@suse.de>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
			
			
This commit is contained in:
		
							parent
							
								
									29b4c7bb85
								
							
						
					
					
						commit
						14b1cd2534
					
				
					 4 changed files with 29 additions and 10 deletions
				
			
		| 
						 | 
					@ -26,7 +26,7 @@
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The caller must hold any appropriate locks.
 | 
					 * The caller must hold any appropriate locks.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_iter *iter)
 | 
					ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_iter *iter)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct netfs_io_request *rreq;
 | 
						struct netfs_io_request *rreq;
 | 
				
			||||||
	ssize_t ret;
 | 
						ssize_t ret;
 | 
				
			||||||
| 
						 | 
					@ -98,6 +98,7 @@ static ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_
 | 
				
			||||||
		iov_iter_revert(iter, orig_count - iov_iter_count(iter));
 | 
							iov_iter_revert(iter, orig_count - iov_iter_count(iter));
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(netfs_unbuffered_read_iter_locked);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * netfs_unbuffered_read_iter - Perform an unbuffered or direct I/O read
 | 
					 * netfs_unbuffered_read_iter - Perform an unbuffered or direct I/O read
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1995,6 +1995,7 @@ require use of the stronger protocol */
 | 
				
			||||||
 *				->chans_need_reconnect
 | 
					 *				->chans_need_reconnect
 | 
				
			||||||
 *				->chans_in_reconnect
 | 
					 *				->chans_in_reconnect
 | 
				
			||||||
 * cifs_tcon->tc_lock		(anything that is not protected by another lock and can change)
 | 
					 * cifs_tcon->tc_lock		(anything that is not protected by another lock and can change)
 | 
				
			||||||
 | 
					 * inode->i_rwsem, taken by fs/netfs/locking.c e.g. should be taken before cifsInodeInfo locks
 | 
				
			||||||
 * cifsInodeInfo->open_file_lock	cifsInodeInfo->openFileList	cifs_alloc_inode
 | 
					 * cifsInodeInfo->open_file_lock	cifsInodeInfo->openFileList	cifs_alloc_inode
 | 
				
			||||||
 * cifsInodeInfo->writers_lock	cifsInodeInfo->writers		cifsInodeInfo_alloc
 | 
					 * cifsInodeInfo->writers_lock	cifsInodeInfo->writers		cifsInodeInfo_alloc
 | 
				
			||||||
 * cifsInodeInfo->lock_sem	cifsInodeInfo->llist		cifs_init_once
 | 
					 * cifsInodeInfo->lock_sem	cifsInodeInfo->llist		cifs_init_once
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2916,16 +2916,32 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to)
 | 
				
			||||||
	 * We need to hold the sem to be sure nobody modifies lock list
 | 
						 * We need to hold the sem to be sure nobody modifies lock list
 | 
				
			||||||
	 * with a brlock that prevents reading.
 | 
						 * with a brlock that prevents reading.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
						if (iocb->ki_flags & IOCB_DIRECT) {
 | 
				
			||||||
 | 
							rc = netfs_start_io_direct(inode);
 | 
				
			||||||
 | 
							if (rc < 0)
 | 
				
			||||||
 | 
								goto out;
 | 
				
			||||||
		down_read(&cinode->lock_sem);
 | 
							down_read(&cinode->lock_sem);
 | 
				
			||||||
	if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(to),
 | 
							if (!cifs_find_lock_conflict(
 | 
				
			||||||
 | 
								    cfile, iocb->ki_pos, iov_iter_count(to),
 | 
				
			||||||
			    tcon->ses->server->vals->shared_lock_type,
 | 
								    tcon->ses->server->vals->shared_lock_type,
 | 
				
			||||||
				     0, NULL, CIFS_READ_OP)) {
 | 
								    0, NULL, CIFS_READ_OP))
 | 
				
			||||||
		if (iocb->ki_flags & IOCB_DIRECT)
 | 
								rc = netfs_unbuffered_read_iter_locked(iocb, to);
 | 
				
			||||||
			rc = netfs_unbuffered_read_iter(iocb, to);
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			rc = netfs_buffered_read_iter(iocb, to);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
		up_read(&cinode->lock_sem);
 | 
							up_read(&cinode->lock_sem);
 | 
				
			||||||
 | 
							netfs_end_io_direct(inode);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							rc = netfs_start_io_read(inode);
 | 
				
			||||||
 | 
							if (rc < 0)
 | 
				
			||||||
 | 
								goto out;
 | 
				
			||||||
 | 
							down_read(&cinode->lock_sem);
 | 
				
			||||||
 | 
							if (!cifs_find_lock_conflict(
 | 
				
			||||||
 | 
								    cfile, iocb->ki_pos, iov_iter_count(to),
 | 
				
			||||||
 | 
								    tcon->ses->server->vals->shared_lock_type,
 | 
				
			||||||
 | 
								    0, NULL, CIFS_READ_OP))
 | 
				
			||||||
 | 
								rc = filemap_read(iocb, to, 0);
 | 
				
			||||||
 | 
							up_read(&cinode->lock_sem);
 | 
				
			||||||
 | 
							netfs_end_io_read(inode);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -389,6 +389,7 @@ struct netfs_cache_ops {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* High-level read API. */
 | 
					/* High-level read API. */
 | 
				
			||||||
 | 
					ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_iter *iter);
 | 
				
			||||||
ssize_t netfs_unbuffered_read_iter(struct kiocb *iocb, struct iov_iter *iter);
 | 
					ssize_t netfs_unbuffered_read_iter(struct kiocb *iocb, struct iov_iter *iter);
 | 
				
			||||||
ssize_t netfs_buffered_read_iter(struct kiocb *iocb, struct iov_iter *iter);
 | 
					ssize_t netfs_buffered_read_iter(struct kiocb *iocb, struct iov_iter *iter);
 | 
				
			||||||
ssize_t netfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter);
 | 
					ssize_t netfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue