Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright(c) 2015 Intel Deutschland GmbH */ #ifndef __DEVCOREDUMP_H #define __DEVCOREDUMP_H #include <linux/device.h> #include <linux/module.h> #include <linux/vmalloc.h> #include <linux/scatterlist.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 * (i.e. both pages and scatterlist instances) * NOTE: if two tables allocated and chained using the sg_chain function then * this function should be called only once on the first table * @table: pointer to sg_table to free */ static inline void _devcd_free_sgtable(struct scatterlist *table) { int i; struct page *page; struct scatterlist *iter; struct scatterlist *delete_iter; /* free pages */ iter = table; for_each_sg(table, iter, sg_nents(table), i) { page = sg_page(iter); if (page) __free_page(page); } /* then free all chained tables */ iter = table; delete_iter = table; /* always points on a head of a table */ while (!sg_is_last(iter)) { iter++; if (sg_is_chain(iter)) { iter = sg_chain_ptr(iter); kfree(delete_iter); delete_iter = iter; } } /* free the last table */ kfree(delete_iter); } #ifdef CONFIG_DEV_COREDUMP void dev_coredumpv(struct device *dev, void *data, size_t datalen, gfp_t gfp); void dev_coredumpm_timeout(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), unsigned long timeout); void dev_coredumpsg(struct device *dev, struct scatterlist *table, size_t datalen, gfp_t gfp); void dev_coredump_put(struct device *dev); #else static inline void dev_coredumpv(struct device *dev, void *data, size_t datalen, gfp_t gfp) { vfree(data); } static inline void dev_coredumpm_timeout(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), unsigned long timeout) { free(data); } static inline void dev_coredumpsg(struct device *dev, struct scatterlist *table, size_t datalen, gfp_t gfp) { _devcd_free_sgtable(table); } static inline void dev_coredump_put(struct device *dev) { } #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 */ |