public inbox for linux-block@vger.kernel.org
 help / color / mirror / Atom feed
* kernel oops when rmmod'ing ublk_drv w/ missing UBLK_CMD_START_DEV
@ 2023-01-25 19:50 Harris, James R
  2023-01-25 20:05 ` Jens Axboe
  0 siblings, 1 reply; 4+ messages in thread
From: Harris, James R @ 2023-01-25 19:50 UTC (permalink / raw)
  To: linux-block@vger.kernel.org, ming.lei@redhat.com

Hi,

I can reliably hit a kernel oops with ublk_drv using the following abnormal sequence of events (repro .c file at end of this e-mail):

1) modprobe ublk_drv
2) run test app which basically does:
  a) submit UBLK_CMD_ADD_DEV
  b) submit UBLK_CMD_SET_PARAMS
  c) wait for completions
  d) do *not* submit UBLK_CMD_START_DEV
  e) exit
3) rmmod ublk_drv

Reproduces on 6.2-rc5, 6.1.5 and 6.1.

Regards,

Jim Harris


[  859.178944] ------------[ cut here ]------------
[  859.178950] sysfs group 'power' not found for kobject 'ublkc0'
[  859.178962] WARNING: CPU: 3 PID: 1109 at fs/sysfs/group.c:278 sysfs_remove_group+0x9c/0xb0
[  859.178980] Modules linked in: ublk_drv(-) nvme_fabrics nvme_core binfmt_misc nls_iso8859_1 uio_pdrv_genirq uio ramoops reed_solomon pstore_blk pstore_zone efi_pstore autofs4 btrfs blake2b_generic raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor xor_neon raid6_pq libcrc32c raid1 raid0 linear virtio_gpu virtio_dma_buf drm_shmem_helper drm_kms_helper syscopyarea sysfillrect sysimgblt usbhid hid drm crct10dif_ce ghash_ce sha3_ce virtio_net sha3_generic sha512_ce sha512_arm64 sha2_ce sha256_arm64 ahci_platform net_failover sha1_ce libahci_platform failover xhci_pci backlight libahci xhci_pci_renesas aes_neon_bs aes_neon_blk aes_ce_blk aes_ce_cipher
[  859.179044] CPU: 3 PID: 1109 Comm: rmmod Not tainted 6.2.0-rc5 #33
[  859.179048] Hardware name: Parallels International GmbH. Parallels ARM Virtual Machine/Parallels ARM Virtual Platform, BIOS 17.1.6 (51584) Thu, 01 Dec 202
[  859.179051] pstate: 61400005 (nZCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
[  859.179055] pc : sysfs_remove_group+0x9c/0xb0
[  859.179060] lr : sysfs_remove_group+0x9c/0xb0
[  859.179066] sp : ffff80000b9c3c20
[  859.179067] x29: ffff80000b9c3c20 x28: ffff0000c08f4100 x27: 0000000000000000
[  859.179072] x26: 0000000000000000 x25: 0000000000000000 x24: 0000000000000000
[  859.179075] x23: ffff0000c0263800 x22: 0000000000000000 x21: ffff0000ccfae170
[  859.179078] x20: ffff800008fa5648 x19: 0000000000000000 x18: 0000000000000000
[  859.179080] x17: 5453595342555300 x16: ffff8000084dc2c0 x15: 6b6c62752f637369
[  859.179083] x14: 0000000000000001 x13: 2730636b6c627527 x12: 207463656a626f6b
[  859.179086] x11: 20726f6620646e75 x10: 6f6620746f6e2027 x9 : ffff800008209b5c
[  859.179089] x8 : 20746f6e20277265 x7 : 0000000000000001 x6 : 0000000000000001
[  859.179092] x5 : ffff0001feb9eb48 x4 : ffff80000b9c3a60 x3 : ffff8001f525f000
[  859.179095] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff0000c08f4100
[  859.179098] Call trace:
[  859.179099]  sysfs_remove_group+0x9c/0xb0
[  859.179105]  dpm_sysfs_remove+0x64/0xb0
[  859.179113]  device_del+0xac/0x3a0
[  859.179119]  cdev_device_del+0x28/0x70
[  859.179125]  ublk_exit+0x84/0xe90 [ublk_drv]
[  859.179137]  __arm64_sys_delete_module+0x180/0x31c
[  859.179143]  invoke_syscall+0x78/0x100
[  859.179151]  el0_svc_common.constprop.0+0x54/0x190
[  859.179157]  do_el0_svc+0x44/0xd0
[  859.179162]  el0_svc+0x2c/0xb4
[  859.179169]  el0t_64_sync_handler+0xbc/0x13c
[  859.179174]  el0t_64_sync+0x1a4/0x1a8
[  859.179178] ---[ end trace 0000000000000000 ]---
[  859.179304] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000070
[  859.179347] Mem abort info:
[  859.179362]   ESR = 0x0000000096000004
[  859.179380]   EC = 0x25: DABT (current EL), IL = 32 bits
[  859.179406]   SET = 0, FnV = 0
[  859.179418]   EA = 0, S1PTW = 0
[  859.179431]   FSC = 0x04: level 0 translation fault
[  859.179450] Data abort info:
[  859.179462]   ISV = 0, ISS = 0x00000004
[  859.179478]   CM = 0, WnR = 0
[  859.179491] user pgtable: 4k pages, 48-bit VAs, pgdp=0000000103cbd000
[  859.179508] [0000000000000070] pgd=0000000000000000, p4d=0000000000000000
[  859.179532] Internal error: Oops: 0000000096000004 [#1] SMP
[  859.179551] Modules linked in: ublk_drv(-) nvme_fabrics nvme_core binfmt_misc nls_iso8859_1 uio_pdrv_genirq uio ramoops reed_solomon pstore_blk pstore_zone efi_pstore autofs4 btrfs blake2b_generic raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor xor_neon raid6_pq libcrc32c raid1 raid0 linear virtio_gpu virtio_dma_buf drm_shmem_helper drm_kms_helper syscopyarea sysfillrect sysimgblt usbhid hid drm crct10dif_ce ghash_ce sha3_ce virtio_net sha3_generic sha512_ce sha512_arm64 sha2_ce sha256_arm64 ahci_platform net_failover sha1_ce libahci_platform failover xhci_pci backlight libahci xhci_pci_renesas aes_neon_bs aes_neon_blk aes_ce_blk aes_ce_cipher
[  859.179694] CPU: 3 PID: 1109 Comm: rmmod Tainted: G        W          6.2.0-rc5 #33
[  859.179714] Hardware name: Parallels International GmbH. Parallels ARM Virtual Machine/Parallels ARM Virtual Platform, BIOS 17.1.6 (51584) Thu, 01 Dec 202
[  859.179744] pstate: 81400005 (Nzcv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
[  859.179760] pc : sysfs_delete_link+0x58/0xe0
[  859.179789] lr : device_remove_class_symlinks+0x94/0xb0
[  859.179817] sp : ffff80000b9c3c20
[  859.179833] x29: ffff80000b9c3c20 x28: ffff0000c08f4100 x27: 0000000000000000
[  859.179851] x26: 0000000000000000 x25: 0000000000000000 x24: ffff80000a1e9a78
[  859.179866] x23: ffff0000c0263800 x22: ffff000191691b00 x21: ffff0000ccfae170
[  859.179881] x20: ffff80000a1b9000 x19: ffff0000c373c018 x18: 0000000000000000
[  859.179897] x17: 5453595342555300 x16: ffff8000084dc2c0 x15: ffff800009e151f8
[  859.179912] x14: 0000000000000000 x13: 0000000000000003 x12: ffff800009dddbb0
[  859.179928] x11: 0000000000000000 x10: ffff800185ccd9c7 x9 : ffff800008aa2164
[  859.179944] x8 : 0101010101010101 x7 : 7f7f7f7f7f7f7f7f x6 : fefefefefefeff6c
[  859.179959] x5 : 8080808080808000 x4 : 0000000000000000 x3 : ffff8000091e4a79
[  859.179975] x2 : ffff0000c49e9280 x1 : 0000000000000000 x0 : 0000000000000000
[  859.179995] Call trace:
[  859.180007]  sysfs_delete_link+0x58/0xe0
[  859.180031]  device_remove_class_symlinks+0x94/0xb0
[  859.180053]  device_del+0xe8/0x3a0
[  859.180072]  cdev_device_del+0x28/0x70
[  859.180093]  ublk_exit+0x84/0xe90 [ublk_drv]
[  859.180120]  __arm64_sys_delete_module+0x180/0x31c
[  859.180144]  invoke_syscall+0x78/0x100
[  859.180169]  el0_svc_common.constprop.0+0x54/0x190
[  859.180647]  do_el0_svc+0x44/0xd0
[  859.181085]  el0_svc+0x2c/0xb4
[  859.181489]  el0t_64_sync_handler+0xbc/0x13c
[  859.181882]  el0t_64_sync+0x1a4/0x1a8
[  859.182301] Code: 350003a0 f9401aa2 b40000a2 f9401a60 (7940e000)
[  859.182777] ---[ end trace 0000000000000000 ]—

===

#include <linux/ublk_cmd.h>
#include <liburing.h>
#include <stdlib.h>
#include <assert.h>

#define UBLK_CTRL_DEV                   "/dev/ublk-control"
#define UBLK_CTRL_RING_DEPTH            32
#define UBLK_IO_MAX_BYTES               65536
#define UBLK_ID                         0

struct ublk_dev;
static void ublk_ctrl_cmd(uint32_t cmd_op);

static int g_fd;
static struct io_uring g_ring;
static uint32_t g_count;

static struct ublksrv_ctrl_dev_info g_dev_info = {
        .queue_depth = 32,
        .nr_hw_queues = 1,
        .dev_id = UBLK_ID,
        .max_io_buf_bytes = UBLK_IO_MAX_BYTES,
        .flags = UBLK_F_URING_CMD_COMP_IN_TASK,
};

static struct ublk_params g_params = {
        .types = UBLK_PARAM_TYPE_BASIC,
        .len = sizeof(g_params),
        .basic = {
                .logical_bs_shift = 9,
                .physical_bs_shift = 9,
                .io_min_shift = 9,
                .io_opt_shift = 12,
                .dev_sectors = 2048,
                .max_sectors = UBLK_IO_MAX_BYTES >> 9,
        }
};

static void
ublk_ctrl_poller(void)
{
        struct io_uring_cqe *cqe;
        int rc;

        while (1) {
                rc = io_uring_peek_cqe(&g_ring, &cqe);
                if (rc == -EAGAIN) {
                        break;
                }
                assert(cqe != NULL);
                io_uring_cqe_seen(&g_ring, cqe);
                g_count++;
        }
}

static void
ublk_ctrl_cmd(uint32_t cmd_op)
{
        int rc = -EINVAL;
        struct io_uring_sqe *sqe;
        struct ublksrv_ctrl_cmd *cmd;

        sqe = io_uring_get_sqe(&g_ring);
        assert(sqe != NULL);
        cmd = (struct ublksrv_ctrl_cmd *)&sqe->addr3;
        sqe->fd = g_fd;
        sqe->opcode = IORING_OP_URING_CMD;
        sqe->off = cmd_op;
        sqe->ioprio = 0;
        cmd->dev_id = UBLK_ID;
        cmd->queue_id = -1;

        switch (cmd_op) {
        case UBLK_CMD_ADD_DEV:
                cmd->addr = (__u64)(uintptr_t)&g_dev_info;
                cmd->len = sizeof(g_dev_info);
                break;
        case UBLK_CMD_SET_PARAMS:
                cmd->addr = (__u64)(uintptr_t)&g_params;
                cmd->len = sizeof(g_params);
                break;
        default:
                assert(false);
                break;
        }
        rc = io_uring_submit(&g_ring);
        assert(rc > 0);
}

int main(int argc, char **argv)
{
        struct io_uring_params p = {};
        int rc;

        g_fd = open(UBLK_CTRL_DEV, O_RDWR);
        assert(g_fd >= 0);
        p.flags = IORING_SETUP_SQE128 | IORING_SETUP_SQPOLL | IORING_SETUP_CQSIZE;
        p.cq_entries = UBLK_CTRL_RING_DEPTH;
        rc = io_uring_queue_init_params(UBLK_CTRL_RING_DEPTH, &g_ring, &p);
        assert(rc == 0);
        g_dev_info.ublksrv_pid = getpid();
        ublk_ctrl_cmd(UBLK_CMD_ADD_DEV);
        ublk_ctrl_cmd(UBLK_CMD_SET_PARAMS);
        while (g_count < 2) {
                ublk_ctrl_poller();
        }
        return 0;
}


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: kernel oops when rmmod'ing ublk_drv w/ missing UBLK_CMD_START_DEV
  2023-01-25 19:50 kernel oops when rmmod'ing ublk_drv w/ missing UBLK_CMD_START_DEV Harris, James R
@ 2023-01-25 20:05 ` Jens Axboe
  2023-01-25 20:43   ` Harris, James R
  2023-01-26 11:33   ` Ming Lei
  0 siblings, 2 replies; 4+ messages in thread
