Merge tag 'for-6.8/block-2024-01-18' of git://git.kernel.dk/linux
[linux-2.6-microblaze.git] / drivers / block / loop.c
index 146b32f..f814549 100644 (file)
@@ -165,39 +165,37 @@ static loff_t get_loop_size(struct loop_device *lo, struct file *file)
        return get_size(lo->lo_offset, lo->lo_sizelimit, file);
 }
 
+/*
+ * We support direct I/O only if lo_offset is aligned with the logical I/O size
+ * of backing device, and the logical block size of loop is bigger than that of
+ * the backing device.
+ */
+static bool lo_bdev_can_use_dio(struct loop_device *lo,
+               struct block_device *backing_bdev)
+{
+       unsigned short sb_bsize = bdev_logical_block_size(backing_bdev);
+
+       if (queue_logical_block_size(lo->lo_queue) < sb_bsize)
+               return false;
+       if (lo->lo_offset & (sb_bsize - 1))
+               return false;
+       return true;
+}
+
 static void __loop_update_dio(struct loop_device *lo, bool dio)
 {
        struct file *file = lo->lo_backing_file;
-       struct address_space *mapping = file->f_mapping;
-       struct inode *inode = mapping->host;
-       unsigned short sb_bsize = 0;
-       unsigned dio_align = 0;
+       struct inode *inode = file->f_mapping->host;
+       struct block_device *backing_bdev = NULL;
        bool use_dio;
 
-       if (inode->i_sb->s_bdev) {
-               sb_bsize = bdev_logical_block_size(inode->i_sb->s_bdev);
-               dio_align = sb_bsize - 1;
-       }
+       if (S_ISBLK(inode->i_mode))
+               backing_bdev = I_BDEV(inode);
+       else if (inode->i_sb->s_bdev)
+               backing_bdev = inode->i_sb->s_bdev;
 
-       /*
-        * We support direct I/O only if lo_offset is aligned with the
-        * logical I/O size of backing device, and the logical block
-        * size of loop is bigger than the backing device's.
-        *
-        * TODO: the above condition may be loosed in the future, and
-        * direct I/O may be switched runtime at that time because most
-        * of requests in sane applications should be PAGE_SIZE aligned
-        */
-       if (dio) {
-               if (queue_logical_block_size(lo->lo_queue) >= sb_bsize &&
-                   !(lo->lo_offset & dio_align) &&
-                   (file->f_mode & FMODE_CAN_ODIRECT))
-                       use_dio = true;
-               else
-                       use_dio = false;
-       } else {
-               use_dio = false;
-       }
+       use_dio = dio && (file->f_mode & FMODE_CAN_ODIRECT) &&
+               (!backing_bdev || lo_bdev_can_use_dio(lo, backing_bdev));
 
        if (lo->use_dio == use_dio)
                return;