From: Michael Jeanson Date: Mon, 15 Mar 2021 18:54:02 +0000 (-0400) Subject: fix: block: add a disk_uevent helper (v5.12) X-Git-Tag: v2.13.0-rc1~14 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=7633c7736aefbf2ac3c308021d7aa2bb3229ae94;p=lttng-modules.git fix: block: add a disk_uevent helper (v5.12) See upstream commit: commit bc359d03c7ec1bf3b86d03bafaf6bbb21e6414fd Author: Christoph Hellwig Date: Sun Jan 24 11:02:39 2021 +0100 block: add a disk_uevent helper Add a helper to call kobject_uevent for the disk and all partitions, and unexport the disk_part_iter_* helpers that are now only used in the core block code. Change-Id: If6e8797049642ab382d5699660ee1dd734e92c90 Signed-off-by: Michael Jeanson Signed-off-by: Mathieu Desnoyers --- diff --git a/include/wrapper/genhd.h b/include/wrapper/genhd.h index 68980388..c28a52e3 100644 --- a/include/wrapper/genhd.h +++ b/include/wrapper/genhd.h @@ -13,6 +13,13 @@ #define _LTTNG_WRAPPER_GENHD_H #include +#include + +#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,11,0)) +#define LTTNG_DISK_PART_TYPE struct block_device +#else +#define LTTNG_DISK_PART_TYPE struct hd_struct +#endif #ifdef CONFIG_KALLSYMS_ALL @@ -94,4 +101,59 @@ struct device_type *wrapper_get_disk_type(void) #endif +/* + * This wrapper has an 'int' return type instead of the original 'void', to be + * able to report the symbol lookup failure to the caller. + * + * Return 0 on success, -1 on error. + */ +int wrapper_disk_part_iter_init(struct disk_part_iter *piter, struct gendisk *disk, + unsigned int flags); +LTTNG_DISK_PART_TYPE *wrapper_disk_part_iter_next(struct disk_part_iter *piter); +void wrapper_disk_part_iter_exit(struct disk_part_iter *piter); + +/* + * Canary function to check for 'disk_part_iter_init()' at compile time. + * + * From 'include/linux/genhd.h': + * + * extern void disk_part_iter_init(struct disk_part_iter *piter, + * struct gendisk *disk, unsigned int flags); + * + */ +static inline +void __canary__disk_part_iter_init(struct disk_part_iter *piter, struct gendisk *disk, + unsigned int flags) +{ + disk_part_iter_init(piter, disk, flags); +} + +/* + * Canary function to check for 'disk_part_iter_next()' at compile time. + * + * From 'include/linux/genhd.h': + * + * struct block_device *disk_part_iter_next(struct disk_part_iter *piter); + * + */ +static inline +LTTNG_DISK_PART_TYPE *__canary__disk_part_iter_next(struct disk_part_iter *piter) +{ + return disk_part_iter_next(piter); +} + +/* + * Canary function to check for 'disk_part_iter_exit()' at compile time. + * + * From 'include/linux/genhd.h': + * + * extern void disk_part_iter_exit(struct disk_part_iter *piter); + * + */ +static inline +void __canary__disk_part_iter_exit(struct disk_part_iter *piter) +{ + return disk_part_iter_exit(piter); +} + #endif /* _LTTNG_WRAPPER_GENHD_H */ diff --git a/src/Kbuild b/src/Kbuild index 616c1dde..e7593fd8 100644 --- a/src/Kbuild +++ b/src/Kbuild @@ -65,6 +65,7 @@ lttng-wrapper-objs := wrapper/page_alloc.o \ wrapper/kallsyms.o \ wrapper/irqdesc.o \ wrapper/fdtable.o \ + wrapper/genhd.o \ lttng-wrapper-impl.o ifneq ($(CONFIG_HAVE_SYSCALL_TRACEPOINTS),) diff --git a/src/lttng-statedump-impl.c b/src/lttng-statedump-impl.c index b3453bf5..846706e3 100644 --- a/src/lttng-statedump-impl.c +++ b/src/lttng-statedump-impl.c @@ -256,13 +256,17 @@ int lttng_enumerate_block_devices(struct lttng_session *session) struct device_type *ptr_disk_type; struct class_dev_iter iter; struct device *dev; + int ret = 0; ptr_block_class = wrapper_get_block_class(); - if (!ptr_block_class) - return -ENOSYS; + if (!ptr_block_class) { + ret = -ENOSYS; + goto end; + } ptr_disk_type = wrapper_get_disk_type(); if (!ptr_disk_type) { - return -ENOSYS; + ret = -ENOSYS; + goto end; } class_dev_iter_init(&iter, ptr_block_class, NULL, ptr_disk_type); while ((dev = class_dev_iter_next(&iter))) { @@ -278,22 +282,32 @@ int lttng_enumerate_block_devices(struct lttng_session *session) (disk->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)) continue; - disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); - while ((part = disk_part_iter_next(&piter))) { + /* + * The original 'disk_part_iter_init' returns void, but our + * wrapper can fail to lookup the original symbol. + */ + if (wrapper_disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0) < 0) { + ret = -ENOSYS; + goto iter_exit; + } + + while ((part = wrapper_disk_part_iter_next(&piter))) { char name_buf[BDEVNAME_SIZE]; if (lttng_get_part_name(disk, part, name_buf) == -ENOSYS) { - disk_part_iter_exit(&piter); - class_dev_iter_exit(&iter); - return -ENOSYS; + wrapper_disk_part_iter_exit(&piter); + ret = -ENOSYS; + goto iter_exit; } trace_lttng_statedump_block_device(session, lttng_get_part_devt(part), name_buf); } - disk_part_iter_exit(&piter); + wrapper_disk_part_iter_exit(&piter); } +iter_exit: class_dev_iter_exit(&iter); - return 0; +end: + return ret; } #ifdef CONFIG_INET diff --git a/src/wrapper/genhd.c b/src/wrapper/genhd.c new file mode 100644 index 00000000..a5a6c410 --- /dev/null +++ b/src/wrapper/genhd.c @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR LGPL-2.1-only) + * + * wrapper/genhd.c + * + * Wrapper around disk_part_iter_(init|next|exit). Using KALLSYMS to get the + * addresses when available, else we need to have a kernel that exports this + * function to GPL modules. This export was removed in 5.12. + * + * Copyright (C) 2021 Michael Jeanson + */ + +#include +#include +#include + +#if (defined(CONFIG_KALLSYMS) && \ + (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,12,0))) + +#include + +static +void (*disk_part_iter_init_sym)(struct disk_part_iter *piter, struct gendisk *disk, + unsigned int flags); + +static +LTTNG_DISK_PART_TYPE *(*disk_part_iter_next_sym)(struct disk_part_iter *piter); + +static +void (*disk_part_iter_exit_sym)(struct disk_part_iter *piter); + +/* + * This wrapper has an 'int' return type instead of the original 'void', to be + * able to report the symbol lookup failure to the caller. + * + * Return 0 on success, -1 on error. + */ +int wrapper_disk_part_iter_init(struct disk_part_iter *piter, struct gendisk *disk, + unsigned int flags) +{ + if (!disk_part_iter_init_sym) + disk_part_iter_init_sym = (void *) kallsyms_lookup_funcptr("disk_part_iter_init"); + + if (disk_part_iter_init_sym) { + disk_part_iter_init_sym(piter, disk, flags); + } else { + printk_once(KERN_WARNING "LTTng: disk_part_iter_init symbol lookup failed.\n"); + return -1; + } + return 0; +} +EXPORT_SYMBOL_GPL(wrapper_disk_part_iter_init); + +LTTNG_DISK_PART_TYPE *wrapper_disk_part_iter_next(struct disk_part_iter *piter) +{ + if (!disk_part_iter_next_sym) + disk_part_iter_next_sym = (void *) kallsyms_lookup_funcptr("disk_part_iter_next"); + + if (disk_part_iter_next_sym) { + return disk_part_iter_next_sym(piter); + } else { + printk_once(KERN_WARNING "LTTng: disk_part_iter_next symbol lookup failed.\n"); + return NULL; + } +} +EXPORT_SYMBOL_GPL(wrapper_disk_part_iter_next); + +/* + * We don't return an error on symbol lookup failure here because there is + * nothing the caller can do to cleanup the iterator. + */ +void wrapper_disk_part_iter_exit(struct disk_part_iter *piter) +{ + if (!disk_part_iter_exit_sym) + disk_part_iter_exit_sym = (void *) kallsyms_lookup_funcptr("disk_part_iter_exit"); + + if (disk_part_iter_exit_sym) { + disk_part_iter_exit_sym(piter); + } else { + printk_once(KERN_WARNING "LTTng: disk_part_iter_exit symbol lookup failed.\n"); + } +} +EXPORT_SYMBOL_GPL(wrapper_disk_part_iter_exit); + +#else + +/* + * This wrapper has an 'int' return type instead of the original 'void', so the + * kallsyms variant can report the symbol lookup failure to the caller. + * + * This variant always succeeds and returns 0. + */ +int wrapper_disk_part_iter_init(struct disk_part_iter *piter, struct gendisk *disk, + unsigned int flags) +{ + disk_part_iter_init(piter, disk, flags); + return 0; +} +EXPORT_SYMBOL_GPL(wrapper_disk_part_iter_init); + +LTTNG_DISK_PART_TYPE *wrapper_disk_part_iter_next(struct disk_part_iter *piter) +{ + return disk_part_iter_next(piter); +} +EXPORT_SYMBOL_GPL(wrapper_disk_part_iter_next); + +void wrapper_disk_part_iter_exit(struct disk_part_iter *piter) +{ + disk_part_iter_exit(piter); +} +EXPORT_SYMBOL_GPL(wrapper_disk_part_iter_exit); +#endif