Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

virtio: add debugfs infrastructure to allow to debug virtio features

Currently there is no way for user to set what features the driver
should obey or not, it is hard wired in the code.

In order to be able to debug the device behavior in case some feature is
disabled, introduce a debugfs infrastructure with couple of files
allowing user to see what features the device advertises and
to set filter for features used by driver.

Example:
$cat /sys/bus/virtio/devices/virtio0/features
1110010111111111111101010000110010000000100000000000000000000000
$ echo "5" >/sys/kernel/debug/virtio/virtio0/filter_feature_add
$ cat /sys/kernel/debug/virtio/virtio0/filter_features
5
$ echo "virtio0" > /sys/bus/virtio/drivers/virtio_net/unbind
$ echo "virtio0" > /sys/bus/virtio/drivers/virtio_net/bind
$ cat /sys/bus/virtio/devices/virtio0/features
1110000111111111111101010000110010000000100000000000000000000000

Note that sysfs "features" now already exists, this patch does not
touch it.

Signed-off-by: Jiri Pirko <jiri@nvidia.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Jiri Pirko and committed by
Paolo Abeni
96a8326d fc48de77

+168
+10
drivers/virtio/Kconfig
··· 178 178 This option adds a flavor of dma buffers that are backed by 179 179 virtio resources. 180 180 181 + config VIRTIO_DEBUG 182 + bool "Debug facilities" 183 + depends on VIRTIO 184 + help 185 + Enable this to expose debug facilities over debugfs. 186 + This allows to debug features, to see what features the device 187 + advertises and to set filter for features used by driver. 188 + 189 + If unsure, say N. 190 + 181 191 endif # VIRTIO_MENU
+1
drivers/virtio/Makefile
··· 13 13 obj-$(CONFIG_VIRTIO_VDPA) += virtio_vdpa.o 14 14 obj-$(CONFIG_VIRTIO_MEM) += virtio_mem.o 15 15 obj-$(CONFIG_VIRTIO_DMA_SHARED_BUFFER) += virtio_dma_buf.o 16 + obj-$(CONFIG_VIRTIO_DEBUG) += virtio_debug.o
+8
drivers/virtio/virtio.c
··· 274 274 else 275 275 dev->features = driver_features_legacy & device_features; 276 276 277 + /* When debugging, user may filter some features by hand. */ 278 + virtio_debug_device_filter_features(dev); 279 + 277 280 /* Transport features always preserved to pass to finalize_features. */ 278 281 for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++) 279 282 if (device_features & (1ULL << i)) ··· 468 465 /* Acknowledge that we've seen the device. */ 469 466 virtio_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); 470 467 468 + virtio_debug_device_init(dev); 469 + 471 470 /* 472 471 * device_add() causes the bus infrastructure to look for a matching 473 472 * driver. ··· 501 496 int index = dev->index; /* save for after device release */ 502 497 503 498 device_unregister(&dev->dev); 499 + virtio_debug_device_exit(dev); 504 500 ida_free(&virtio_index_ida, index); 505 501 } 506 502 EXPORT_SYMBOL_GPL(unregister_virtio_device); ··· 596 590 { 597 591 if (bus_register(&virtio_bus) != 0) 598 592 panic("virtio bus registration failed"); 593 + virtio_debug_init(); 599 594 return 0; 600 595 } 601 596 602 597 static void __exit virtio_exit(void) 603 598 { 599 + virtio_debug_exit(); 604 600 bus_unregister(&virtio_bus); 605 601 ida_destroy(&virtio_index_ida); 606 602 }
+114
drivers/virtio/virtio_debug.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + #include <linux/virtio.h> 4 + #include <linux/virtio_config.h> 5 + #include <linux/debugfs.h> 6 + 7 + static struct dentry *virtio_debugfs_dir; 8 + 9 + static int virtio_debug_device_features_show(struct seq_file *s, void *data) 10 + { 11 + struct virtio_device *dev = s->private; 12 + u64 device_features; 13 + unsigned int i; 14 + 15 + device_features = dev->config->get_features(dev); 16 + for (i = 0; i < BITS_PER_LONG_LONG; i++) { 17 + if (device_features & (1ULL << i)) 18 + seq_printf(s, "%u\n", i); 19 + } 20 + return 0; 21 + } 22 + DEFINE_SHOW_ATTRIBUTE(virtio_debug_device_features); 23 + 24 + static int virtio_debug_filter_features_show(struct seq_file *s, void *data) 25 + { 26 + struct virtio_device *dev = s->private; 27 + unsigned int i; 28 + 29 + for (i = 0; i < BITS_PER_LONG_LONG; i++) { 30 + if (dev->debugfs_filter_features & (1ULL << i)) 31 + seq_printf(s, "%u\n", i); 32 + } 33 + return 0; 34 + } 35 + DEFINE_SHOW_ATTRIBUTE(virtio_debug_filter_features); 36 + 37 + static int virtio_debug_filter_features_clear(void *data, u64 val) 38 + { 39 + struct virtio_device *dev = data; 40 + 41 + if (val == 1) 42 + dev->debugfs_filter_features = 0; 43 + return 0; 44 + } 45 + 46 + DEFINE_DEBUGFS_ATTRIBUTE(virtio_debug_filter_features_clear_fops, NULL, 47 + virtio_debug_filter_features_clear, "%llu\n"); 48 + 49 + static int virtio_debug_filter_feature_add(void *data, u64 val) 50 + { 51 + struct virtio_device *dev = data; 52 + 53 + if (val >= BITS_PER_LONG_LONG) 54 + return -EINVAL; 55 + dev->debugfs_filter_features |= BIT_ULL_MASK(val); 56 + return 0; 57 + } 58 + 59 + DEFINE_DEBUGFS_ATTRIBUTE(virtio_debug_filter_feature_add_fops, NULL, 60 + virtio_debug_filter_feature_add, "%llu\n"); 61 + 62 + static int virtio_debug_filter_feature_del(void *data, u64 val) 63 + { 64 + struct virtio_device *dev = data; 65 + 66 + if (val >= BITS_PER_LONG_LONG) 67 + return -EINVAL; 68 + dev->debugfs_filter_features &= ~BIT_ULL_MASK(val); 69 + return 0; 70 + } 71 + 72 + DEFINE_DEBUGFS_ATTRIBUTE(virtio_debug_filter_feature_del_fops, NULL, 73 + virtio_debug_filter_feature_del, "%llu\n"); 74 + 75 + void virtio_debug_device_init(struct virtio_device *dev) 76 + { 77 + dev->debugfs_dir = debugfs_create_dir(dev_name(&dev->dev), 78 + virtio_debugfs_dir); 79 + debugfs_create_file("device_features", 0400, dev->debugfs_dir, dev, 80 + &virtio_debug_device_features_fops); 81 + debugfs_create_file("filter_features", 0400, dev->debugfs_dir, dev, 82 + &virtio_debug_filter_features_fops); 83 + debugfs_create_file("filter_features_clear", 0200, dev->debugfs_dir, dev, 84 + &virtio_debug_filter_features_clear_fops); 85 + debugfs_create_file("filter_feature_add", 0200, dev->debugfs_dir, dev, 86 + &virtio_debug_filter_feature_add_fops); 87 + debugfs_create_file("filter_feature_del", 0200, dev->debugfs_dir, dev, 88 + &virtio_debug_filter_feature_del_fops); 89 + } 90 + EXPORT_SYMBOL_GPL(virtio_debug_device_init); 91 + 92 + void virtio_debug_device_filter_features(struct virtio_device *dev) 93 + { 94 + dev->features &= ~dev->debugfs_filter_features; 95 + } 96 + EXPORT_SYMBOL_GPL(virtio_debug_device_filter_features); 97 + 98 + void virtio_debug_device_exit(struct virtio_device *dev) 99 + { 100 + debugfs_remove_recursive(dev->debugfs_dir); 101 + } 102 + EXPORT_SYMBOL_GPL(virtio_debug_device_exit); 103 + 104 + void virtio_debug_init(void) 105 + { 106 + virtio_debugfs_dir = debugfs_create_dir("virtio", NULL); 107 + } 108 + EXPORT_SYMBOL_GPL(virtio_debug_init); 109 + 110 + void virtio_debug_exit(void) 111 + { 112 + debugfs_remove_recursive(virtio_debugfs_dir); 113 + } 114 + EXPORT_SYMBOL_GPL(virtio_debug_exit);
+35
include/linux/virtio.h
··· 126 126 * @vqs: the list of virtqueues for this device. 127 127 * @features: the features supported by both driver and device. 128 128 * @priv: private pointer for the driver's use. 129 + * @debugfs_dir: debugfs directory entry. 130 + * @debugfs_filter_features: features to be filtered set by debugfs. 129 131 */ 130 132 struct virtio_device { 131 133 int index; ··· 143 141 struct list_head vqs; 144 142 u64 features; 145 143 void *priv; 144 + #ifdef CONFIG_VIRTIO_DEBUG 145 + struct dentry *debugfs_dir; 146 + u64 debugfs_filter_features; 147 + #endif 146 148 }; 147 149 148 150 #define dev_to_virtio(_dev) container_of_const(_dev, struct virtio_device, dev) ··· 243 237 void virtqueue_dma_sync_single_range_for_device(struct virtqueue *_vq, dma_addr_t addr, 244 238 unsigned long offset, size_t size, 245 239 enum dma_data_direction dir); 240 + 241 + #ifdef CONFIG_VIRTIO_DEBUG 242 + void virtio_debug_device_init(struct virtio_device *dev); 243 + void virtio_debug_device_exit(struct virtio_device *dev); 244 + void virtio_debug_device_filter_features(struct virtio_device *dev); 245 + void virtio_debug_init(void); 246 + void virtio_debug_exit(void); 247 + #else 248 + static inline void virtio_debug_device_init(struct virtio_device *dev) 249 + { 250 + } 251 + 252 + static inline void virtio_debug_device_exit(struct virtio_device *dev) 253 + { 254 + } 255 + 256 + static inline void virtio_debug_device_filter_features(struct virtio_device *dev) 257 + { 258 + } 259 + 260 + static inline void virtio_debug_init(void) 261 + { 262 + } 263 + 264 + static inline void virtio_debug_exit(void) 265 + { 266 + } 267 + #endif 268 + 246 269 #endif /* _LINUX_VIRTIO_H */