2020-04-22 07:40:29

by Christoph Hellwig

[permalink] [raw]
Subject: bdi: fix use-after-free for dev_name(bdi->dev) v3

Hi all,

the first three patches are my take on the proposal from Yufen Yu
to fix the use after free of the device name of the bdi device.

The rest is vaguely related cleanups.

Changes since v2:
- switch vboxsf to a shorter bdi name

Changes since v1:
- use a static dev_name buffer inside struct backing_dev_info


2020-04-22 07:40:35

by Christoph Hellwig

[permalink] [raw]
Subject: [PATCH 1/9] vboxsf: don't use the source name in the bdi name

Simplify the bdi name to mirror what we are doing elsewhere, and
drop them name in favor of just using a number. This avoids a
potentially very long bdi name.

Signed-off-by: Christoph Hellwig <[email protected]>
---
fs/vboxsf/super.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/vboxsf/super.c b/fs/vboxsf/super.c
index 675e26989376..8fe03b4a0d2b 100644
--- a/fs/vboxsf/super.c
+++ b/fs/vboxsf/super.c
@@ -164,7 +164,7 @@ static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc)
goto fail_free;
}

- err = super_setup_bdi_name(sb, "vboxsf-%s.%d", fc->source, sbi->bdi_id);
+ err = super_setup_bdi_name(sb, "vboxsf-%d", sbi->bdi_id);
if (err)
goto fail_free;

--
2.26.1

2020-04-22 07:40:42

by Christoph Hellwig

[permalink] [raw]
Subject: [PATCH 2/9] bdi: move bdi_dev_name out of line

bdi_dev_name is not a fast path function, move it out of line. This
prepares for using it from modular callers without having to export
an implementation detail like bdi_unknown_name.

Signed-off-by: Christoph Hellwig <[email protected]>
Reviewed-by: Jan Kara <[email protected]>
Reviewed-by: Greg Kroah-Hartman <[email protected]>
---
include/linux/backing-dev.h | 9 +--------
mm/backing-dev.c | 10 +++++++++-
2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index f88197c1ffc2..c9ad5c3b7b4b 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -505,13 +505,6 @@ static inline int bdi_rw_congested(struct backing_dev_info *bdi)
(1 << WB_async_congested));
}

-extern const char *bdi_unknown_name;
-
-static inline const char *bdi_dev_name(struct backing_dev_info *bdi)
-{
- if (!bdi || !bdi->dev)
- return bdi_unknown_name;
- return dev_name(bdi->dev);
-}
+const char *bdi_dev_name(struct backing_dev_info *bdi);

#endif /* _LINUX_BACKING_DEV_H */
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index c81b4f3a7268..c2c44c89ee5d 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -21,7 +21,7 @@ struct backing_dev_info noop_backing_dev_info = {
EXPORT_SYMBOL_GPL(noop_backing_dev_info);

static struct class *bdi_class;
-const char *bdi_unknown_name = "(unknown)";
+static const char *bdi_unknown_name = "(unknown)";

/*
* bdi_lock protects bdi_tree and updates to bdi_list. bdi_list has RCU
@@ -1043,6 +1043,14 @@ void bdi_put(struct backing_dev_info *bdi)
}
EXPORT_SYMBOL(bdi_put);

+const char *bdi_dev_name(struct backing_dev_info *bdi)
+{
+ if (!bdi || !bdi->dev)
+ return bdi_unknown_name;
+ return dev_name(bdi->dev);
+}
+EXPORT_SYMBOL_GPL(bdi_dev_name);
+
static wait_queue_head_t congestion_wqh[2] = {
__WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]),
__WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1])
--
2.26.1

2020-04-22 07:40:46

by Christoph Hellwig

[permalink] [raw]
Subject: [PATCH 3/9] bdi: use bdi_dev_name() to get device name

From: Yufen Yu <[email protected]>

Use the common interface bdi_dev_name() to get device name.

Signed-off-by: Yufen Yu <[email protected]>
Reviewed-by: Greg Kroah-Hartman <[email protected]>
Signed-off-by: Christoph Hellwig <[email protected]>
---
block/bfq-iosched.c | 5 +++--
block/blk-cgroup.c | 2 +-
fs/ceph/debugfs.c | 2 +-
include/trace/events/wbt.h | 8 ++++----
4 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
index 78ba57efd16b..4d4fe44a9eea 100644
--- a/block/bfq-iosched.c
+++ b/block/bfq-iosched.c
@@ -4976,8 +4976,9 @@ bfq_set_next_ioprio_data(struct bfq_queue *bfqq, struct bfq_io_cq *bic)
ioprio_class = IOPRIO_PRIO_CLASS(bic->ioprio);
switch (ioprio_class) {
default:
- dev_err(bfqq->bfqd->queue->backing_dev_info->dev,
- "bfq: bad prio class %d\n", ioprio_class);
+ pr_err("bdi %s: bfq: bad prio class %d\n",
+ bdi_dev_name(bfqq->bfqd->queue->backing_dev_info),
+ ioprio_class);
/* fall through */
case IOPRIO_CLASS_NONE:
/*
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index c5dc833212e1..930212c1a512 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -496,7 +496,7 @@ const char *blkg_dev_name(struct blkcg_gq *blkg)
{
/* some drivers (floppy) instantiate a queue w/o disk registered */
if (blkg->q->backing_dev_info->dev)
- return dev_name(blkg->q->backing_dev_info->dev);
+ return bdi_dev_name(blkg->q->backing_dev_info);
return NULL;
}

diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c
index 481ac97b4d25..dcaed75de9e6 100644
--- a/fs/ceph/debugfs.c
+++ b/fs/ceph/debugfs.c
@@ -271,7 +271,7 @@ void ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
&congestion_kb_fops);

snprintf(name, sizeof(name), "../../bdi/%s",
- dev_name(fsc->sb->s_bdi->dev));
+ bdi_dev_name(fsc->sb->s_bdi));
fsc->debugfs_bdi =
debugfs_create_symlink("bdi",
fsc->client->debugfs_dir,
diff --git a/include/trace/events/wbt.h b/include/trace/events/wbt.h
index 784814160197..9c66e59d859c 100644
--- a/include/trace/events/wbt.h
+++ b/include/trace/events/wbt.h
@@ -33,7 +33,7 @@ TRACE_EVENT(wbt_stat,
),

TP_fast_assign(
- strlcpy(__entry->name, dev_name(bdi->dev),
+ strlcpy(__entry->name, bdi_dev_name(bdi),
ARRAY_SIZE(__entry->name));
__entry->rmean = stat[0].mean;
__entry->rmin = stat[0].min;
@@ -68,7 +68,7 @@ TRACE_EVENT(wbt_lat,
),

TP_fast_assign(
- strlcpy(__entry->name, dev_name(bdi->dev),
+ strlcpy(__entry->name, bdi_dev_name(bdi),
ARRAY_SIZE(__entry->name));
__entry->lat = div_u64(lat, 1000);
),
@@ -105,7 +105,7 @@ TRACE_EVENT(wbt_step,
),

TP_fast_assign(
- strlcpy(__entry->name, dev_name(bdi->dev),
+ strlcpy(__entry->name, bdi_dev_name(bdi),
ARRAY_SIZE(__entry->name));
__entry->msg = msg;
__entry->step = step;
@@ -141,7 +141,7 @@ TRACE_EVENT(wbt_timer,
),

TP_fast_assign(
- strlcpy(__entry->name, dev_name(bdi->dev),
+ strlcpy(__entry->name, bdi_dev_name(bdi),
ARRAY_SIZE(__entry->name));
__entry->status = status;
__entry->step = step;
--
2.26.1

2020-04-22 07:40:50

by Christoph Hellwig

[permalink] [raw]
Subject: [PATCH 5/9] driver core: remove device_create_vargs

All external users of device_create_vargs are gone, so remove it and
open code it in the only caller.

Signed-off-by: Christoph Hellwig <[email protected]>
Reviewed-by: Greg Kroah-Hartman <[email protected]>
---
drivers/base/core.c | 37 ++-----------------------------------
include/linux/device.h | 4 ----
2 files changed, 2 insertions(+), 39 deletions(-)

diff --git a/drivers/base/core.c b/drivers/base/core.c
index 139cdf7e7327..fb8ae248e5aa 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -3188,40 +3188,6 @@ device_create_groups_vargs(struct class *class, struct device *parent,
return ERR_PTR(retval);
}

-/**
- * device_create_vargs - creates a device and registers it with sysfs
- * @class: pointer to the struct class that this device should be registered to
- * @parent: pointer to the parent struct device of this new device, if any
- * @devt: the dev_t for the char device to be added
- * @drvdata: the data to be added to the device for callbacks
- * @fmt: string for the device's name
- * @args: va_list for the device's name
- *
- * This function can be used by char device classes. A struct device
- * will be created in sysfs, registered to the specified class.
- *
- * A "dev" file will be created, showing the dev_t for the device, if
- * the dev_t is not 0,0.
- * If a pointer to a parent struct device is passed in, the newly created
- * struct device will be a child of that device in sysfs.
- * The pointer to the struct device will be returned from the call.
- * Any further sysfs files that might be required can be created using this
- * pointer.
- *
- * Returns &struct device pointer on success, or ERR_PTR() on error.
- *
- * Note: the struct class passed to this function must have previously
- * been created with a call to class_create().
- */
-struct device *device_create_vargs(struct class *class, struct device *parent,
- dev_t devt, void *drvdata, const char *fmt,
- va_list args)
-{
- return device_create_groups_vargs(class, parent, devt, drvdata, NULL,
- fmt, args);
-}
-EXPORT_SYMBOL_GPL(device_create_vargs);
-
/**
* device_create - creates a device and registers it with sysfs
* @class: pointer to the struct class that this device should be registered to
@@ -3253,7 +3219,8 @@ struct device *device_create(struct class *class, struct device *parent,
struct device *dev;

va_start(vargs, fmt);
- dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
+ dev = device_create_groups_vargs(class, parent, devt, drvdata, NULL,
+ fmt, vargs);
va_end(vargs);
return dev;
}
diff --git a/include/linux/device.h b/include/linux/device.h
index ac8e37cd716a..15460a5ac024 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -884,10 +884,6 @@ extern bool device_is_bound(struct device *dev);
/*
* Easy functions for dynamically creating devices on the fly
*/
-extern __printf(5, 0)
-struct device *device_create_vargs(struct class *cls, struct device *parent,
- dev_t devt, void *drvdata,
- const char *fmt, va_list vargs);
extern __printf(5, 6)
struct device *device_create(struct class *cls, struct device *parent,
dev_t devt, void *drvdata,
--
2.26.1

2020-04-22 07:40:55

by Christoph Hellwig

[permalink] [raw]
Subject: [PATCH 6/9] bdi: unexport bdi_register_va

bdi_register_va is only used by super.c, which can't be modular.

Signed-off-by: Christoph Hellwig <[email protected]>
Reviewed-by: Jan Kara <[email protected]>
Reviewed-by: Greg Kroah-Hartman <[email protected]>
---
mm/backing-dev.c | 1 -
1 file changed, 1 deletion(-)

diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index efc5b83acd2d..eb6b51e49d11 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -964,7 +964,6 @@ int bdi_register_va(struct backing_dev_info *bdi, const char *fmt, va_list args)
trace_writeback_bdi_register(bdi);
return 0;
}
-EXPORT_SYMBOL(bdi_register_va);

int bdi_register(struct backing_dev_info *bdi, const char *fmt, ...)
{
--
2.26.1

2020-04-22 07:41:02

by Christoph Hellwig

[permalink] [raw]
Subject: [PATCH 7/9] bdi: remove bdi_register_owner

Split out a new bdi_set_owner helper to set the owner, and move the policy
for creating the bdi name back into genhd.c, where it belongs.

Signed-off-by: Christoph Hellwig <[email protected]>
Reviewed-by: Jan Kara <[email protected]>
Reviewed-by: Greg Kroah-Hartman <[email protected]>
---
block/genhd.c | 8 +++++---
include/linux/backing-dev.h | 2 +-
mm/backing-dev.c | 12 ++----------
3 files changed, 8 insertions(+), 14 deletions(-)

diff --git a/block/genhd.c b/block/genhd.c
index 06b642b23a07..7d10cfc38c70 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -840,13 +840,15 @@ static void __device_add_disk(struct device *parent, struct gendisk *disk,
disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
disk->flags |= GENHD_FL_NO_PART_SCAN;
} else {
+ struct backing_dev_info *bdi = disk->queue->backing_dev_info;
+ struct device *dev = disk_to_dev(disk);
int ret;

/* Register BDI before referencing it from bdev */
- disk_to_dev(disk)->devt = devt;
- ret = bdi_register_owner(disk->queue->backing_dev_info,
- disk_to_dev(disk));
+ dev->devt = devt;
+ ret = bdi_register(bdi, "%u:%u", MAJOR(devt), MINOR(devt));
WARN_ON(ret);
+ bdi_set_owner(bdi, dev);
blk_register_region(disk_devt(disk), disk->minors, NULL,
exact_match, exact_lock, disk);
}
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index c9ad5c3b7b4b..4098ed6ba6b4 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -33,7 +33,7 @@ int bdi_register(struct backing_dev_info *bdi, const char *fmt, ...);
__printf(2, 0)
int bdi_register_va(struct backing_dev_info *bdi, const char *fmt,
va_list args);
-int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner);
+void bdi_set_owner(struct backing_dev_info *bdi, struct device *owner);
void bdi_unregister(struct backing_dev_info *bdi);

struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id);
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index eb6b51e49d11..bb993f99d424 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -977,20 +977,12 @@ int bdi_register(struct backing_dev_info *bdi, const char *fmt, ...)
}
EXPORT_SYMBOL(bdi_register);

-int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner)
+void bdi_set_owner(struct backing_dev_info *bdi, struct device *owner)
{
- int rc;
-
- rc = bdi_register(bdi, "%u:%u", MAJOR(owner->devt), MINOR(owner->devt));
- if (rc)
- return rc;
- /* Leaking owner reference... */
- WARN_ON(bdi->owner);
+ WARN_ON_ONCE(bdi->owner);
bdi->owner = owner;
get_device(owner);
- return 0;
}
-EXPORT_SYMBOL(bdi_register_owner);

/*
* Remove bdi from bdi_list, and ensure that it is no longer visible
--
2.26.1

2020-04-22 07:41:05

by Christoph Hellwig

[permalink] [raw]
Subject: [PATCH 8/9] bdi: simplify bdi_alloc

Merge the _node vs normal version and drop the superflous gfp_t argument.

Signed-off-by: Christoph Hellwig <[email protected]>
Reviewed-by: Jan Kara <[email protected]>
Reviewed-by: Greg Kroah-Hartman <[email protected]>
---
block/blk-core.c | 2 +-
drivers/mtd/mtdcore.c | 2 +-
fs/super.c | 2 +-
include/linux/backing-dev.h | 6 +-----
mm/backing-dev.c | 7 +++----
5 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/block/blk-core.c b/block/blk-core.c
index 7e4a1da0715e..ab87f2833ab2 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -484,7 +484,7 @@ struct request_queue *__blk_alloc_queue(int node_id)
if (ret)
goto fail_id;

- q->backing_dev_info = bdi_alloc_node(GFP_KERNEL, node_id);
+ q->backing_dev_info = bdi_alloc(node_id);
if (!q->backing_dev_info)
goto fail_split;

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 2916674208b3..39ec563d9a14 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -2036,7 +2036,7 @@ static struct backing_dev_info * __init mtd_bdi_init(char *name)
struct backing_dev_info *bdi;
int ret;

- bdi = bdi_alloc(GFP_KERNEL);
+ bdi = bdi_alloc(NUMA_NO_NODE);
if (!bdi)
return ERR_PTR(-ENOMEM);

diff --git a/fs/super.c b/fs/super.c
index cd352530eca9..dd28fcd706ff 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1598,7 +1598,7 @@ int super_setup_bdi_name(struct super_block *sb, char *fmt, ...)
int err;
va_list args;

- bdi = bdi_alloc(GFP_KERNEL);
+ bdi = bdi_alloc(NUMA_NO_NODE);
if (!bdi)
return -ENOMEM;

diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index 4098ed6ba6b4..6b3504bf7a42 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -36,11 +36,7 @@ int bdi_register_va(struct backing_dev_info *bdi, const char *fmt,
void bdi_set_owner(struct backing_dev_info *bdi, struct device *owner);
void bdi_unregister(struct backing_dev_info *bdi);

-struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id);
-static inline struct backing_dev_info *bdi_alloc(gfp_t gfp_mask)
-{
- return bdi_alloc_node(gfp_mask, NUMA_NO_NODE);
-}
+struct backing_dev_info *bdi_alloc(int node_id);

void wb_start_background_writeback(struct bdi_writeback *wb);
void wb_workfn(struct work_struct *work);
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index bb993f99d424..1f55d5b8269f 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -865,12 +865,11 @@ static int bdi_init(struct backing_dev_info *bdi)
return ret;
}

-struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id)
+struct backing_dev_info *bdi_alloc(int node_id)
{
struct backing_dev_info *bdi;

- bdi = kmalloc_node(sizeof(struct backing_dev_info),
- gfp_mask | __GFP_ZERO, node_id);
+ bdi = kzalloc_node(sizeof(*bdi), GFP_KERNEL, node_id);
if (!bdi)
return NULL;

@@ -880,7 +879,7 @@ struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id)
}
return bdi;
}
-EXPORT_SYMBOL(bdi_alloc_node);
+EXPORT_SYMBOL(bdi_alloc);

static struct rb_node **bdi_lookup_rb_node(u64 id, struct rb_node **parentp)
{
--
2.26.1

2020-04-22 07:43:03

by Christoph Hellwig

[permalink] [raw]
Subject: [PATCH 4/9] bdi: add a ->dev_name field to struct backing_dev_info

Cache a copy of the name for the life time of the backing_dev_info
structure so that we can reference it even after unregistering.

Fixes: 68f23b89067f ("memcg: fix a crash in wb_workfn when a device disappears")
Reported-by: Yufen Yu <[email protected]>
Signed-off-by: Christoph Hellwig <[email protected]>
---
include/linux/backing-dev-defs.h | 1 +
mm/backing-dev.c | 5 +++--
2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h
index 4fc87dee005a..2849bdbb3acb 100644
--- a/include/linux/backing-dev-defs.h
+++ b/include/linux/backing-dev-defs.h
@@ -220,6 +220,7 @@ struct backing_dev_info {
wait_queue_head_t wb_waitq;

struct device *dev;
+ char dev_name[64];
struct device *owner;

struct timer_list laptop_mode_wb_timer;
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index c2c44c89ee5d..efc5b83acd2d 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -938,7 +938,8 @@ int bdi_register_va(struct backing_dev_info *bdi, const char *fmt, va_list args)
if (bdi->dev) /* The driver needs to use separate queues per device */
return 0;

- dev = device_create_vargs(bdi_class, NULL, MKDEV(0, 0), bdi, fmt, args);
+ vsnprintf(bdi->dev_name, sizeof(bdi->dev_name), fmt, args);
+ dev = device_create(bdi_class, NULL, MKDEV(0, 0), bdi, bdi->dev_name);
if (IS_ERR(dev))
return PTR_ERR(dev);

@@ -1047,7 +1048,7 @@ const char *bdi_dev_name(struct backing_dev_info *bdi)
{
if (!bdi || !bdi->dev)
return bdi_unknown_name;
- return dev_name(bdi->dev);
+ return bdi->dev_name;
}
EXPORT_SYMBOL_GPL(bdi_dev_name);

--
2.26.1

2020-04-22 07:43:14

by Christoph Hellwig

[permalink] [raw]
Subject: [PATCH 9/9] bdi: remove the name field in struct backing_dev_info

The name is only printed for a not registered bdi in writeback. Use the
device name there as is more useful anyway for the unlike case that the
warning triggers.

Signed-off-by: Christoph Hellwig <[email protected]>
Reviewed-by: Jan Kara <[email protected]>
Reviewed-by: Greg Kroah-Hartman <[email protected]>
---
block/blk-core.c | 1 -
drivers/mtd/mtdcore.c | 1 -
fs/fs-writeback.c | 2 +-
fs/super.c | 2 --
include/linux/backing-dev-defs.h | 2 --
mm/backing-dev.c | 1 -
6 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/block/blk-core.c b/block/blk-core.c
index ab87f2833ab2..f37068c611bf 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -494,7 +494,6 @@ struct request_queue *__blk_alloc_queue(int node_id)

q->backing_dev_info->ra_pages = VM_READAHEAD_PAGES;
q->backing_dev_info->capabilities = BDI_CAP_CGROUP_WRITEBACK;
- q->backing_dev_info->name = "block";
q->node = node_id;

timer_setup(&q->backing_dev_info->laptop_mode_wb_timer,
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 39ec563d9a14..fcb018ce17c3 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -2040,7 +2040,6 @@ static struct backing_dev_info * __init mtd_bdi_init(char *name)
if (!bdi)
return ERR_PTR(-ENOMEM);

- bdi->name = name;
/*
* We put '-0' suffix to the name to get the same name format as we
* used to get. Since this is called only once, we get a unique name.
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 76ac9c7d32ec..d85323607b49 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -2320,7 +2320,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)

WARN(bdi_cap_writeback_dirty(wb->bdi) &&
!test_bit(WB_registered, &wb->state),
- "bdi-%s not registered\n", wb->bdi->name);
+ "bdi-%s not registered\n", bdi_dev_name(wb->bdi));

inode->dirtied_when = jiffies;
if (dirtytime)
diff --git a/fs/super.c b/fs/super.c
index dd28fcd706ff..4991f441988e 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1602,8 +1602,6 @@ int super_setup_bdi_name(struct super_block *sb, char *fmt, ...)
if (!bdi)
return -ENOMEM;

- bdi->name = sb->s_type->name;
-
va_start(args, fmt);
err = bdi_register_va(bdi, fmt, args);
va_end(args);
diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h
index 2849bdbb3acb..011bb8ad0738 100644
--- a/include/linux/backing-dev-defs.h
+++ b/include/linux/backing-dev-defs.h
@@ -194,8 +194,6 @@ struct backing_dev_info {
congested_fn *congested_fn; /* Function pointer if device is md/dm */
void *congested_data; /* Pointer to aux data for congested func */

- const char *name;
-
struct kref refcnt; /* Reference counter for the structure */
unsigned int capabilities; /* Device capabilities */
unsigned int min_ratio;
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 1f55d5b8269f..d382272bcc31 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -15,7 +15,6 @@
#include <trace/events/writeback.h>

struct backing_dev_info noop_backing_dev_info = {
- .name = "noop",
.capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
};
EXPORT_SYMBOL_GPL(noop_backing_dev_info);
--
2.26.1

2020-04-22 08:17:53

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH 1/9] vboxsf: don't use the source name in the bdi name

Hi,

On 4/22/20 9:38 AM, Christoph Hellwig wrote:
> Simplify the bdi name to mirror what we are doing elsewhere, and
> drop them name in favor of just using a number. This avoids a
> potentially very long bdi name.
>
> Signed-off-by: Christoph Hellwig <[email protected]>

Looks good to me:

Reviewed-by: Hans de Goede <[email protected]>

Regards,

Hans


> ---
> fs/vboxsf/super.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/fs/vboxsf/super.c b/fs/vboxsf/super.c
> index 675e26989376..8fe03b4a0d2b 100644
> --- a/fs/vboxsf/super.c
> +++ b/fs/vboxsf/super.c
> @@ -164,7 +164,7 @@ static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc)
> goto fail_free;
> }
>
> - err = super_setup_bdi_name(sb, "vboxsf-%s.%d", fc->source, sbi->bdi_id);
> + err = super_setup_bdi_name(sb, "vboxsf-%d", sbi->bdi_id);
> if (err)
> goto fail_free;
>
>

2020-04-22 09:11:36

by Jan Kara

[permalink] [raw]
Subject: Re: [PATCH 3/9] bdi: use bdi_dev_name() to get device name

On Wed 22-04-20 09:38:45, Christoph Hellwig wrote:
> From: Yufen Yu <[email protected]>
>
> Use the common interface bdi_dev_name() to get device name.
>
> Signed-off-by: Yufen Yu <[email protected]>
> Reviewed-by: Greg Kroah-Hartman <[email protected]>
> Signed-off-by: Christoph Hellwig <[email protected]>

Looks good to me. You can add:

Reviewed-by: Jan Kara <[email protected]>

Honza

> ---
> block/bfq-iosched.c | 5 +++--
> block/blk-cgroup.c | 2 +-
> fs/ceph/debugfs.c | 2 +-
> include/trace/events/wbt.h | 8 ++++----
> 4 files changed, 9 insertions(+), 8 deletions(-)
>
> diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
> index 78ba57efd16b..4d4fe44a9eea 100644
> --- a/block/bfq-iosched.c
> +++ b/block/bfq-iosched.c
> @@ -4976,8 +4976,9 @@ bfq_set_next_ioprio_data(struct bfq_queue *bfqq, struct bfq_io_cq *bic)
> ioprio_class = IOPRIO_PRIO_CLASS(bic->ioprio);
> switch (ioprio_class) {
> default:
> - dev_err(bfqq->bfqd->queue->backing_dev_info->dev,
> - "bfq: bad prio class %d\n", ioprio_class);
> + pr_err("bdi %s: bfq: bad prio class %d\n",
> + bdi_dev_name(bfqq->bfqd->queue->backing_dev_info),
> + ioprio_class);
> /* fall through */
> case IOPRIO_CLASS_NONE:
> /*
> diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
> index c5dc833212e1..930212c1a512 100644
> --- a/block/blk-cgroup.c
> +++ b/block/blk-cgroup.c
> @@ -496,7 +496,7 @@ const char *blkg_dev_name(struct blkcg_gq *blkg)
> {
> /* some drivers (floppy) instantiate a queue w/o disk registered */
> if (blkg->q->backing_dev_info->dev)
> - return dev_name(blkg->q->backing_dev_info->dev);
> + return bdi_dev_name(blkg->q->backing_dev_info);
> return NULL;
> }
>
> diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c
> index 481ac97b4d25..dcaed75de9e6 100644
> --- a/fs/ceph/debugfs.c
> +++ b/fs/ceph/debugfs.c
> @@ -271,7 +271,7 @@ void ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
> &congestion_kb_fops);
>
> snprintf(name, sizeof(name), "../../bdi/%s",
> - dev_name(fsc->sb->s_bdi->dev));
> + bdi_dev_name(fsc->sb->s_bdi));
> fsc->debugfs_bdi =
> debugfs_create_symlink("bdi",
> fsc->client->debugfs_dir,
> diff --git a/include/trace/events/wbt.h b/include/trace/events/wbt.h
> index 784814160197..9c66e59d859c 100644
> --- a/include/trace/events/wbt.h
> +++ b/include/trace/events/wbt.h
> @@ -33,7 +33,7 @@ TRACE_EVENT(wbt_stat,
> ),
>
> TP_fast_assign(
> - strlcpy(__entry->name, dev_name(bdi->dev),
> + strlcpy(__entry->name, bdi_dev_name(bdi),
> ARRAY_SIZE(__entry->name));
> __entry->rmean = stat[0].mean;
> __entry->rmin = stat[0].min;
> @@ -68,7 +68,7 @@ TRACE_EVENT(wbt_lat,
> ),
>
> TP_fast_assign(
> - strlcpy(__entry->name, dev_name(bdi->dev),
> + strlcpy(__entry->name, bdi_dev_name(bdi),
> ARRAY_SIZE(__entry->name));
> __entry->lat = div_u64(lat, 1000);
> ),
> @@ -105,7 +105,7 @@ TRACE_EVENT(wbt_step,
> ),
>
> TP_fast_assign(
> - strlcpy(__entry->name, dev_name(bdi->dev),
> + strlcpy(__entry->name, bdi_dev_name(bdi),
> ARRAY_SIZE(__entry->name));
> __entry->msg = msg;
> __entry->step = step;
> @@ -141,7 +141,7 @@ TRACE_EVENT(wbt_timer,
> ),
>
> TP_fast_assign(
> - strlcpy(__entry->name, dev_name(bdi->dev),
> + strlcpy(__entry->name, bdi_dev_name(bdi),
> ARRAY_SIZE(__entry->name));
> __entry->status = status;
> __entry->step = step;
> --
> 2.26.1
>
--
Jan Kara <[email protected]>
SUSE Labs, CR

2020-04-22 09:12:05

by Jan Kara

[permalink] [raw]
Subject: Re: [PATCH 4/9] bdi: add a ->dev_name field to struct backing_dev_info

On Wed 22-04-20 09:38:46, Christoph Hellwig wrote:
> Cache a copy of the name for the life time of the backing_dev_info
> structure so that we can reference it even after unregistering.
>
> Fixes: 68f23b89067f ("memcg: fix a crash in wb_workfn when a device disappears")
> Reported-by: Yufen Yu <[email protected]>
> Signed-off-by: Christoph Hellwig <[email protected]>

Looks good to me. You can add:

Reviewed-by: Jan Kara <[email protected]>

Honza

> ---
> include/linux/backing-dev-defs.h | 1 +
> mm/backing-dev.c | 5 +++--
> 2 files changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h
> index 4fc87dee005a..2849bdbb3acb 100644
> --- a/include/linux/backing-dev-defs.h
> +++ b/include/linux/backing-dev-defs.h
> @@ -220,6 +220,7 @@ struct backing_dev_info {
> wait_queue_head_t wb_waitq;
>
> struct device *dev;
> + char dev_name[64];
> struct device *owner;
>
> struct timer_list laptop_mode_wb_timer;
> diff --git a/mm/backing-dev.c b/mm/backing-dev.c
> index c2c44c89ee5d..efc5b83acd2d 100644
> --- a/mm/backing-dev.c
> +++ b/mm/backing-dev.c
> @@ -938,7 +938,8 @@ int bdi_register_va(struct backing_dev_info *bdi, const char *fmt, va_list args)
> if (bdi->dev) /* The driver needs to use separate queues per device */
> return 0;
>
> - dev = device_create_vargs(bdi_class, NULL, MKDEV(0, 0), bdi, fmt, args);
> + vsnprintf(bdi->dev_name, sizeof(bdi->dev_name), fmt, args);
> + dev = device_create(bdi_class, NULL, MKDEV(0, 0), bdi, bdi->dev_name);
> if (IS_ERR(dev))
> return PTR_ERR(dev);
>
> @@ -1047,7 +1048,7 @@ const char *bdi_dev_name(struct backing_dev_info *bdi)
> {
> if (!bdi || !bdi->dev)
> return bdi_unknown_name;
> - return dev_name(bdi->dev);
> + return bdi->dev_name;
> }
> EXPORT_SYMBOL_GPL(bdi_dev_name);
>
> --
> 2.26.1
>
--
Jan Kara <[email protected]>
SUSE Labs, CR

2020-04-22 09:14:13

by Jan Kara

[permalink] [raw]
Subject: Re: [PATCH 5/9] driver core: remove device_create_vargs

On Wed 22-04-20 09:38:47, Christoph Hellwig wrote:
> All external users of device_create_vargs are gone, so remove it and
> open code it in the only caller.
>
> Signed-off-by: Christoph Hellwig <[email protected]>
> Reviewed-by: Greg Kroah-Hartman <[email protected]>

Looks good to me. You can add:

Reviewed-by: Jan Kara <[email protected]>

Honza

> ---
> drivers/base/core.c | 37 ++-----------------------------------
> include/linux/device.h | 4 ----
> 2 files changed, 2 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/base/core.c b/drivers/base/core.c
> index 139cdf7e7327..fb8ae248e5aa 100644
> --- a/drivers/base/core.c
> +++ b/drivers/base/core.c
> @@ -3188,40 +3188,6 @@ device_create_groups_vargs(struct class *class, struct device *parent,
> return ERR_PTR(retval);
> }
>
> -/**
> - * device_create_vargs - creates a device and registers it with sysfs
> - * @class: pointer to the struct class that this device should be registered to
> - * @parent: pointer to the parent struct device of this new device, if any
> - * @devt: the dev_t for the char device to be added
> - * @drvdata: the data to be added to the device for callbacks
> - * @fmt: string for the device's name
> - * @args: va_list for the device's name
> - *
> - * This function can be used by char device classes. A struct device
> - * will be created in sysfs, registered to the specified class.
> - *
> - * A "dev" file will be created, showing the dev_t for the device, if
> - * the dev_t is not 0,0.
> - * If a pointer to a parent struct device is passed in, the newly created
> - * struct device will be a child of that device in sysfs.
> - * The pointer to the struct device will be returned from the call.
> - * Any further sysfs files that might be required can be created using this
> - * pointer.
> - *
> - * Returns &struct device pointer on success, or ERR_PTR() on error.
> - *
> - * Note: the struct class passed to this function must have previously
> - * been created with a call to class_create().
> - */
> -struct device *device_create_vargs(struct class *class, struct device *parent,
> - dev_t devt, void *drvdata, const char *fmt,
> - va_list args)
> -{
> - return device_create_groups_vargs(class, parent, devt, drvdata, NULL,
> - fmt, args);
> -}
> -EXPORT_SYMBOL_GPL(device_create_vargs);
> -
> /**
> * device_create - creates a device and registers it with sysfs
> * @class: pointer to the struct class that this device should be registered to
> @@ -3253,7 +3219,8 @@ struct device *device_create(struct class *class, struct device *parent,
> struct device *dev;
>
> va_start(vargs, fmt);
> - dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
> + dev = device_create_groups_vargs(class, parent, devt, drvdata, NULL,
> + fmt, vargs);
> va_end(vargs);
> return dev;
> }
> diff --git a/include/linux/device.h b/include/linux/device.h
> index ac8e37cd716a..15460a5ac024 100644
> --- a/include/linux/device.h
> +++ b/include/linux/device.h
> @@ -884,10 +884,6 @@ extern bool device_is_bound(struct device *dev);
> /*
> * Easy functions for dynamically creating devices on the fly
> */
> -extern __printf(5, 0)
> -struct device *device_create_vargs(struct class *cls, struct device *parent,
> - dev_t devt, void *drvdata,
> - const char *fmt, va_list vargs);
> extern __printf(5, 6)
> struct device *device_create(struct class *cls, struct device *parent,
> dev_t devt, void *drvdata,
> --
> 2.26.1
>
--
Jan Kara <[email protected]>
SUSE Labs, CR

2020-04-23 00:09:44

by Bart Van Assche

[permalink] [raw]
Subject: Re: [PATCH 3/9] bdi: use bdi_dev_name() to get device name

On 4/22/20 12:38 AM, Christoph Hellwig wrote:> Use the common interface
bdi_dev_name() to get device name.
Reviewed-by: Bart Van Assche <[email protected]>

2020-04-23 00:11:04

by Bart Van Assche

[permalink] [raw]
Subject: Re: [PATCH 2/9] bdi: move bdi_dev_name out of line

On 4/22/20 12:38 AM, Christoph Hellwig wrote:
> bdi_dev_name is not a fast path function, move it out of line. This
> prepares for using it from modular callers without having to export
> an implementation detail like bdi_unknown_name.

Reviewed-by: Bart Van Assche <[email protected]>

2020-04-23 00:13:00

by Bart Van Assche

[permalink] [raw]
Subject: Re: [PATCH 4/9] bdi: add a ->dev_name field to struct backing_dev_info

On 4/22/20 12:38 AM, Christoph Hellwig wrote:
> Cache a copy of the name for the life time of the backing_dev_info
> structure so that we can reference it even after unregistering.

Reviewed-by: Bart Van Assche <[email protected]>

2020-04-23 00:15:20

by Bart Van Assche

[permalink] [raw]
Subject: Re: [PATCH 6/9] bdi: unexport bdi_register_va

On 4/22/20 12:38 AM, Christoph Hellwig wrote:
> bdi_register_va is only used by super.c, which can't be modular.

Reviewed-by: Bart Van Assche <[email protected]>

2020-04-23 00:15:33

by Bart Van Assche

[permalink] [raw]
Subject: Re: [PATCH 8/9] bdi: simplify bdi_alloc

On 4/22/20 12:38 AM, Christoph Hellwig wrote:
> Merge the _node vs normal version and drop the superflous gfp_t argument.

Reviewed-by: Bart Van Assche <[email protected]>

2020-04-23 00:17:00

by Bart Van Assche

[permalink] [raw]
Subject: Re: [PATCH 7/9] bdi: remove bdi_register_owner

On 4/22/20 12:38 AM, Christoph Hellwig wrote:
> Split out a new bdi_set_owner helper to set the owner, and move the policy
> for creating the bdi name back into genhd.c, where it belongs.

Reviewed-by: Bart Van Assche <[email protected]>

2020-04-23 00:20:19

by Bart Van Assche

[permalink] [raw]
Subject: Re: [PATCH 9/9] bdi: remove the name field in struct backing_dev_info

On 4/22/20 12:38 AM, Christoph Hellwig wrote:
> The name is only printed for a not registered bdi in writeback. Use the
> device name there as is more useful anyway for the unlike case that the
> warning triggers.

Reviewed-by: Bart Van Assche <[email protected]>

2020-04-25 08:03:07

by Christoph Hellwig

[permalink] [raw]
Subject: Re: bdi: fix use-after-free for dev_name(bdi->dev) v3

Any more comments? Are we ready to merge this now?

On Wed, Apr 22, 2020 at 09:38:42AM +0200, Christoph Hellwig wrote:
> Hi all,
>
> the first three patches are my take on the proposal from Yufen Yu
> to fix the use after free of the device name of the bdi device.
>
> The rest is vaguely related cleanups.
>
> Changes since v2:
> - switch vboxsf to a shorter bdi name
>
> Changes since v1:
> - use a static dev_name buffer inside struct backing_dev_info
---end quoted text---

2020-04-25 10:45:27

by Hans de Goede

[permalink] [raw]
Subject: Re: bdi: fix use-after-free for dev_name(bdi->dev) v3

Hi,

On 4/25/20 9:59 AM, Christoph Hellwig wrote:
> Any more comments? Are we ready to merge this now?

Merging this fine with me.

Regards,

Hans


> On Wed, Apr 22, 2020 at 09:38:42AM +0200, Christoph Hellwig wrote:
>> Hi all,
>>
>> the first three patches are my take on the proposal from Yufen Yu
>> to fix the use after free of the device name of the bdi device.
>>
>> The rest is vaguely related cleanups.
>>
>> Changes since v2:
>> - switch vboxsf to a shorter bdi name
>>
>> Changes since v1:
>> - use a static dev_name buffer inside struct backing_dev_info
> ---end quoted text---
>

2020-04-28 06:55:18

by Christoph Hellwig

[permalink] [raw]
Subject: Re: bdi: fix use-after-free for dev_name(bdi->dev) v3

Jens,

can you pick this series up? At least 1-4 are probably usefu for 5.7
and -stable.