cifs: Fix locking in cifs_strict_readv()
authorSteve French <stfrench@microsoft.com>
Mon, 13 May 2024 22:02:05 +0000 (17:02 -0500)
committerSteve French <stfrench@microsoft.com>
Mon, 13 May 2024 22:02:05 +0000 (17:02 -0500)
Fix to take the i_rwsem (through the netfs locking wrappers) before taking
cinode->lock_sem.

Fixes: 3ee1a1fc3981 ("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>
fs/netfs/direct_read.c
fs/smb/client/cifsglob.h
fs/smb/client/file.c
include/linux/netfs.h

index ad4370b3935d6ee1678e82f05926b990f05edc1d..10a1e4da6bda5c59c66199f8473825f97a46bcff 100644 (file)
@@ -26,7 +26,7 @@
  *
  * 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;
        ssize_t ret;
@@ -98,6 +98,7 @@ out:
                iov_iter_revert(iter, orig_count - iov_iter_count(iter));
        return ret;
 }
+EXPORT_SYMBOL(netfs_unbuffered_read_iter_locked);
 
 /**
  * netfs_unbuffered_read_iter - Perform an unbuffered or direct I/O read
index 65574e69ba4f9094f8bc871adedb9311498bc9e9..73482734a8d8e9523940b8d0e791320edc6b6863 100644 (file)
@@ -1995,6 +1995,7 @@ require use of the stronger protocol */
  *                             ->chans_need_reconnect
  *                             ->chans_in_reconnect
  * 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->writers_lock cifsInodeInfo->writers          cifsInodeInfo_alloc
  * cifsInodeInfo->lock_sem     cifsInodeInfo->llist            cifs_init_once
index 4c981ce89f8a7d0dc534076b7f18ebdc2a5b6ce5..9d38294a7e68002e348ee57a8a005c02d83c0955 100644 (file)
@@ -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
         * with a brlock that prevents reading.
         */
-       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)) {
-               if (iocb->ki_flags & IOCB_DIRECT)
-                       rc = netfs_unbuffered_read_iter(iocb, to);
-               else
-                       rc = netfs_buffered_read_iter(iocb, to);
+       if (iocb->ki_flags & IOCB_DIRECT) {
+               rc = netfs_start_io_direct(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 = netfs_unbuffered_read_iter_locked(iocb, to);
+               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);
        }
-       up_read(&cinode->lock_sem);
+out:
        return rc;
 }
 
index f45d06284f2f841c0ec91240689190821010b72c..ca56a4428043d58392954fbfbedd43178cde7a74 100644 (file)
@@ -389,6 +389,7 @@ struct netfs_cache_ops {
 };
 
 /* 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_buffered_read_iter(struct kiocb *iocb, struct iov_iter *iter);
 ssize_t netfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter);