#!/usr/bin/bpftrace /* * log rbd opens and releases * * run like: * * bpftrace -I /lib/modules/$(uname -r)/source/drivers/block -I /lib/modules/$(uname -r)/build this_script * * This assumes you have the appropriate linux source and build * artifacts available on the machine where you're running bpftrace. * * Note: * https://github.com/iovisor/bpftrace/pull/2315 * BTF for kernel modules * * Once that lands in your local bpftrace you hopefully don't need the linux * source and build stuff, nor the 'extracted' stuff below, and you should be * able to simply run this script like: * * chmod +x ./this_script * ./this_script * */ //////////////////////////////////////////////////////////// // extracted from // linux/drivers/block/rbd.c // #include #include #include #include #include "rbd_types.h" /* * An RBD device name will be "rbd#", where the "rbd" comes from * RBD_DRV_NAME above, and # is a unique integer identifier. */ #define DEV_NAME_LEN 32 /* * block device image metadata (in-memory version) */ struct rbd_image_header { /* These six fields never change for a given rbd image */ char *object_prefix; __u8 obj_order; u64 stripe_unit; u64 stripe_count; s64 data_pool_id; u64 features; /* Might be changeable someday? */ /* The remaining fields need to be updated occasionally */ u64 image_size; struct ceph_snap_context *snapc; char *snap_names; /* format 1 only */ u64 *snap_sizes; /* format 1 only */ }; enum rbd_watch_state { RBD_WATCH_STATE_UNREGISTERED, RBD_WATCH_STATE_REGISTERED, RBD_WATCH_STATE_ERROR, }; enum rbd_lock_state { RBD_LOCK_STATE_UNLOCKED, RBD_LOCK_STATE_LOCKED, RBD_LOCK_STATE_RELEASING, }; /* WatchNotify::ClientId */ struct rbd_client_id { u64 gid; u64 handle; }; struct rbd_mapping { u64 size; }; /* * a single device */ struct rbd_device { int dev_id; /* blkdev unique id */ int major; /* blkdev assigned major */ int minor; struct gendisk *disk; /* blkdev's gendisk and rq */ u32 image_format; /* Either 1 or 2 */ struct rbd_client *rbd_client; char name[DEV_NAME_LEN]; /* blkdev name, e.g. rbd3 */ spinlock_t lock; /* queue, flags, open_count */ struct rbd_image_header header; unsigned long flags; /* possibly lock protected */ struct rbd_spec *spec; struct rbd_options *opts; char *config_info; /* add{,_single_major} string */ struct ceph_object_id header_oid; struct ceph_object_locator header_oloc; struct ceph_file_layout layout; /* used for all rbd requests */ struct mutex watch_mutex; enum rbd_watch_state watch_state; struct ceph_osd_linger_request *watch_handle; u64 watch_cookie; struct delayed_work watch_dwork; struct rw_semaphore lock_rwsem; enum rbd_lock_state lock_state; char lock_cookie[32]; struct rbd_client_id owner_cid; struct work_struct acquired_lock_work; struct work_struct released_lock_work; struct delayed_work lock_dwork; struct work_struct unlock_work; spinlock_t lock_lists_lock; struct list_head acquiring_list; struct list_head running_list; struct completion acquire_wait; int acquire_err; struct completion releasing_wait; spinlock_t object_map_lock; u8 *object_map; u64 object_map_size; /* in objects */ u64 object_map_flags; struct workqueue_struct *task_wq; struct rbd_spec *parent_spec; u64 parent_overlap; atomic_t parent_ref; struct rbd_device *parent; /* Block layer tags. */ struct blk_mq_tag_set tag_set; /* protects updating the header */ struct rw_semaphore header_rwsem; struct rbd_mapping mapping; struct list_head node; /* sysfs related */ struct device dev; unsigned long open_count; /* protected by lock */ }; // // end of extraction //////////////////////////////////////////////////////////// kprobe:rbd_open { $bdev = (struct block_device *)arg0; $rbd_dev = (struct rbd_device *)($bdev->bd_disk->private_data); printf("%s O %d %s %lu %s\n", strftime("%T.%f", nsecs), pid, $rbd_dev->name, $rbd_dev->open_count, comm ); } kprobe:rbd_release { $disk = (struct gendisk *)arg0; $rbd_dev = (struct rbd_device *)($disk->private_data); printf("%s R %d %s %lu %s\n", strftime("%T.%f", nsecs), pid, $rbd_dev->name, $rbd_dev->open_count, comm ); }