From: Jens Axboe @ 2023-01-25 20:05 UTC (permalink / raw)
  To: Harris, James R, linux-block@vger.kernel.org, ming.lei@redhat.com

On 1/25/23 12:50?PM, Harris, James R wrote:
> Hi,
> 
> I can reliably hit a kernel oops with ublk_drv using the following abnormal sequence of events (repro .c file at end of this e-mail):
> 
> 1) modprobe ublk_drv
> 2) run test app which basically does:
>   a) submit UBLK_CMD_ADD_DEV
>   b) submit UBLK_CMD_SET_PARAMS
>   c) wait for completions
>   d) do *not* submit UBLK_CMD_START_DEV
>   e) exit
> 3) rmmod ublk_drv
> 
> Reproduces on 6.2-rc5, 6.1.5 and 6.1.

Something like this may do it, but I'll let Ming sort out the details
on what's the most appropriate fix.


diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 17b677b5d3b2..dacc13e2a476 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -1149,11 +1149,17 @@ static void ublk_unquiesce_dev(struct ublk_device *ub)
 	blk_mq_kick_requeue_list(ub->ub_disk->queue);
 }
 
-static void ublk_stop_dev(struct ublk_device *ub)
+/*
+ * Returns if the device was live or not
+ */
+static bool ublk_stop_dev(struct ublk_device *ub)
 {
+	bool was_live = false;
+
 	mutex_lock(&ub->mutex);
 	if (ub->dev_info.state == UBLK_S_DEV_DEAD)
 		goto unlock;
+	was_live = true;
 	if (ublk_can_use_recovery(ub)) {
 		if (ub->dev_info.state == UBLK_S_DEV_LIVE)
 			__ublk_quiesce_dev(ub);
@@ -1168,6 +1174,7 @@ static void ublk_stop_dev(struct ublk_device *ub)
 	ublk_cancel_dev(ub);
 	mutex_unlock(&ub->mutex);
 	cancel_delayed_work_sync(&ub->monitor_work);
+	return was_live;
 }
 
 /* device can only be started after all IOs are ready */
@@ -1470,7 +1477,8 @@ static int ublk_add_tag_set(struct ublk_device *ub)
 
 static void ublk_remove(struct ublk_device *ub)
 {
-	ublk_stop_dev(ub);
+	if (!ublk_stop_dev(ub))
+		return;
 	cancel_work_sync(&ub->stop_work);
 	cancel_work_sync(&ub->quiesce_work);
 	cdev_device_del(&ub->cdev, &ub->cdev_dev);
@@ -1771,7 +1779,8 @@ static int ublk_ctrl_stop_dev(struct io_uring_cmd *cmd)
 	if (!ub)
 		return -EINVAL;
 
-	ublk_stop_dev(ub);
+	if (!ublk_stop_dev(ub))
+		return -EINVAL;
 	cancel_work_sync(&ub->stop_work);
 	cancel_work_sync(&ub->quiesce_work);
 

-- 
Jens Axboe


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: kernel oops when rmmod'ing ublk_drv w/ missing UBLK_CMD_START_DEV
  2023-01-25 20:05 ` Jens Axboe
@ 2023-01-25 20:43   ` Harris, James R
  2023-01-26 11:33   ` Ming Lei
  1 sibling, 0 replies; 4+ messages in thread
From: Harris, James R @ 2023-01-25 20:43 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-block@vger.kernel.org, ming.lei@redhat.com



> On Jan 25, 2023, at 1:05 PM, Jens Axboe <axboe@kernel.dk> wrote:
> 
> On 1/25/23 12:50?PM, Harris, James R wrote:
>> Hi,
>> 
>> I can reliably hit a kernel oops with ublk_drv using the following abnormal sequence of events (repro .c file at end of this e-mail):
>> 
>> 1) modprobe ublk_drv
>> 2) run test app which basically does:
>>  a) submit UBLK_CMD_ADD_DEV
>>  b) submit UBLK_CMD_SET_PARAMS
>>  c) wait for completions
>>  d) do *not* submit UBLK_CMD_START_DEV
>>  e) exit
>> 3) rmmod ublk_drv
>> 
>> Reproduces on 6.2-rc5, 6.1.5 and 6.1.
> 
> Something like this may do it, but I'll let Ming sort out the details
> on what's the most appropriate fix.

Thanks Jens.  This patch fixes things for me.  If you and Ming decide to go forward
with this patch, feel free to add:

Tested-by: Jim Harris <james.r.harris@intel.com>

> 
> 
> diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
> index 17b677b5d3b2..dacc13e2a476 100644
> --- a/drivers/block/ublk_drv.c
> +++ b/drivers/block/ublk_drv.c
> @@ -1149,11 +1149,17 @@ static void ublk_unquiesce_dev(struct ublk_device *ub)
> 	blk_mq_kick_requeue_list(ub->ub_disk->queue);
> }
> 
> -static void ublk_stop_dev(struct ublk_device *ub)
> +/*
> + * Returns if the device was live or not
> + */
> +static bool ublk_stop_dev(struct ublk_device *ub)
> {
> +	bool was_live = false;
> +
> 	mutex_lock(&ub->mutex);
> 	if (ub->dev_info.state == UBLK_S_DEV_DEAD)
> 		goto unlock;
> +	was_live = true;
> 	if (ublk_can_use_recovery(ub)) {
> 		if (ub->dev_info.state == UBLK_S_DEV_LIVE)
> 			__ublk_quiesce_dev(ub);
> @@ -1168,6 +1174,7 @@ static void ublk_stop_dev(struct ublk_device *ub)
> 	ublk_cancel_dev(ub);
> 	mutex_unlock(&ub->mutex);
> 	cancel_delayed_work_sync(&ub->monitor_work);
> +	return was_live;
> }
> 
> /* device can only be started after all IOs are ready */
> @@ -1470,7 +1477,8 @@ static int ublk_add_tag_set(struct ublk_device *ub)
> 
> static void ublk_remove(struct ublk_device *ub)
> {
> -	ublk_stop_dev(ub);
> +	if (!ublk_stop_dev(ub))
> +		return;
> 	cancel_work_sync(&ub->stop_work);
> 	cancel_work_sync(&ub->quiesce_work);
> 	cdev_device_del(&ub->cdev, &ub->cdev_dev);
> @@ -1771,7 +1779,8 @@ static int ublk_ctrl_stop_dev(struct io_uring_cmd *cmd)
> 	if (!ub)
> 		return -EINVAL;
> 
> -	ublk_stop_dev(ub);
> +	if (!ublk_stop_dev(ub))
> +		return -EINVAL;
> 	cancel_work_sync(&ub->stop_work);
> 	cancel_work_sync(&ub->quiesce_work);
> 
> 
> -- 
> Jens Axboe
> 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: kernel oops when rmmod'ing ublk_drv w/ missing UBLK_CMD_START_DEV
  2023-01-25 20:05 ` Jens Axboe
  2023-01-25 20:43   ` Harris, James R
@ 2023-01-26 11:33   ` Ming Lei
  1 sibling, 0 replies; 4+ messages in thread
From: Ming Lei @ 2023-01-26 11:33 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Harris, James R, linux-block@vger.kernel.org, ming.lei

On Wed, Jan 25, 2023 at 01:05:55PM -0700, Jens Axboe wrote:
> On 1/25/23 12:50?PM, Harris, James R wrote:
> > Hi,
> > 
> > I can reliably hit a kernel oops with ublk_drv using the following abnormal sequence of events (repro .c file at end of this e-mail):
> > 
> > 1) modprobe ublk_drv
> > 2) run test app which basically does:
> >   a) submit UBLK_CMD_ADD_DEV
> >   b) submit UBLK_CMD_SET_PARAMS
> >   c) wait for completions
> >   d) do *not* submit UBLK_CMD_START_DEV
> >   e) exit
> > 3) rmmod ublk_drv
> > 
> > Reproduces on 6.2-rc5, 6.1.5 and 6.1.
> 
> Something like this may do it, but I'll let Ming sort out the details
> on what's the most appropriate fix.

Hi Jens and James,

The ublk char device still needs to be deleted even though START_DEV
isn't called given the char device is added in ADD_DEV's handler, so
the current logic is correct.

The root cause is that 'ublk_chr_class' is destroyed too early, so
the following patch should fix the issue.

diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index 17b677b5d3b2..e54693204630 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -2092,13 +2092,12 @@ static void __exit ublk_exit(void)
        struct ublk_device *ub;
        int id;

-       class_destroy(ublk_chr_class);
-
-       misc_deregister(&ublk_misc);
-
        idr_for_each_entry(&ublk_index_idr, ub, id)
                ublk_remove(ub);

+       class_destroy(ublk_chr_class);
+       misc_deregister(&ublk_misc);
+
        idr_destroy(&ublk_index_idr);
        unregister_chrdev_region(ublk_chr_devt, UBLK_MINORS);
 }


Thanks, 
Ming


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-01-26 11:34 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-01-25 19:50 kernel oops when rmmod'ing ublk_drv w/ missing UBLK_CMD_START_DEV Harris, James R
2023-01-25 20:05 ` Jens Axboe
2023-01-25 20:43   ` Harris, James R
2023-01-26 11:33   ` Ming Lei

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox