Re: [PATCH v4 09/10] loop: Clean up LOOP_SET_STATUS lo_flags handling.

2020-05-06 Thread Christoph Hellwig
On Wed, Apr 29, 2020 at 04:03:40PM +0200, Martijn Coenen wrote:
> LOOP_SET_STATUS(64) will actually allow some lo_flags to be modified; in
> particular, LO_FLAGS_AUTOCLEAR can be set and cleared, whereas
> LO_FLAGS_PARTSCAN can be set to request a partition scan. Make this
> explicit by updating the UAPI to include the flags that can be
> set/cleared using this ioctl.
> 
> The implementation can then blindly take over the passed in flags,
> and use the previous flags for those flags that can't be set / cleared
> using LOOP_SET_STATUS.

Looks good,

Reviewed-by: Christoph Hellwig 


[PATCH v4 09/10] loop: Clean up LOOP_SET_STATUS lo_flags handling.

2020-04-29 Thread Martijn Coenen
LOOP_SET_STATUS(64) will actually allow some lo_flags to be modified; in
particular, LO_FLAGS_AUTOCLEAR can be set and cleared, whereas
LO_FLAGS_PARTSCAN can be set to request a partition scan. Make this
explicit by updating the UAPI to include the flags that can be
set/cleared using this ioctl.

The implementation can then blindly take over the passed in flags,
and use the previous flags for those flags that can't be set / cleared
using LOOP_SET_STATUS.

Signed-off-by: Martijn Coenen 
---
 drivers/block/loop.c  | 19 +--
 include/uapi/linux/loop.h | 10 --
 2 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index f172a64333aa..cfbdd99fdb1a 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1049,9 +1049,7 @@ loop_set_status_from_info(struct loop_device *lo,
lo->transfer = xfer->transfer;
lo->ioctl = xfer->ioctl;
 
-   if ((lo->lo_flags & LO_FLAGS_AUTOCLEAR) !=
-(info->lo_flags & LO_FLAGS_AUTOCLEAR))
-   lo->lo_flags ^= LO_FLAGS_AUTOCLEAR;
+   lo->lo_flags = info->lo_flags;
 
lo->lo_encrypt_key_size = info->lo_encrypt_key_size;
lo->lo_init[0] = info->lo_init[0];
@@ -1338,6 +1336,7 @@ loop_set_status(struct loop_device *lo, const struct 
loop_info64 *info)
int err;
struct block_device *bdev;
kuid_t uid = current_uid();
+   int prev_lo_flags;
bool partscan = false;
bool size_changed = false;
loff_t validated_size;
@@ -1381,10 +1380,19 @@ loop_set_status(struct loop_device *lo, const struct 
loop_info64 *info)
goto out_unfreeze;
}
 
+   prev_lo_flags = lo->lo_flags;
+
err = loop_set_status_from_info(lo, info);
if (err)
goto out_unfreeze;
 
+   /* Mask out flags that can't be set using LOOP_SET_STATUS. */
+   lo->lo_flags &= ~LOOP_SET_STATUS_SETTABLE_FLAGS;
+   /* For those flags, use the previous values instead */
+   lo->lo_flags |= prev_lo_flags & ~LOOP_SET_STATUS_SETTABLE_FLAGS;
+   /* For flags that can't be cleared, use previous values too */
+   lo->lo_flags |= prev_lo_flags & ~LOOP_SET_STATUS_CLEARABLE_FLAGS;
+
if (size_changed)
loop_set_size(lo, validated_size);
 
@@ -1396,9 +1404,8 @@ loop_set_status(struct loop_device *lo, const struct 
loop_info64 *info)
 out_unfreeze:
blk_mq_unfreeze_queue(lo->lo_queue);
 
-   if (!err && (info->lo_flags & LO_FLAGS_PARTSCAN) &&
-!(lo->lo_flags & LO_FLAGS_PARTSCAN)) {
-   lo->lo_flags |= LO_FLAGS_PARTSCAN;
+   if (!err && (lo->lo_flags & LO_FLAGS_PARTSCAN) &&
+!(prev_lo_flags & LO_FLAGS_PARTSCAN)) {
lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN;
bdev = lo->lo_device;
partscan = true;
diff --git a/include/uapi/linux/loop.h b/include/uapi/linux/loop.h
index 080a8df134ef..6b32fee80ce0 100644
--- a/include/uapi/linux/loop.h
+++ b/include/uapi/linux/loop.h
@@ -25,6 +25,12 @@ enum {
LO_FLAGS_DIRECT_IO  = 16,
 };
 
+/* LO_FLAGS that can be set using LOOP_SET_STATUS(64) */
+#define LOOP_SET_STATUS_SETTABLE_FLAGS (LO_FLAGS_AUTOCLEAR | LO_FLAGS_PARTSCAN)
+
+/* LO_FLAGS that can be cleared using LOOP_SET_STATUS(64) */
+#define LOOP_SET_STATUS_CLEARABLE_FLAGS (LO_FLAGS_AUTOCLEAR)
+
 #include/* for __kernel_old_dev_t */
 #include/* for __u64 */
 
@@ -37,7 +43,7 @@ struct loop_info {
intlo_offset;
intlo_encrypt_type;
intlo_encrypt_key_size; /* ioctl w/o */
-   intlo_flags;/* ioctl r/o */
+   intlo_flags;
char   lo_name[LO_NAME_SIZE];
unsigned char  lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
unsigned long  lo_init[2];
@@ -53,7 +59,7 @@ struct loop_info64 {
__u32  lo_number;   /* ioctl r/o */
__u32  lo_encrypt_type;
__u32  lo_encrypt_key_size; /* ioctl w/o */
-   __u32  lo_flags;/* ioctl r/o */
+   __u32  lo_flags;
__u8   lo_file_name[LO_NAME_SIZE];
__u8   lo_crypt_name[LO_NAME_SIZE];
__u8   lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
-- 
2.26.2.303.gf8c07b1a785-goog