I have a private custom block module that has been around since the kernel 4.x days. Every once in a while it wouldn't build on a kernel update, so I'd have to figure out what you do with the new kernel (luckily most of the time someone else already asked and found the solution). This break happened again with the kernel 5.15.x update. The last kernel I built this for was and it was working was 5.10.x. I found examples of what is done now, however, it's not working for me. I'm getting a crash / failure when calling the add_disk() function. Is there something I'm missing? I took out the 4.x specific code from below, but left the other 5.x stuff in. Here's a skeleton outline of the module (the failure occurs on insmod of the kernel which is just creating a block device that doesn't do much but look for ioctl requests). Can one of the expects look at what I may be doing wrong? Here's that skeleton code: #include <linux/module.h> #include <linux/kernel.h> #include <linux/version.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/spinlock.h> #include <linux/genhd.h> #include <linux/blkdev.h> #include <linux/errno.h> #include <linux/sched.h> // for set_user_nice #include <linux/math64.h> #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)) #include <linux/blk-mq.h> #endif //--------------------- // Macro //--------------------- #define MIN_NICE -20 // can't find it on this system. #define BUFFERmaxElements(s) (sizeof(s)/sizeof((s)[0])) #define SZBUFFERmaxStrLen(s) ((sizeof(s)/sizeof((s)[0]))-1) #define NUMdevicesDefault 10 #define NUMdevicesMin 2 #define NUMdevicesMax 27 //--------------------- // Types //---------------------- typedef struct _sVHXMountDev { spinlock_t Lock; // lock for device access struct mutex IOCTLLock; // mutext for handling of ioctl #if (LINUX_VERSION_CODE < KERNEL_VERSION(5,15,0)) struct request_queue *Queue; // request queue for device #endif struct gendisk *GenDisk; // kernel disk device #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)) struct blk_mq_tag_set tag_set; // new blk_mq method #endif unsigned int OpenCount; // keep track if device open void *VHXMountObj; // CVHXMount mounted object for vhx file (C version) } sVHXMountDev, *psVHXMountDev; //---------------------- // Parameters //---------------------- static unsigned int MajorDevNum=0; module_param(MajorDevNum, uint, 0444); static unsigned int NumDevices=NUMdevicesDefault; module_param(NumDevices, uint, 0444); //---------------------- // Local Data //---------------------- static const char VHXMountDevName[]="vhx"; static const char VHXMountDevNameFmt[]="vhx%c"; static sVHXMountDev *VHXMountDevArr=NULL; unsigned int VHXMountMajor=0; unsigned int VHXMountNumDevices=NUMdevicesDefault; //------------------------------------------------------------------------- // Block operations structure //------------------------------------------------------------------------- static struct block_device_operations VHXMountBlockOps= { .owner = THIS_MODULE, // required initialization .open = VHXMountOpen, // open device function .release = VHXMountClose, // close device function .ioctl = VHXMountIOCTL, // the ioctl handler #if defined(CONFIG_COMPAT) .compat_ioctl = VHXMountIOCTL, // no special version needed #endif }; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)) static struct blk_mq_ops _mq_ops = { .queue_rq = VHXMountRequest, }; #endif //------------------------------------------------------------------------- // Purpose: Uninitialize device // // Input: vhxdev - [io] device to uninitalize // // Output: na // // Notes: This removes a mounted drive // static void VHXUnintializeDevice(sVHXMountDev *vhxdev) { //printk(KERN_DEBUG "VHXUninitializeDevice(%p)", vhxdev); int devindex=-1; // check if gen disk setup if (vhxdev->GenDisk) { devindex=vhxdev->GenDisk->first_minor / VHXMOUNT_MINOR_CNT; //printk(KERN_DEBUG "VHXUninitializeDevice: gendisk"); // stop new requests from arriving (okay to call del_gendisk without add_gendisk) del_gendisk(vhxdev->GenDisk); #if (LINUX_VERSION_CODE > KERNEL_VERSION(5,10,0)) blk_cleanup_disk(vhxdev->GenDisk); #else put_disk(vhxdev->GenDisk); #endif vhxdev->GenDisk=NULL; } #if (LINUX_VERSION_CODE < KERNEL_VERSION(5,15,0)) // check if queue setup if (vhxdev->Queue) { //printk(KERN_DEBUG "VHXUninitializeDevice: queue"); blk_cleanup_queue(vhxdev->Queue); vhxdev->Queue=NULL; } #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)) // free blk_mq tag item if (vhxdev->tag_set.tags) { blk_mq_free_tag_set(&vhxdev->tag_set); } #endif //printk(KERN_DEBUG "VHXUninitializeDevice: object"); // close down the object if it exists VHXMountObjDelete(vhxdev->VHXMountObj); vhxdev->VHXMountObj=NULL; if (devindex>=0) { printk(KERN_INFO "VHXMount %i: driver uninstalled.\n", devindex); } } //------------------------------------------------------------------------- // Purpose: Sets up the device being mounted per the arguments // // Input: vhxdev - [o] device to initialize // devindex - [i] device index being initialized // ioctlarg - [i] arguments for mounting vhx file // // Output: negative error code or zero if success // // Notes: ioctl is used to cause mounting of image file // static int VHXMountSetupDevice(sVHXMountDev *vhxdev, unsigned int devindex, const sVHXMountIOCTLArg *ioctlarg) { // ensure structure is zeroed memset(vhxdev, 0, sizeof(*vhxdev)); // check if master device or actual mount if (ioctlarg!=NULL) { // N/A - REMOVED } // init spinlock for request queue spin_lock_init(&vhxdev->Lock); // init mutext mutex_init(&vhxdev->IOCTLLock); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0)) memset(&vhxdev->tag_set, 0, sizeof(vhxdev->tag_set)); vhxdev->tag_set.ops = &_mq_ops; vhxdev->tag_set.nr_hw_queues = 1; vhxdev->tag_set.nr_maps = 1; vhxdev->tag_set.queue_depth = 128; vhxdev->tag_set.numa_node = NUMA_NO_NODE; vhxdev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE /*| BLK_MQ_F_SG_MERGE*/; vhxdev->tag_set.driver_data = vhxdev; { int ret = blk_mq_alloc_tag_set(&vhxdev->tag_set); if (ret) { printk (KERN_WARNING "VHXMount: unable to allocate and initialize tag set. Error %i\n", ret); VHXUnintializeDevice(vhxdev); return ret; } } vhxdev->GenDisk = blk_mq_alloc_disk(&vhxdev->tag_set, vhxdev); if (IS_ERR(vhxdev->GenDisk)) { int err=PTR_ERR(vhxdev->GenDisk); printk(KERN_ERR "VHXMount %i: blk_mq_alloc_disk failure (%i).\n", devindex, err); VHXUnintializeDevice(vhxdev); return err; } #else vhxdev->tag_set.cmd_size = 0; vhxdev->tag_set.driver_data = vhxdev; vhxdev->Queue = blk_mq_init_sq_queue (&vhxdev->tag_set, &_mq_ops, 128, BLK_MQ_F_SHOULD_MERGE /*| BLK_MQ_F_SG_MERGE*/); if (IS_ERR (vhxdev->Queue)) { int ret = PTR_ERR (vhxdev->Queue); printk (KERN_WARNING "VHXMount: unable to allocate and initialize tag set. Error %i\n", ret); vhxdev->Queue=NULL; VHXUnintializeDevice(vhxdev); return ret; } vhxdev->Queue->queuedata = vhxdev; // setup the gendisk structure vhxdev->GenDisk = alloc_disk(VHXMOUNT_MINOR_CNT); if (!vhxdev->GenDisk) { printk(KERN_ERR "VHXMount %i: alloc_disk failure.\n", devindex); VHXUnintializeDevice(vhxdev); return -ENOMEM; } // setup the gendisk structure vhxdev->GenDisk->queue = vhxdev->Queue; #endif vhxdev->GenDisk->major = VHXMountMajor; vhxdev->GenDisk->first_minor = VHXMOUNT_MINOR_CNT*devindex; vhxdev->GenDisk->flags |= GENHD_FL_NO_PART_SCAN; //GENHD_FL_SUPPRESS_PARTITION_INFO; // use to stop from being added to /proc/partitions vhxdev->GenDisk->fops = &VHXMountBlockOps; vhxdev->GenDisk->private_data = vhxdev; set_disk_ro(vhxdev->GenDisk, 1); // add items for non master device if (vhxdev->VHXMountObj) { snprintf(vhxdev->GenDisk->disk_name, BUFFERmaxElements(vhxdev->GenDisk->disk_name), VHXMountDevNameFmt, devindex+'a'-1); set_capacity(vhxdev->GenDisk, VHXMountObjGetTotalSectors(vhxdev->VHXMountObj)*(VHXMountObjGetBytesPerSector(vhxdev->VHXMountObj)/KERNEL_SECTOR_SIZE)); //printk(KERN_DEBUG "Set capacity to %llu sectors\n", (uint64_t) get_capacity(vhxdev->GenDisk)); // setup worker thread } else { // master device strncpy(vhxdev->GenDisk->disk_name, VHXMountDevName, SZBUFFERmaxStrLen(vhxdev->GenDisk->disk_name)); } // do this last as several functions can be called prior to this returning int err=add_disk(vhxdev->GenDisk); /* ####################################################################### ####################################################################### This is where there is a dump in the message log for 5.15.60 showing: Aug 20 00:06:19 (none) user.warn kernel: ------------[ cut here ]------------ Aug 20 00:06:19 (none) user.warn kernel: WARNING: CPU: 0 PID: 891 at block/genhd.c:416 device_add_disk+0x37/0x336 Aug 20 00:06:19 (none) user.warn kernel: Modules linked in: vhdxmount(PO+) hid_generic sg usbhid usb_storage hid sr_mod sd_mod cdrom nvme i2c_i801 nvme_core i2c_smbus evdev ahci libahci i2c_core tulip pcspkr xhci_pci xhci_hcd ehci_pci t10_pi ehci_hcd thermal video butt Aug 20 00:06:19 (none) user.warn kernel: CPU: 0 PID: 891 Comm: insmod Tainted: P W O 5.15.60-amd64-custom #1 Aug 20 00:06:19 (none) user.warn kernel: Hardware name: /DH77KC, BIOS KCH7710H.86A.0111.2018.0329.1405 03/29/2018 Aug 20 00:06:19 (none) user.warn kernel: RIP: 0010:device_add_disk+0x37/0x336 Aug 20 00:06:19 (none) user.warn kernel: Code: f6 41 55 41 54 53 51 48 8b 7e 50 48 8b 5e 40 48 89 55 d0 e8 26 fe fe ff 41 83 3e 00 4c 8d 6b 40 74 46 41 8b 46 08 85 c0 75 04 <0f> 0b eb 43 3d 00 01 00 00 7e 19 be 00 01 00 00 48 c7 c7 58 2b de Aug 20 00:06:19 (none) user.warn kernel: RSP: 0018:ffffc900000cfc38 EFLAGS: 00010246 Aug 20 00:06:19 (none) user.warn kernel: RAX: 0000000000000000 RBX: ffff88803dabd2c0 RCX: ffff88800df96dc0 Aug 20 00:06:19 (none) user.warn kernel: RDX: 0000000000000000 RSI: 0000000000000286 RDI: ffff88800df96dd0 Aug 20 00:06:19 (none) user.warn kernel: RBP: ffffc900000cfc68 R08: 0000000000000000 R09: ffffc900000cfb68 Aug 20 00:06:19 (none) user.warn kernel: R10: 0000000000000286 R11: 000000000000026c R12: ffff88803d6fc000 Aug 20 00:06:19 (none) user.warn kernel: R13: ffff88803dabd300 R14: ffff88800df02000 R15: 0000000000000000 Aug 20 00:06:19 (none) user.warn kernel: FS: 0000000000000000(0000) GS:ffff888100200000(0063) knlGS:00000000f7f45a80 Aug 20 00:06:19 (none) user.warn kernel: CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033 Aug 20 00:06:19 (none) user.warn kernel: CR2: 00000000f7e32461 CR3: 000000003ce86003 CR4: 00000000000606f0 Aug 20 00:06:19 (none) user.warn kernel: Call Trace: Aug 20 00:06:19 (none) user.warn kernel: <TASK> Aug 20 00:06:19 (none) user.warn kernel: VHXMountSetupDevice+0x1da/0x20e [vhdxmount] Aug 20 00:06:19 (none) user.warn kernel: ? 0xffffffffa00f9000 Aug 20 00:06:19 (none) user.warn kernel: VHXMountInitC+0x117/0x1000 [vhdxmount] Aug 20 00:06:19 (none) user.warn kernel: do_one_initcall+0x64/0x144 Aug 20 00:06:19 (none) user.warn kernel: ? kmem_cache_alloc+0x73/0x82 Aug 20 00:06:19 (none) user.warn kernel: do_init_module+0x48/0x1e3 Aug 20 00:06:19 (none) user.warn kernel: load_module+0x1c96/0x224a Aug 20 00:06:19 (none) user.warn kernel: __do_sys_finit_module+0x9a/0xab Aug 20 00:06:19 (none) user.warn kernel: __ia32_sys_finit_module+0x14/0x16 Aug 20 00:06:19 (none) user.warn kernel: __do_fast_syscall_32+0xa4/0xcb Aug 20 00:06:19 (none) user.warn kernel: do_fast_syscall_32+0x34/0x72 Aug 20 00:06:19 (none) user.warn kernel: do_SYSENTER_32+0x1f/0x21 Aug 20 00:06:19 (none) user.warn kernel: entry_SYSENTER_compat_after_hwframe+0x4d/0x5c Aug 20 00:06:19 (none) user.warn kernel: RIP: 0023:0xf7f04549 Aug 20 00:06:19 (none) user.warn kernel: Code: 03 74 c0 01 10 05 03 74 b8 01 10 06 03 74 b4 01 10 07 03 74 b0 01 10 08 03 74 d8 01 00 00 00 00 00 51 52 55 89 e5 0f 34 cd 80 <5d> 5a 59 c3 90 90 90 90 8d b4 26 00 00 00 00 8d b4 26 00 00 00 00 Aug 20 00:06:19 (none) user.warn kernel: RSP: 002b:00000000ffefd3dc EFLAGS: 00000296 ORIG_RAX: 000000000000015e Aug 20 00:06:19 (none) user.warn kernel: RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00000000f7f2446c Aug 20 00:06:19 (none) user.warn kernel: RDX: 0000000000000000 RSI: 0000000057f25220 RDI: 0000000057f242a0 Aug 20 00:06:19 (none) user.warn kernel: RBP: 00000000f7f227bc R08: 0000000000000000 R09: 0000000000000000 Aug 20 00:06:19 (none) user.warn kernel: R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 Aug 20 00:06:19 (none) user.warn kernel: R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 Aug 20 00:06:19 (none) user.warn kernel: </TASK> Aug 20 00:06:19 (none) user.warn kernel: ---[ end trace e02aadea0ffa66da ]--- Aug 20 00:06:19 (none) user.err kernel: VHXMount 0: failed to add disk (-22). Aug 20 00:06:19 (none) user.info kernel: VHXMount 0: driver uninstalled. ####################################################################### ####################################################################### */ if (err!=0) { printk(KERN_ERR "VHXMount %i: failed to add disk (%i).\n", devindex, err); VHXUnintializeDevice(vhxdev); return err; } // disk now exists printk(KERN_INFO "VHXMount %i: driver installed.\n", devindex); return 0; } //------------------------------------------------------------------------- // Purpose: Required registration and init for linux driver // // Input: na // // Output: // // Notes: // static int __init VHXMountInitC(void) { int result; // assign parameters over to values so they don't change during run. VHXMountMajor=MajorDevNum; VHXMountNumDevices=NumDevices; // validate num devices values if (VHXMountNumDevices<NUMdevicesMin) { VHXMountNumDevices=NUMdevicesMin; } else if (VHXMountNumDevices>NUMdevicesMax) { VHXMountNumDevices=NUMdevicesMax; } // assign back to variables for output to /sys/module/vhxmount/parameters NumDevices=VHXMountNumDevices; // register block device // if VHXMountMajor!=0 then returns 0 on success and negative on error // if VHXMountMajor==0 then returns the new major num 1-255 or negative on error result=register_blkdev(VHXMountMajor, VHXMountDevName); if (result<=0) { printk(KERN_ERR "VHXMount: register_blkdev failure.\n"); return -EBUSY; } // assign return device num if major was zero if (VHXMountMajor==0) { VHXMountMajor=result; MajorDevNum=result; } // allocate array for preallocated devices if ((VHXMountDevArr=(sVHXMountDev*)kmalloc(VHXMountNumDevices*sizeof(sVHXMountDev), GFP_KERNEL))==NULL) { unregister_blkdev(VHXMountMajor, VHXMountDevName); return -ENOMEM; } // zero memory error of array memset(VHXMountDevArr, 0, VHXMountNumDevices*sizeof(sVHXMountDev)); // setup master device VHXMountSetupDevice(VHXMountDevArr, 0, NULL); return 0; } //------------------------------------------------------------------------- // Purpose: Remove linux driver // // Input: na // // Output: // // Notes: // static void __exit VHXMountRemoveC(void) { // handle each device for (unsigned int i=0;i<VHXMountNumDevices;i++) { // uninitialize device VHXUnintializeDevice(VHXMountDevArr+i); } // handle cleanup of block device unregister_blkdev(VHXMountMajor, VHXMountDevName); // clean up array kfree(VHXMountDevArr); VHXMountDevArr=NULL; } //---------------------- // Driver Information //---------------------- module_init(VHXMountInitC); module_exit(VHXMountRemoveC); MODULE_LICENSE("Proprietary"); MODULE_AUTHOR("Acme, Inc."); MODULE_DESCRIPTION("VHXMount Driver"); MODULE_ALIAS_BLOCKDEV_MAJOR(MajorDevNum);