v1->v2: 1) Replace BLK_DEV_DUMPINFO with BLK_DEV_WRITE_MOUNTED_QUIET, which is logically opposite; 2) Make BLK_DEV_WRITE_MOUNTED_QUIET dependent on BLK_DEV_WRITE_MOUNTED, and decide whether to set bd_writers by BLK_DEV_WRITE_MOUNTED_QUIET; 3) Move bdev_dump_info() into bdev_may_open(); 4) Add the cmdline interface to control whether to show info; 5) Pass the state of "writes blocked" to part0 when mounting a partition. v2->v3: Add restriction for modifying bd_writers. v3->v4: 1) Count bd_writers regardless of whether bdev_allow_write_mounted is set; 2) Expand the meaning of bdev_allow_write_mounted; 3) Add config option to detect writing to part0 while partitions mounted; 4) Add bd_mounters to record the number of times that part0 or partition is mounted; 5) Show info about opening a lower device for write while upper-layers mounted. v4->v5: Move introduction of bd_mounters to patch1.
Li Lingfeng (5): block: Count writers and mounters regardless of whether bdev_allow_write_mounted is set block: Expand the meaning of bdev_allow_write_mounted block: Add config option to detect writing to part0 while partitions mounted block: Add config option to show info about opening a mounted device for write block: Show info about opening a lower device for write while upper-layers mounted
block/Kconfig | 19 ++++++++ block/bdev.c | 100 +++++++++++++++++++++++++++++++++----- include/linux/blk_types.h | 1 + 3 files changed, 107 insertions(+), 13 deletions(-)
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S3GW CVE: NA
---------------------------
Introduce bd_mounters to record the num of mount. The count of bd_writers and bd_mounters can have other uses and they doesn't block writes when bdev_allow_write_mounted is not set, so remove the restriction for counting them.
Signed-off-by: Li Lingfeng lilingfeng3@huawei.com --- block/bdev.c | 19 +++++++++---------- include/linux/blk_types.h | 1 + 2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/block/bdev.c b/block/bdev.c index dd39c26c44ad..715428eb6621 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -735,17 +735,22 @@ void blkdev_put_no_open(struct block_device *bdev)
static bool bdev_writes_blocked(struct block_device *bdev) { - return bdev->bd_writers == -1; + return !!bdev->bd_mounters; }
static void bdev_block_writes(struct block_device *bdev) { - bdev->bd_writers = -1; + bdev->bd_mounters++; }
static void bdev_unblock_writes(struct block_device *bdev) { - bdev->bd_writers = 0; + bdev->bd_mounters--; +} + +static bool bdev_mount_blocked(struct block_device *bdev) +{ + return bdev->bd_writers > 0; }
static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode) @@ -755,16 +760,13 @@ static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode) /* Writes blocked? */ if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) return false; - if (mode & BLK_OPEN_RESTRICT_WRITES && bdev->bd_writers > 0) + if (mode & BLK_OPEN_RESTRICT_WRITES && bdev_mount_blocked(bdev)) return false; return true; }
static void bdev_claim_write_access(struct block_device *bdev, blk_mode_t mode) { - if (bdev_allow_write_mounted) - return; - /* Claim exclusive or shared write access. */ if (mode & BLK_OPEN_RESTRICT_WRITES) bdev_block_writes(bdev); @@ -774,9 +776,6 @@ static void bdev_claim_write_access(struct block_device *bdev, blk_mode_t mode)
static void bdev_yield_write_access(struct block_device *bdev, blk_mode_t mode) { - if (bdev_allow_write_mounted) - return; - /* Yield exclusive or shared write access. */ if (mode & BLK_OPEN_RESTRICT_WRITES) bdev_unblock_writes(bdev); diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 262ae789726b..0e1e429d3f74 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -70,6 +70,7 @@ struct block_device { bool bd_make_it_fail; #endif int bd_writers; + int bd_mounters; /* * keep this out-of-line as it's both big and not needed in the fast * path
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S3GW CVE: NA
---------------------------
For bdev_allow_write_mounted, there will be more subdivided scenarios and different bits of it will be used to indicate different scenarios, so expand it now.
Signed-off-by: Li Lingfeng lilingfeng3@huawei.com --- block/bdev.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/block/bdev.c b/block/bdev.c index 715428eb6621..8998c93a0814 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -31,7 +31,10 @@ #include "blk.h"
/* Should we allow writing to mounted block devices? */ -static bool bdev_allow_write_mounted = IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED); +#define BLKDEV_ALLOW_WRITE_MOUNTED 0 + +static u8 bdev_allow_write_mounted = + IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED) << BLKDEV_ALLOW_WRITE_MOUNTED;
struct bdev_inode { struct block_device bdev; @@ -755,7 +758,7 @@ static bool bdev_mount_blocked(struct block_device *bdev)
static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode) { - if (bdev_allow_write_mounted) + if (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED)) return true; /* Writes blocked? */ if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) @@ -1134,7 +1137,7 @@ void bdev_statx_dioalign(struct inode *inode, struct kstat *stat)
static int __init setup_bdev_allow_write_mounted(char *str) { - if (kstrtobool(str, &bdev_allow_write_mounted)) + if (kstrtou8(str, 0, &bdev_allow_write_mounted)) pr_warn("Invalid option string for bdev_allow_write_mounted:" " '%s'\n", str); return 1;
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S3GW CVE: NA
---------------------------
When a partition of a block device is mounted, opening the entire block device for write operations may also damage the file system. Identify this situation.
Signed-off-by: Li Lingfeng lilingfeng3@huawei.com --- block/Kconfig | 10 ++++++++++ block/bdev.c | 13 ++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/block/Kconfig b/block/Kconfig index 03b53a50939f..05fdd81a708f 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -239,6 +239,16 @@ config BLK_INLINE_ENCRYPTION_FALLBACK by falling back to the kernel crypto API when inline encryption hardware is not present.
+config BLK_DEV_DETECT_WRITING_PART0 + bool "Detect writing to part0 when partitions mounted" + default n + help + When partitions of a block device are mounted, writing to part0's + buffer cache is likely going to cause filesystem corruption on + each partition. + As a supplement to BLK_DEV_WRITE_MOUNTED(_QUIET), enabling this + to detect the scenario above. + source "block/partitions/Kconfig"
config BLK_MQ_PCI diff --git a/block/bdev.c b/block/bdev.c index 8998c93a0814..4b0e6c49a9e7 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -32,9 +32,12 @@
/* Should we allow writing to mounted block devices? */ #define BLKDEV_ALLOW_WRITE_MOUNTED 0 +/* Should we detect writing to part0 when partitions mounted */ +#define BLKDEV_DETECT_WRITING_PART0 1
static u8 bdev_allow_write_mounted = - IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED) << BLKDEV_ALLOW_WRITE_MOUNTED; + IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED) << BLKDEV_ALLOW_WRITE_MOUNTED || + IS_ENABLED(CONFIG_BLK_DEV_DETECT_WRITING_PART0) << BLKDEV_DETECT_WRITING_PART0;
struct bdev_inode { struct block_device bdev; @@ -744,15 +747,23 @@ static bool bdev_writes_blocked(struct block_device *bdev) static void bdev_block_writes(struct block_device *bdev) { bdev->bd_mounters++; + if (bdev_is_partition(bdev) && + bdev_allow_write_mounted & (1 << BLKDEV_DETECT_WRITING_PART0)) + bdev_whole(bdev)->bd_mounters++; }
static void bdev_unblock_writes(struct block_device *bdev) { bdev->bd_mounters--; + if (bdev_is_partition(bdev) && + bdev_allow_write_mounted & (1 << BLKDEV_DETECT_WRITING_PART0)) + bdev_whole(bdev)->bd_mounters--; }
static bool bdev_mount_blocked(struct block_device *bdev) { + if (bdev_allow_write_mounted & (1 << BLKDEV_DETECT_WRITING_PART0)) + return bdev->bd_writers > 0 || bdev_whole(bdev)->bd_writers > 0; return bdev->bd_writers > 0; }
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S3GW CVE: NA
---------------------------
When writing to a mounted block device is allowed, we need to identify which processes may write to the block device to prevent the file system from being damaged in silence.
Signed-off-by: Li Lingfeng lilingfeng3@huawei.com --- block/Kconfig | 9 +++++++++ block/bdev.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 2 deletions(-)
diff --git a/block/Kconfig b/block/Kconfig index 05fdd81a708f..29065fb2860b 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -249,6 +249,15 @@ config BLK_DEV_DETECT_WRITING_PART0 As a supplement to BLK_DEV_WRITE_MOUNTED(_QUIET), enabling this to detect the scenario above.
+config BLK_DEV_WRITE_MOUNTED_QUIET + bool "Keep quiet when detecting conflict of opening block device" + default y + depends on BLK_DEV_WRITE_MOUNTED + help + While writing to mounted block devices is allowed, disabling this + to dump info when opening mounted block devices for write or + trying to mount write opened block devices. + source "block/partitions/Kconfig"
config BLK_MQ_PCI diff --git a/block/bdev.c b/block/bdev.c index 4b0e6c49a9e7..720b01b4cb45 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -34,10 +34,13 @@ #define BLKDEV_ALLOW_WRITE_MOUNTED 0 /* Should we detect writing to part0 when partitions mounted */ #define BLKDEV_DETECT_WRITING_PART0 1 +/* Should we keep quiet when opening mounted block devices for write? */ +#define BLKDEV_WRITE_MOUNTED_QUIET 2
static u8 bdev_allow_write_mounted = IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED) << BLKDEV_ALLOW_WRITE_MOUNTED || - IS_ENABLED(CONFIG_BLK_DEV_DETECT_WRITING_PART0) << BLKDEV_DETECT_WRITING_PART0; + IS_ENABLED(CONFIG_BLK_DEV_DETECT_WRITING_PART0) << BLKDEV_DETECT_WRITING_PART0 || + IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED_QUIET) << BLKDEV_WRITE_MOUNTED_QUIET;
struct bdev_inode { struct block_device bdev; @@ -739,6 +742,27 @@ void blkdev_put_no_open(struct block_device *bdev) put_device(&bdev->bd_device); }
+static void blkdev_dump_conflict_opener(struct block_device *bdev, char *msg) +{ + char name[BDEVNAME_SIZE]; + struct task_struct *p = NULL; + char comm_buf[TASK_COMM_LEN]; + pid_t p_pid; + + rcu_read_lock(); + p = rcu_dereference(current->real_parent); + task_lock(p); + strncpy(comm_buf, p->comm, TASK_COMM_LEN); + p_pid = p->pid; + task_unlock(p); + rcu_read_unlock(); + + snprintf(name, sizeof(name), "%pg", bdev); + pr_info_ratelimited("%s [%s]. current [%d %s]. parent [%d %s]\n", + msg, name, + current->pid, current->comm, p_pid, comm_buf); +} + static bool bdev_writes_blocked(struct block_device *bdev) { return !!bdev->bd_mounters; @@ -767,10 +791,25 @@ static bool bdev_mount_blocked(struct block_device *bdev) return bdev->bd_writers > 0; }
+static void bdev_dump_info(struct block_device *bdev, blk_mode_t mode) +{ + if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET)) + return; + + if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) + blkdev_dump_conflict_opener(bdev, "VFS: Open an exclusive opened " + "block device for write"); + else if (mode & BLK_OPEN_RESTRICT_WRITES && bdev_mount_blocked(bdev)) + blkdev_dump_conflict_opener(bdev, "VFS: Open a write opened " + "block device exclusively"); +} + static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode) { - if (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED)) + if (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED)) { + bdev_dump_info(bdev, mode); return true; + } /* Writes blocked? */ if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) return false; @@ -1151,6 +1190,19 @@ static int __init setup_bdev_allow_write_mounted(char *str) if (kstrtou8(str, 0, &bdev_allow_write_mounted)) pr_warn("Invalid option string for bdev_allow_write_mounted:" " '%s'\n", str); + /* + * It's meaningless to set BLKDEV_WRITE_MOUNTED_QUIET if + * BLKDEV_ALLOW_WRITE_MOUNTED is not set. + */ + if (!(bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED))) { + if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET)) { + pr_warn("Invalid value for bdev_allow_write_mounted:" + " '%d', it should be set as 0/1/2/3/5/7\n", + bdev_allow_write_mounted); + bdev_allow_write_mounted &= ~(1 << BLKDEV_WRITE_MOUNTED_QUIET); + } + } + return 1; } __setup("bdev_allow_write_mounted=", setup_bdev_allow_write_mounted);
Hi,
在 2024/01/09 10:19, Li Lingfeng 写道:
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S3GW CVE: NA
When writing to a mounted block device is allowed, we need to identify which processes may write to the block device to prevent the file system from being damaged in silence.
Signed-off-by: Li Lingfeng lilingfeng3@huawei.com
block/Kconfig | 9 +++++++++ block/bdev.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 2 deletions(-)
diff --git a/block/Kconfig b/block/Kconfig index 05fdd81a708f..29065fb2860b 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -249,6 +249,15 @@ config BLK_DEV_DETECT_WRITING_PART0 As a supplement to BLK_DEV_WRITE_MOUNTED(_QUIET), enabling this to detect the scenario above.
+config BLK_DEV_WRITE_MOUNTED_QUIET
bool "Keep quiet when detecting conflict of opening block device"
default y
depends on BLK_DEV_WRITE_MOUNTED
help
While writing to mounted block devices is allowed, disabling this
to dump info when opening mounted block devices for write or
trying to mount write opened block devices.
source "block/partitions/Kconfig"
config BLK_MQ_PCI
diff --git a/block/bdev.c b/block/bdev.c index 4b0e6c49a9e7..720b01b4cb45 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -34,10 +34,13 @@ #define BLKDEV_ALLOW_WRITE_MOUNTED 0 /* Should we detect writing to part0 when partitions mounted */ #define BLKDEV_DETECT_WRITING_PART0 1 +/* Should we keep quiet when opening mounted block devices for write? */ +#define BLKDEV_WRITE_MOUNTED_QUIET 2
static u8 bdev_allow_write_mounted = IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED) << BLKDEV_ALLOW_WRITE_MOUNTED ||
- IS_ENABLED(CONFIG_BLK_DEV_DETECT_WRITING_PART0) << BLKDEV_DETECT_WRITING_PART0;
IS_ENABLED(CONFIG_BLK_DEV_DETECT_WRITING_PART0) << BLKDEV_DETECT_WRITING_PART0 ||
IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED_QUIET) << BLKDEV_WRITE_MOUNTED_QUIET;
struct bdev_inode { struct block_device bdev;
@@ -739,6 +742,27 @@ void blkdev_put_no_open(struct block_device *bdev) put_device(&bdev->bd_device); }
+static void blkdev_dump_conflict_opener(struct block_device *bdev, char *msg) +{
- char name[BDEVNAME_SIZE];
- struct task_struct *p = NULL;
- char comm_buf[TASK_COMM_LEN];
- pid_t p_pid;
- rcu_read_lock();
- p = rcu_dereference(current->real_parent);
- task_lock(p);
- strncpy(comm_buf, p->comm, TASK_COMM_LEN);
- p_pid = p->pid;
- task_unlock(p);
- rcu_read_unlock();
- snprintf(name, sizeof(name), "%pg", bdev);
- pr_info_ratelimited("%s [%s]. current [%d %s]. parent [%d %s]\n",
msg, name,
current->pid, current->comm, p_pid, comm_buf);
+}
- static bool bdev_writes_blocked(struct block_device *bdev) { return !!bdev->bd_mounters;
@@ -767,10 +791,25 @@ static bool bdev_mount_blocked(struct block_device *bdev) return bdev->bd_writers > 0; }
+static void bdev_dump_info(struct block_device *bdev, blk_mode_t mode) +{
- if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET))
return;
- if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev))
blkdev_dump_conflict_opener(bdev, "VFS: Open an exclusive opened "
"block device for write");
- else if (mode & BLK_OPEN_RESTRICT_WRITES && bdev_mount_blocked(bdev))
blkdev_dump_conflict_opener(bdev, "VFS: Open a write opened "
"block device exclusively");
+}
bdev_dump_info() looks like the same as bdev_may_open(), how about:
bdev_may_open() { bool blocked = false;
if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET)) return true;
if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) { blocked = true; bdev_dump... } else is (else if (mode & BLK_OPEN_RESTRICT_WRITES && bdev_mount_blocked(bdev))) { blocked = true; bdev_dump... }
return !blocked || (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED); }
- static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode) {
- if (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED))
- if (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED)) {
return true;bdev_dump_info(bdev, mode);
- } /* Writes blocked? */ if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) return false;
@@ -1151,6 +1190,19 @@ static int __init setup_bdev_allow_write_mounted(char *str) if (kstrtou8(str, 0, &bdev_allow_write_mounted)) pr_warn("Invalid option string for bdev_allow_write_mounted:" " '%s'\n", str);
- /*
* It's meaningless to set BLKDEV_WRITE_MOUNTED_QUIET if
* BLKDEV_ALLOW_WRITE_MOUNTED is not set.
*/
- if (!(bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED))) {
if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET)) {
pr_warn("Invalid value for bdev_allow_write_mounted:"
" '%d', it should be set as 0/1/2/3/5/7\n",
bdev_allow_write_mounted);
bdev_allow_write_mounted &= ~(1 << BLKDEV_WRITE_MOUNTED_QUIET);
}
- }
- return 1; } __setup("bdev_allow_write_mounted=", setup_bdev_allow_write_mounted);
Hi,
在 2024/01/09 10:46, Yu Kuai 写道:
Hi,
在 2024/01/09 10:19, Li Lingfeng 写道:
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S3GW CVE: NA
When writing to a mounted block device is allowed, we need to identify which processes may write to the block device to prevent the file system from being damaged in silence.
Signed-off-by: Li Lingfeng lilingfeng3@huawei.com
block/Kconfig | 9 +++++++++ block/bdev.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 2 deletions(-)
diff --git a/block/Kconfig b/block/Kconfig index 05fdd81a708f..29065fb2860b 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -249,6 +249,15 @@ config BLK_DEV_DETECT_WRITING_PART0 As a supplement to BLK_DEV_WRITE_MOUNTED(_QUIET), enabling this to detect the scenario above. +config BLK_DEV_WRITE_MOUNTED_QUIET + bool "Keep quiet when detecting conflict of opening block device" + default y + depends on BLK_DEV_WRITE_MOUNTED + help + While writing to mounted block devices is allowed, disabling this + to dump info when opening mounted block devices for write or + trying to mount write opened block devices.
source "block/partitions/Kconfig" config BLK_MQ_PCI diff --git a/block/bdev.c b/block/bdev.c index 4b0e6c49a9e7..720b01b4cb45 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -34,10 +34,13 @@ #define BLKDEV_ALLOW_WRITE_MOUNTED 0 /* Should we detect writing to part0 when partitions mounted */ #define BLKDEV_DETECT_WRITING_PART0 1 +/* Should we keep quiet when opening mounted block devices for write? */ +#define BLKDEV_WRITE_MOUNTED_QUIET 2 static u8 bdev_allow_write_mounted = IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED) << BLKDEV_ALLOW_WRITE_MOUNTED || - IS_ENABLED(CONFIG_BLK_DEV_DETECT_WRITING_PART0) << BLKDEV_DETECT_WRITING_PART0; + IS_ENABLED(CONFIG_BLK_DEV_DETECT_WRITING_PART0) << BLKDEV_DETECT_WRITING_PART0 || + IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED_QUIET) << BLKDEV_WRITE_MOUNTED_QUIET; struct bdev_inode { struct block_device bdev; @@ -739,6 +742,27 @@ void blkdev_put_no_open(struct block_device *bdev) put_device(&bdev->bd_device); } +static void blkdev_dump_conflict_opener(struct block_device *bdev, char *msg) +{ + char name[BDEVNAME_SIZE]; + struct task_struct *p = NULL; + char comm_buf[TASK_COMM_LEN]; + pid_t p_pid;
+ rcu_read_lock(); + p = rcu_dereference(current->real_parent); + task_lock(p); + strncpy(comm_buf, p->comm, TASK_COMM_LEN); + p_pid = p->pid; + task_unlock(p); + rcu_read_unlock();
+ snprintf(name, sizeof(name), "%pg", bdev); + pr_info_ratelimited("%s [%s]. current [%d %s]. parent [%d %s]\n", + msg, name, + current->pid, current->comm, p_pid, comm_buf); +}
static bool bdev_writes_blocked(struct block_device *bdev) { return !!bdev->bd_mounters; @@ -767,10 +791,25 @@ static bool bdev_mount_blocked(struct block_device *bdev) return bdev->bd_writers > 0; } +static void bdev_dump_info(struct block_device *bdev, blk_mode_t mode) +{ + if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET)) + return;
+ if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) + blkdev_dump_conflict_opener(bdev, "VFS: Open an exclusive opened " + "block device for write"); + else if (mode & BLK_OPEN_RESTRICT_WRITES && bdev_mount_blocked(bdev)) + blkdev_dump_conflict_opener(bdev, "VFS: Open a write opened " + "block device exclusively"); +}
bdev_dump_info() looks like the same as bdev_may_open(), how about:
bdev_may_open() { bool blocked = false;
if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET)) return true;
if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) { blocked = true; bdev_dump... } else is (else if (mode & BLK_OPEN_RESTRICT_WRITES && bdev_mount_blocked(bdev))) { blocked = true; bdev_dump... }
return !blocked || (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED); }
Or this is better:
bdev_may_conflict_open() { if (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED)) return true;
// kernel log return false; }
bdev_may_open() { if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET)) return true; if (xxx) return bdev_may_conflict_open(); else if (xxx) return bdev_may_conflict_open(); return true; }
static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode) { - if (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED)) + if (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED)) { + bdev_dump_info(bdev, mode); return true; + } /* Writes blocked? */ if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) return false; @@ -1151,6 +1190,19 @@ static int __init setup_bdev_allow_write_mounted(char *str) if (kstrtou8(str, 0, &bdev_allow_write_mounted)) pr_warn("Invalid option string for bdev_allow_write_mounted:" " '%s'\n", str); + /* + * It's meaningless to set BLKDEV_WRITE_MOUNTED_QUIET if + * BLKDEV_ALLOW_WRITE_MOUNTED is not set. + */ + if (!(bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED))) { + if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET)) { + pr_warn("Invalid value for bdev_allow_write_mounted:" + " '%d', it should be set as 0/1/2/3/5/7\n", + bdev_allow_write_mounted); + bdev_allow_write_mounted &= ~(1 << BLKDEV_WRITE_MOUNTED_QUIET); + } + }
return 1; } __setup("bdev_allow_write_mounted=", setup_bdev_allow_write_mounted);
在 2024/1/9 11:02, Yu Kuai 写道:
Hi,
在 2024/01/09 10:46, Yu Kuai 写道:
Hi,
在 2024/01/09 10:19, Li Lingfeng 写道:
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S3GW CVE: NA
When writing to a mounted block device is allowed, we need to identify which processes may write to the block device to prevent the file system from being damaged in silence.
Signed-off-by: Li Lingfeng lilingfeng3@huawei.com
block/Kconfig | 9 +++++++++ block/bdev.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 2 deletions(-)
diff --git a/block/Kconfig b/block/Kconfig index 05fdd81a708f..29065fb2860b 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -249,6 +249,15 @@ config BLK_DEV_DETECT_WRITING_PART0 As a supplement to BLK_DEV_WRITE_MOUNTED(_QUIET), enabling this to detect the scenario above. +config BLK_DEV_WRITE_MOUNTED_QUIET + bool "Keep quiet when detecting conflict of opening block device" + default y + depends on BLK_DEV_WRITE_MOUNTED + help + While writing to mounted block devices is allowed, disabling this + to dump info when opening mounted block devices for write or + trying to mount write opened block devices.
source "block/partitions/Kconfig" config BLK_MQ_PCI diff --git a/block/bdev.c b/block/bdev.c index 4b0e6c49a9e7..720b01b4cb45 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -34,10 +34,13 @@ #define BLKDEV_ALLOW_WRITE_MOUNTED 0 /* Should we detect writing to part0 when partitions mounted */ #define BLKDEV_DETECT_WRITING_PART0 1 +/* Should we keep quiet when opening mounted block devices for write? */ +#define BLKDEV_WRITE_MOUNTED_QUIET 2 static u8 bdev_allow_write_mounted = IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED) << BLKDEV_ALLOW_WRITE_MOUNTED || - IS_ENABLED(CONFIG_BLK_DEV_DETECT_WRITING_PART0) << BLKDEV_DETECT_WRITING_PART0; + IS_ENABLED(CONFIG_BLK_DEV_DETECT_WRITING_PART0) << BLKDEV_DETECT_WRITING_PART0 || + IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED_QUIET) << BLKDEV_WRITE_MOUNTED_QUIET; struct bdev_inode { struct block_device bdev; @@ -739,6 +742,27 @@ void blkdev_put_no_open(struct block_device *bdev) put_device(&bdev->bd_device); } +static void blkdev_dump_conflict_opener(struct block_device *bdev, char *msg) +{ + char name[BDEVNAME_SIZE]; + struct task_struct *p = NULL; + char comm_buf[TASK_COMM_LEN]; + pid_t p_pid;
+ rcu_read_lock(); + p = rcu_dereference(current->real_parent); + task_lock(p); + strncpy(comm_buf, p->comm, TASK_COMM_LEN); + p_pid = p->pid; + task_unlock(p); + rcu_read_unlock();
+ snprintf(name, sizeof(name), "%pg", bdev); + pr_info_ratelimited("%s [%s]. current [%d %s]. parent [%d %s]\n", + msg, name, + current->pid, current->comm, p_pid, comm_buf); +}
static bool bdev_writes_blocked(struct block_device *bdev) { return !!bdev->bd_mounters; @@ -767,10 +791,25 @@ static bool bdev_mount_blocked(struct block_device *bdev) return bdev->bd_writers > 0; } +static void bdev_dump_info(struct block_device *bdev, blk_mode_t mode) +{ + if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET)) + return;
+ if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) + blkdev_dump_conflict_opener(bdev, "VFS: Open an exclusive opened " + "block device for write"); + else if (mode & BLK_OPEN_RESTRICT_WRITES && bdev_mount_blocked(bdev)) + blkdev_dump_conflict_opener(bdev, "VFS: Open a write opened " + "block device exclusively"); +}
bdev_dump_info() looks like the same as bdev_may_open(), how about:
bdev_may_open() { bool blocked = false;
if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET)) return true;
if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) { blocked = true; bdev_dump... } else is (else if (mode & BLK_OPEN_RESTRICT_WRITES && bdev_mount_blocked(bdev))) { blocked = true; bdev_dump... }
return !blocked || (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED); }
Or this is better:
bdev_may_conflict_open() { if (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED)) return true;
// kernel log return false; }
bdev_may_open() { if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET)) return true; if (xxx) return bdev_may_conflict_open(); else if (xxx) return bdev_may_conflict_open(); return true; }
How about just extract the logic of detection as a function, like this:
u8 bdev_open_conficted() { if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) return 1; if (mode & BLK_OPEN_RESTRICT_WRITES && bdev_mount_blocked(bdev)) return 2; return 0; }
bdev_may_open() { bool blocked; u8 open_conficted;
if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET)) return true;
open_conficted = bdev_open_conficted(); sitch (open_conficted) { case 0: blocked = false; case 1: blkdev_dump_conflict_opener(); blocked = true; case 2: blkdev_dump_conflict_opener(); blocked = true; };
return (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED)) || !blocked; }
static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode) { - if (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED)) + if (bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED)) { + bdev_dump_info(bdev, mode); return true; + } /* Writes blocked? */ if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) return false; @@ -1151,6 +1190,19 @@ static int __init setup_bdev_allow_write_mounted(char *str) if (kstrtou8(str, 0, &bdev_allow_write_mounted)) pr_warn("Invalid option string for bdev_allow_write_mounted:" " '%s'\n", str); + /* + * It's meaningless to set BLKDEV_WRITE_MOUNTED_QUIET if + * BLKDEV_ALLOW_WRITE_MOUNTED is not set. + */ + if (!(bdev_allow_write_mounted & (1 << BLKDEV_ALLOW_WRITE_MOUNTED))) { + if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET)) { + pr_warn("Invalid value for bdev_allow_write_mounted:" + " '%d', it should be set as 0/1/2/3/5/7\n", + bdev_allow_write_mounted); + bdev_allow_write_mounted &= ~(1 << BLKDEV_WRITE_MOUNTED_QUIET); + } + }
return 1; } __setup("bdev_allow_write_mounted=", setup_bdev_allow_write_mounted);
hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8S3GW CVE: NA
---------------------------
Filesystem on logic devices may be corrupted when writing to a block device which is used to create logic devices, so show info to indicate this risk behavior.
Signed-off-by: Li Lingfeng lilingfeng3@huawei.com --- block/bdev.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/block/bdev.c b/block/bdev.c index 720b01b4cb45..0db7e4ee7a00 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -768,6 +768,14 @@ static bool bdev_writes_blocked(struct block_device *bdev) return !!bdev->bd_mounters; }
+static bool bdev_lower_device_writes_blocked(struct block_device *bdev) +{ + if (bdev_allow_write_mounted & (1 << BLKDEV_DETECT_WRITING_PART0)) + return !!bdev->bd_holder; + else + return !!bdev->bd_holder && bdev->bd_holder != bd_may_claim; +} + static void bdev_block_writes(struct block_device *bdev) { bdev->bd_mounters++; @@ -796,7 +804,8 @@ static void bdev_dump_info(struct block_device *bdev, blk_mode_t mode) if (bdev_allow_write_mounted & (1 << BLKDEV_WRITE_MOUNTED_QUIET)) return;
- if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) + if (mode & BLK_OPEN_WRITE && (bdev_writes_blocked(bdev) || + bdev_lower_device_writes_blocked(bdev))) blkdev_dump_conflict_opener(bdev, "VFS: Open an exclusive opened " "block device for write"); else if (mode & BLK_OPEN_RESTRICT_WRITES && bdev_mount_blocked(bdev))