loop: open code the direct I/O flag update in loop_set_dio
authorChristoph Hellwig <hch@lst.de>
Fri, 10 Jan 2025 07:37:35 +0000 (08:37 +0100)
committerJens Axboe <axboe@kernel.dk>
Fri, 10 Jan 2025 14:31:50 +0000 (07:31 -0700)
loop_set_dio is different from the other (__)loop_update_dio callers in
that it doesn't take any implicit conditions into account and wants to
update the direct I/O flag to the user passed in value and fail if that
can't be done.

Open code the logic here to prepare for simplifying the other direct I/O
flag updates and to make the error handling less convoluted.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20250110073750.1582447-6-hch@lst.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/block/loop.c

index cf80cdf5e440afe26cbd666ca45a1fc0c1798bdd..6eb6d901151c191831aed19afe12bdc757f06400 100644 (file)
@@ -1455,16 +1455,28 @@ static int loop_set_capacity(struct loop_device *lo)
 
 static int loop_set_dio(struct loop_device *lo, unsigned long arg)
 {
-       int error = -ENXIO;
-       if (lo->lo_state != Lo_bound)
-               goto out;
+       bool use_dio = !!arg;
 
-       __loop_update_dio(lo, !!arg);
-       if (lo->use_dio == !!arg)
+       if (lo->lo_state != Lo_bound)
+               return -ENXIO;
+       if (use_dio == lo->use_dio)
                return 0;
-       error = -EINVAL;
- out:
-       return error;
+
+       if (use_dio) {
+               if (!lo_can_use_dio(lo))
+                       return -EINVAL;
+               /* flush dirty pages before starting to use direct I/O */
+               vfs_fsync(lo->lo_backing_file, 0);
+       }
+
+       blk_mq_freeze_queue(lo->lo_queue);
+       lo->use_dio = use_dio;
+       if (use_dio)
+               lo->lo_flags |= LO_FLAGS_DIRECT_IO;
+       else
+               lo->lo_flags &= ~LO_FLAGS_DIRECT_IO;
+       blk_mq_unfreeze_queue(lo->lo_queue);
+       return 0;
 }
 
 static int loop_set_block_size(struct loop_device *lo, unsigned long arg)