Re: Block module crash loading on 5.15.x kernel?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I found it - needed to add:

vhxdev->GenDisk->minors = 1;

On Fri, Aug 19, 2022 at 5:46 PM David F. <df7729@xxxxxxxxx> wrote:
>
> 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);



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux