Skip to content

Commit 14b1cd2

Browse files
author
Steve French
committed
cifs: Fix locking in cifs_strict_readv()
Fix to take the i_rwsem (through the netfs locking wrappers) before taking cinode->lock_sem. Fixes: 3ee1a1f ("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>
1 parent 29b4c7b commit 14b1cd2

File tree

4 files changed

+29
-10
lines changed

4 files changed

+29
-10
lines changed

fs/netfs/direct_read.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*
2727
* The caller must hold any appropriate locks.
2828
*/
29-
static ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_iter *iter)
29+
ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_iter *iter)
3030
{
3131
struct netfs_io_request *rreq;
3232
ssize_t ret;
@@ -98,6 +98,7 @@ static ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_
9898
iov_iter_revert(iter, orig_count - iov_iter_count(iter));
9999
return ret;
100100
}
101+
EXPORT_SYMBOL(netfs_unbuffered_read_iter_locked);
101102

102103
/**
103104
* netfs_unbuffered_read_iter - Perform an unbuffered or direct I/O read

fs/smb/client/cifsglob.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1995,6 +1995,7 @@ require use of the stronger protocol */
19951995
* ->chans_need_reconnect
19961996
* ->chans_in_reconnect
19971997
* cifs_tcon->tc_lock (anything that is not protected by another lock and can change)
1998+
* inode->i_rwsem, taken by fs/netfs/locking.c e.g. should be taken before cifsInodeInfo locks
19981999
* cifsInodeInfo->open_file_lock cifsInodeInfo->openFileList cifs_alloc_inode
19992000
* cifsInodeInfo->writers_lock cifsInodeInfo->writers cifsInodeInfo_alloc
20002001
* cifsInodeInfo->lock_sem cifsInodeInfo->llist cifs_init_once

fs/smb/client/file.c

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2916,16 +2916,32 @@ cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to)
29162916
* We need to hold the sem to be sure nobody modifies lock list
29172917
* with a brlock that prevents reading.
29182918
*/
2919-
down_read(&cinode->lock_sem);
2920-
if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(to),
2921-
tcon->ses->server->vals->shared_lock_type,
2922-
0, NULL, CIFS_READ_OP)) {
2923-
if (iocb->ki_flags & IOCB_DIRECT)
2924-
rc = netfs_unbuffered_read_iter(iocb, to);
2925-
else
2926-
rc = netfs_buffered_read_iter(iocb, to);
2919+
if (iocb->ki_flags & IOCB_DIRECT) {
2920+
rc = netfs_start_io_direct(inode);
2921+
if (rc < 0)
2922+
goto out;
2923+
down_read(&cinode->lock_sem);
2924+
if (!cifs_find_lock_conflict(
2925+
cfile, iocb->ki_pos, iov_iter_count(to),
2926+
tcon->ses->server->vals->shared_lock_type,
2927+
0, NULL, CIFS_READ_OP))
2928+
rc = netfs_unbuffered_read_iter_locked(iocb, to);
2929+
up_read(&cinode->lock_sem);
2930+
netfs_end_io_direct(inode);
2931+
} else {
2932+
rc = netfs_start_io_read(inode);
2933+
if (rc < 0)
2934+
goto out;
2935+
down_read(&cinode->lock_sem);
2936+
if (!cifs_find_lock_conflict(
2937+
cfile, iocb->ki_pos, iov_iter_count(to),
2938+
tcon->ses->server->vals->shared_lock_type,
2939+
0, NULL, CIFS_READ_OP))
2940+
rc = filemap_read(iocb, to, 0);
2941+
up_read(&cinode->lock_sem);
2942+
netfs_end_io_read(inode);
29272943
}
2928-
up_read(&cinode->lock_sem);
2944+
out:
29292945
return rc;
29302946
}
29312947

include/linux/netfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ struct netfs_cache_ops {
389389
};
390390

391391
/* High-level read API. */
392+
ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_iter *iter);
392393
ssize_t netfs_unbuffered_read_iter(struct kiocb *iocb, struct iov_iter *iter);
393394
ssize_t netfs_buffered_read_iter(struct kiocb *iocb, struct iov_iter *iter);
394395
ssize_t netfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter);

0 commit comments

Comments
 (0)