devcoredump: Add dev_coredumpm_timeout()

Add function to set a custom coredump timeout.

For Xe driver usage, current 5 minutes timeout may be too short for
users to search and understand what needs to be done to capture
coredump to report bugs.

We have plans to automate(distribute a udev script) it but at the end
will be up to distros and users to pack it so having a option to
increase the timeout is a safer option.

v2:
- replace dev_coredump_timeout_set() by dev_coredumpm_timeout() (Mukesh)

v3:
- make dev_coredumpm() static inline (Johannes)

v5:
- rename DEVCOREDUMP_TIMEOUT -> DEVCD_TIMEOUT to avoid redefinition
in include/net/bluetooth/coredump.h

v6:
- fix definition of dev_coredumpm_timeout() when CONFIG_DEV_COREDUMP
is disabled

Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Mukesh Ojha <quic_mojha@quicinc.com>
Cc: Johannes Berg <johannes@sipsolutions.net>
Cc: Jonathan Cavitt <jonathan.cavitt@intel.com>
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Reviewed-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
Link: https://patchwork.freedesktop.org/patch/msgid/20240611174716.72660-1-jose.souza@intel.com
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
This commit is contained in:
José Roberto de Souza 2024-06-11 10:47:15 -07:00 committed by Rodrigo Vivi
parent 513ea833c2
commit 3b9c181bcd
No known key found for this signature in database
GPG Key ID: FA625F640EEB13CA
2 changed files with 54 additions and 22 deletions

View File

@ -18,9 +18,6 @@ static struct class devcd_class;
/* global disable flag, for security purposes */ /* global disable flag, for security purposes */
static bool devcd_disabled; static bool devcd_disabled;
/* if data isn't read by userspace after 5 minutes then delete it */
#define DEVCD_TIMEOUT (HZ * 60 * 5)
struct devcd_entry { struct devcd_entry {
struct device devcd_dev; struct device devcd_dev;
void *data; void *data;
@ -328,7 +325,8 @@ void dev_coredump_put(struct device *dev)
EXPORT_SYMBOL_GPL(dev_coredump_put); EXPORT_SYMBOL_GPL(dev_coredump_put);
/** /**
* dev_coredumpm - create device coredump with read/free methods * dev_coredumpm_timeout - create device coredump with read/free methods with a
* custom timeout.
* @dev: the struct device for the crashed device * @dev: the struct device for the crashed device
* @owner: the module that contains the read/free functions, use %THIS_MODULE * @owner: the module that contains the read/free functions, use %THIS_MODULE
* @data: data cookie for the @read/@free functions * @data: data cookie for the @read/@free functions
@ -336,17 +334,20 @@ EXPORT_SYMBOL_GPL(dev_coredump_put);
* @gfp: allocation flags * @gfp: allocation flags
* @read: function to read from the given buffer * @read: function to read from the given buffer
* @free: function to free the given buffer * @free: function to free the given buffer
* @timeout: time in jiffies to remove coredump
* *
* Creates a new device coredump for the given device. If a previous one hasn't * Creates a new device coredump for the given device. If a previous one hasn't
* been read yet, the new coredump is discarded. The data lifetime is determined * been read yet, the new coredump is discarded. The data lifetime is determined
* by the device coredump framework and when it is no longer needed the @free * by the device coredump framework and when it is no longer needed the @free
* function will be called to free the data. * function will be called to free the data.
*/ */
void dev_coredumpm(struct device *dev, struct module *owner, void dev_coredumpm_timeout(struct device *dev, struct module *owner,
void *data, size_t datalen, gfp_t gfp, void *data, size_t datalen, gfp_t gfp,
ssize_t (*read)(char *buffer, loff_t offset, size_t count, ssize_t (*read)(char *buffer, loff_t offset,
void *data, size_t datalen), size_t count, void *data,
void (*free)(void *data)) size_t datalen),
void (*free)(void *data),
unsigned long timeout)
{ {
static atomic_t devcd_count = ATOMIC_INIT(0); static atomic_t devcd_count = ATOMIC_INIT(0);
struct devcd_entry *devcd; struct devcd_entry *devcd;
@ -403,7 +404,7 @@ void dev_coredumpm(struct device *dev, struct module *owner,
dev_set_uevent_suppress(&devcd->devcd_dev, false); dev_set_uevent_suppress(&devcd->devcd_dev, false);
kobject_uevent(&devcd->devcd_dev.kobj, KOBJ_ADD); kobject_uevent(&devcd->devcd_dev.kobj, KOBJ_ADD);
INIT_DELAYED_WORK(&devcd->del_wk, devcd_del); INIT_DELAYED_WORK(&devcd->del_wk, devcd_del);
schedule_delayed_work(&devcd->del_wk, DEVCD_TIMEOUT); schedule_delayed_work(&devcd->del_wk, timeout);
mutex_unlock(&devcd->mutex); mutex_unlock(&devcd->mutex);
return; return;
put_device: put_device:
@ -414,7 +415,7 @@ void dev_coredumpm(struct device *dev, struct module *owner,
free: free:
free(data); free(data);
} }
EXPORT_SYMBOL_GPL(dev_coredumpm); EXPORT_SYMBOL_GPL(dev_coredumpm_timeout);
/** /**
* dev_coredumpsg - create device coredump that uses scatterlist as data * dev_coredumpsg - create device coredump that uses scatterlist as data

View File

@ -12,6 +12,9 @@
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/slab.h> #include <linux/slab.h>
/* if data isn't read by userspace after 5 minutes then delete it */
#define DEVCD_TIMEOUT (HZ * 60 * 5)
/* /*
* _devcd_free_sgtable - free all the memory of the given scatterlist table * _devcd_free_sgtable - free all the memory of the given scatterlist table
* (i.e. both pages and scatterlist instances) * (i.e. both pages and scatterlist instances)
@ -50,16 +53,17 @@ static inline void _devcd_free_sgtable(struct scatterlist *table)
kfree(delete_iter); kfree(delete_iter);
} }
#ifdef CONFIG_DEV_COREDUMP #ifdef CONFIG_DEV_COREDUMP
void dev_coredumpv(struct device *dev, void *data, size_t datalen, void dev_coredumpv(struct device *dev, void *data, size_t datalen,
gfp_t gfp); gfp_t gfp);
void dev_coredumpm(struct device *dev, struct module *owner, void dev_coredumpm_timeout(struct device *dev, struct module *owner,
void *data, size_t datalen, gfp_t gfp, void *data, size_t datalen, gfp_t gfp,
ssize_t (*read)(char *buffer, loff_t offset, size_t count, ssize_t (*read)(char *buffer, loff_t offset,
void *data, size_t datalen), size_t count, void *data,
void (*free)(void *data)); size_t datalen),
void (*free)(void *data),
unsigned long timeout);
void dev_coredumpsg(struct device *dev, struct scatterlist *table, void dev_coredumpsg(struct device *dev, struct scatterlist *table,
size_t datalen, gfp_t gfp); size_t datalen, gfp_t gfp);
@ -73,11 +77,13 @@ static inline void dev_coredumpv(struct device *dev, void *data,
} }
static inline void static inline void
dev_coredumpm(struct device *dev, struct module *owner, dev_coredumpm_timeout(struct device *dev, struct module *owner,
void *data, size_t datalen, gfp_t gfp, void *data, size_t datalen, gfp_t gfp,
ssize_t (*read)(char *buffer, loff_t offset, size_t count, ssize_t (*read)(char *buffer, loff_t offset,
void *data, size_t datalen), size_t count, void *data,
void (*free)(void *data)) size_t datalen),
void (*free)(void *data),
unsigned long timeout)
{ {
free(data); free(data);
} }
@ -92,4 +98,29 @@ static inline void dev_coredump_put(struct device *dev)
} }
#endif /* CONFIG_DEV_COREDUMP */ #endif /* CONFIG_DEV_COREDUMP */
/**
* dev_coredumpm - create device coredump with read/free methods
* @dev: the struct device for the crashed device
* @owner: the module that contains the read/free functions, use %THIS_MODULE
* @data: data cookie for the @read/@free functions
* @datalen: length of the data
* @gfp: allocation flags
* @read: function to read from the given buffer
* @free: function to free the given buffer
*
* Creates a new device coredump for the given device. If a previous one hasn't
* been read yet, the new coredump is discarded. The data lifetime is determined
* by the device coredump framework and when it is no longer needed the @free
* function will be called to free the data.
*/
static inline void dev_coredumpm(struct device *dev, struct module *owner,
void *data, size_t datalen, gfp_t gfp,
ssize_t (*read)(char *buffer, loff_t offset, size_t count,
void *data, size_t datalen),
void (*free)(void *data))
{
dev_coredumpm_timeout(dev, owner, data, datalen, gfp, read, free,
DEVCD_TIMEOUT);
}
#endif /* __DEVCOREDUMP_H */ #endif /* __DEVCOREDUMP_H */