LINUX.ORG.RU

Сообщения zenbooster

 

dmsetup message - вывод строки результата

Форум — Development

Есть команда dmsetup message ...,

и есть функция device mapper-а:

typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv, char *result, unsigned maxlen);

Можно ли посмотреть содержимое результата result после выполнения упомянутой команды?

Ожидал, что результат будет выведен в stdout, но нет…

 , ,

zenbooster
()

block device driver: не работает чтение

Форум — Development

Ядро: 5.15.0-70-generic.

Я раньше (параметр is_remap=0) в подобной задаче при получении входного запроса bio, формировал свой запрос bio к вышестоящему устройству, и всё работало. Но медленно. Скорость записи на флешку была ~460 kb/sec. Потом я решил пробрасывать запрос bio вышестоящему устройству напрямую (is_remap=1). Если при этом не пытаться модифицировать данные, то всё работает, и скорость возрастает до 1.8 мб/сек т.е. ~ в 4 раза. Но если начать модифицировать данные (а это нужно), то работает только запись. При чтении, dd получает нерасшифрованные данные, а bio в stackbd_end_io_read_cloned (перед этим клонированный с помощью bio_clone_fast в stackbd_io_fn_remap) вообще имеет нулевой размер. При этом размер obio ненулевой. Как такое вообще происходит, и как сделать правильно?

Интересно, что если в stackbd_end_io_read_cloned менять данные после вызова bio_endio, то в dd прилетают расшифрованные данные, но чую, что так делать не правильно. Что подтверждается тем, что fsck после mkfs вешает систему.

Вот, например, я читаю сектор:

user@astra-1:~/git/stackbd/module$ sudo dd if=/dev/stackbd0 count=1 | hexdump -C
00000000  63 d0 18 e5 e3 ee fb a6  ee e9 fc 88 8a a8 a8 88  |c...............|
00000010  8a 88 88 88 88 70 88 88  98 88 8c 88 88 88 88 88  |.....p..........|
00000020  88 48 26 8b 88 b3 88 88  88 88 88 88 8a 88 88 88  |.H&.............|
00000030  89 88 8e 88 88 88 88 88  88 88 88 88 88 88 88 88  |................|
00000040  08 88 a1 57 55 08 9b c6  c7 a8 c6 c9 c5 cd a8 a8  |...WU...........|
00000050  a8 a8 ce c9 dc bb ba a8  a8 a8 86 97 36 ff f4 24  |............6..$|
00000060  aa 48 fc 83 de 3c 86 33  8f 88 45 98 d6 63 78 ba  |.H...<.3..E..cx.|
00000070  6c 45 9e 45 91 63 76 dc  e0 e1 fb a8 e1 fb a8 e6  |lE.E.cv.........|
00000080  e7 fc a8 e9 a8 ea e7 e7  fc e9 ea e4 ed a8 ec e1  |................|
00000090  fb e3 a6 a8 a8 d8 e4 ed  e9 fb ed a8 e1 e6 fb ed  |................|
000000a0  fa fc a8 e9 a8 ea e7 e7  fc e9 ea e4 ed a8 ee e4  |................|
000000b0  e7 f8 f8 f1 a8 e9 e6 ec  85 82 f8 fa ed fb fb a8  |................|
000000c0  e9 e6 f1 a8 e3 ed f1 a8  fc e7 a8 fc fa f1 a8 e9  |................|
000000d0  ef e9 e1 e6 a8 a6 a6 a6  a8 85 82 88 88 88 88 88  |................|
000000e0  88 88 88 88 88 88 88 88  88 88 88 88 88 88 88 88  |................|
*
000001f0  88 88 88 88 88 88 88 88  88 88 88 88 88 88 dd 22  |..............."|
1+0 записей получено
1+0 записей отправлено
512 байт скопировано, 0,0063565 s, 80,5 kB/s
00000200
user@astra-1:~/git/stackbd/module$

И вот, что вижу в логе:

Jun  9 15:24:11 astra-1 kernel: stackbd [task=00000000c60564d5] stackbd_io_fn_remap: HIT.r.1
Jun  9 15:24:11 astra-1 kernel: debugbd [task=00000000c60564d5] debugbd_submit_bio: debugbd: make request read  block 0            #pages 0    total-size 16384     
Jun  9 15:24:11 astra-1 kernel: stackbd [task=00000000c60564d5] stackbd_io_fn_remap: HIT.r.2
Jun  9 15:24:11 astra-1 kernel: stackbd [task=0000000089abc07d] stackbd_end_io_read_cloned: HIT.1
Jun  9 15:24:11 astra-1 kernel: stackbd [task=0000000089abc07d] stackbd_end_io_read_cloned: HIT.2: obio.size=16384; bio.size=0
Jun  9 15:24:11 astra-1 kernel: stackbd [task=0000000089abc07d] stackbd_end_io_read_cloned: HIT.3
Jun  9 15:24:11 astra-1 kernel: stackbd [task=0000000089abc07d] stackbd_end_io_read_cloned: HIT.4
Jun  9 15:24:11 astra-1 kernel: stackbd [task=00000000c60564d5] stackbd_io_fn_remap: HIT.r.1
Jun  9 15:24:11 astra-1 kernel: debugbd [task=00000000c60564d5] debugbd_submit_bio: debugbd: make request read  block 32           #pages 0    total-size 32768     
Jun  9 15:24:11 astra-1 kernel: stackbd [task=00000000c60564d5] stackbd_io_fn_remap: HIT.r.2
Jun  9 15:24:11 astra-1 kernel: stackbd [task=0000000089abc07d] stackbd_end_io_read_cloned: HIT.1
Jun  9 15:24:11 astra-1 kernel: stackbd [task=0000000089abc07d] stackbd_end_io_read_cloned: HIT.2: obio.size=32768; bio.size=0
Jun  9 15:24:11 astra-1 kernel: stackbd [task=0000000089abc07d] stackbd_end_io_read_cloned: HIT.3

debugbd - это тот же драйвер, только выводящий информацию о запросах, для отладки.

Исходный код драйвера stackbd:

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/version.h>
#include <linux/kernel.h> // printk()
#include <linux/fs.h>     // everything...
#include <linux/errno.h>  // error codes
#include <linux/types.h>  // size_t
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/kthread.h>

#include <trace/events/block.h>

#include "logging.h"
#include "../common/stackbd.h"

#define STACKBD_BDEV_MODE (FMODE_READ | FMODE_WRITE | FMODE_EXCL)

#define KERNEL_SECTOR_SHIFT 9
#define KERNEL_SECTOR_SIZE (1 << KERNEL_SECTOR_SHIFT)

#define DECLARE_BIO_VEC struct bio_vec
#define ACCESS_BIO_VEC(x) (x)
#define DECLARE_BVEC_ITER struct bvec_iter
#define BIO_SET_SECTOR(bio, sec) (bio)->bi_iter.bi_sector = (sec)
#define BIO_GET_SECTOR(bio) (bio)->bi_iter.bi_sector
#define BIO_GET_SIZE(bio) (bio)->bi_iter.bi_size
#define BIO_SET_BDEV(bio, bdev) bio_set_dev((bio), (bdev));

//#ifdef CONFIG_LBDAF
#define SEC_FMT "llu"
//#else
//#define SEC_FMT "lu"
//#endif

MODULE_LICENSE("Dual BSD/GPL");

static int major_num = 0;
module_param(major_num, int, 0);
static int LOGICAL_BLOCK_SIZE = 512;
module_param(LOGICAL_BLOCK_SIZE, int, 0);
static bool is_remap = false;
module_param(is_remap, bool, 0);

typedef struct
{
	char path[PATH_MAX];
    fmode_t mode; // используется в aldcc_start / aldcc_stop
	bool is_bdev_raw_ok;
	struct block_device *bdev_raw;
} stackbd_target_t;

/*
 * The internal representation of our device.
 */
static struct stackbd_t {
    sector_t capacity; /* Sectors */
    struct gendisk *gd;
    spinlock_t lock;
    struct bio_list bio_list;
    struct task_struct *thread;
    int is_active;
    stackbd_target_t tgt;
    /* Our request queue */
    struct request_queue *queue;
} stackbd;

static DECLARE_WAIT_QUEUE_HEAD(req_event);

typedef void (* t_stackbd_io_fn)(struct bio *);
static t_stackbd_io_fn p_stackbd_io_fn = NULL;
static struct bio_set bs;

int buffer_read(
	struct stackbd_t *dev,
    unsigned long sector,
    unsigned long nsect,
    char *buffer
)
{
    int result = 0;
    unsigned nsize = nsect << KERNEL_SECTOR_SHIFT;
    int npages = ((nsize - 1) >> PAGE_SHIFT) + 1;
    struct bio *bio;
    struct block_device *bdev = dev->tgt.bdev_raw;

    //PINFO("begin; sector=%ld; nsect=%ld; buffer=%p\n", sector, nsect, buffer);

    if(unlikely(!dev->tgt.is_bdev_raw_ok))
    {
        PERROR("bdev is NULL!\n");
        result = -EFAULT;
        goto out;
    }

    bio = bio_alloc(GFP_NOIO, npages);

    if(unlikely(!bio))
    {
        PERROR("bio_alloc failed!\n");
        result = -ENOMEM;
        goto out;
    }

    BIO_SET_BDEV(bio, bdev);
    BIO_SET_SECTOR(bio, sector);

    bio_set_op_attrs(bio, REQ_OP_READ, REQ_PREFLUSH);

    {
        char *ptr = buffer;
        do
        {
            struct page *page;
            page = virt_to_page(ptr);
            if(unlikely(!page))
            {
                PERROR("virt_to_page failed!\n");
                result = -ENOMEM;
                break;
            }

            {
                unsigned op = offset_in_page(ptr);
                unsigned this_step = min((unsigned)(PAGE_SIZE - op), nsize);
                bio_add_page(bio, page, this_step, op);
                nsize -= this_step;
                ptr += this_step;
            }
        } while(nsize > 0);

        if(likely(!result))
        {
            result = submit_bio_wait(bio);
        }
        bio_put(bio);
    }
out:
    //PINFO("end (%d)\n", result);
    return result;
}

int buffer_write(
    struct stackbd_t *dev,
    unsigned long sector,
    unsigned long nsect,
    char *buffer
)
{
    int result = 0;
    unsigned nsize = nsect << KERNEL_SECTOR_SHIFT;
    int npages = ((nsize - 1) >> PAGE_SHIFT) + 1;
    struct bio *bio;
    struct block_device *bdev = dev->tgt.bdev_raw;

    //PINFO("begin; sector=%ld; nsect=%ld; buffer=%p\n", sector, nsect, buffer);

    if(unlikely(!dev->tgt.is_bdev_raw_ok))
    {
        PERROR("bdev is NULL!\n");
        result = -EFAULT;
        goto out;
    }

    bio = bio_alloc(GFP_NOIO, npages);
    if(unlikely(!bio))
    {
        PERROR("bio_alloc failed!\n");
        result = -ENOMEM;
        goto out;
    }
    BIO_SET_BDEV(bio, bdev);
    BIO_SET_SECTOR(bio, sector);

    bio_set_op_attrs(bio, REQ_OP_WRITE, REQ_PREFLUSH);

    {
        char *ptr = buffer;
        do
        {
            struct page *page = virt_to_page(ptr);

            if(unlikely(!page))
            {
                PERROR("alloc page failed!\n");
                result = -ENOMEM;
                break;
            }

            {
                unsigned op = offset_in_page(ptr);
                unsigned this_step = min((unsigned)(PAGE_SIZE - op), nsize);
                bio_add_page(bio, page, this_step, op);
                nsize -= this_step;
                ptr += this_step;
            }
        } while(nsize > 0);

        if(likely(!result))
        {
	#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
            result = submit_bio_wait(bio);
	#else
            result = submit_bio_wait(WRITE | REQ_FLUSH, bio);
	#endif
        }
        bio_put(bio);
    }
out:
    //PINFO("end (%d)\n", result);
    return result;
}

static void stackbd_end_io_read_cloned(struct bio *bio)
{
    struct bio *obio = bio->bi_private;
    PINFO("HIT.1");
    if (bio_data_dir(bio) == READ)
    {
        DECLARE_BIO_VEC bvec;
        DECLARE_BVEC_ITER iter;

        PINFO("HIT.2: obio.size=%u; bio.size=%u", BIO_GET_SIZE(obio), BIO_GET_SIZE(bio));

        bio_for_each_segment(bvec, bio, iter)
        {
            char *p = page_address(ACCESS_BIO_VEC(bvec).bv_page) + ACCESS_BIO_VEC(bvec).bv_offset;
            int len = ACCESS_BIO_VEC(bvec).bv_len;
            int i;

            print_hex_dump(KERN_INFO, "readed data (1-st 16 bytes) ", DUMP_PREFIX_OFFSET, 16, 1, p, 16, false);

            for(i = 0; i < len; i++)
            {
                //*p++ ^= 0x12345678;
                *p++ ^= 0x88;
            }

            //p += len;
        }
        PINFO("HIT.3");
        bio_put(bio);
        bio_endio(obio);
    }
    else
    {
        bio_put(bio);
        bio_endio(obio);
    }
    //bio_put(bio);
    PINFO("HIT.4");
}

static void stackbd_io_fn_remap(struct bio *bio)
{
    DECLARE_BIO_VEC bvec;
    DECLARE_BVEC_ITER iter;
    struct bio *cbio = bio_clone_fast(bio, GFP_NOIO, &bs);

    BIO_SET_BDEV(cbio, stackbd.tgt.bdev_raw);
    cbio->bi_end_io = stackbd_end_io_read_cloned;
    cbio->bi_private = bio;
    //submit_bio_noacct(cbio);

    //trace_block_bio_remap(/*bdev_get_queue(stackbd.bdev_raw), */bio,
    //    stackbd.tgt.bdev_raw->bd_dev, BIO_GET_SECTOR(bio));

    if (bio_data_dir(bio) == READ)
    {
        PINFO("HIT.r.1");
        submit_bio_noacct(cbio);
        PINFO("HIT.r.2");
    }
    else
    {
        PINFO("HIT.w.1");
        bio_for_each_segment(bvec, cbio, iter)
        {
            char *p = page_address(ACCESS_BIO_VEC(bvec).bv_page) + ACCESS_BIO_VEC(bvec).bv_offset;
            int len = ACCESS_BIO_VEC(bvec).bv_len;
            int i;

            for(i = 0; i < len; i++)
            {
                // *p++ ^= 0x12345678;
                *p++ ^= 0x88;
            }

            print_hex_dump(KERN_INFO, "writed data (1-st 16 bytes) ", DUMP_PREFIX_OFFSET, 16, 1, p, 16, false);

            //p += len;
        }
        PINFO("HIT.w.2");
        submit_bio_noacct(cbio);
        PINFO("HIT.w.3");
    }
}

static void my_bio_complete(struct bio *bio, int ret)
{
    if (ret)
        bio_io_error(bio);
    else
        bio_endio(bio);
}

static void stackbd_io_fn_clone(struct bio *bio)
{
    int res;
    DECLARE_BIO_VEC bvec;
    DECLARE_BVEC_ITER iter;
    sector_t sector = BIO_GET_SECTOR(bio);
    int size = BIO_GET_SIZE(bio);
    int nsect = size >> KERNEL_SECTOR_SHIFT;
    char *src, *p;

    do
    {
		if (bio_data_dir(bio) == READ)
		{
			p = src = kmalloc(size, GFP_KERNEL);
			if (!src)
			{
				PERROR("Unable to allocate read buffer!\n");
				res = -ENOMEM;
				break;
			}

			do
			{
				res = buffer_read(&stackbd, sector, nsect, src);
				if (unlikely(res))
				{
					PERROR("i/o error while read!\n");
					break;
				}

				bio_for_each_segment(bvec, bio, iter)
				{
					char *dst = page_address(ACCESS_BIO_VEC(bvec).bv_page) + ACCESS_BIO_VEC(bvec).bv_offset;
					int len = ACCESS_BIO_VEC(bvec).bv_len;
					memcpy(dst, p, len);
					p += len;
				}
			}
			while (0);
		}
		else
		{
			p = src = kmalloc(size, GFP_KERNEL);
			if (!src)
			{
				PERROR("Unable to allocate write buffer!\n");
				res = -ENOMEM;
				break;
			}

			bio_for_each_segment(bvec, bio, iter)
			{
				char *dst = page_address(ACCESS_BIO_VEC(bvec).bv_page) + ACCESS_BIO_VEC(bvec).bv_offset;
				int len = ACCESS_BIO_VEC(bvec).bv_len;
				memcpy(p, dst, len);
				p += len;
			}
			res = buffer_write(&stackbd, sector, nsect, src);
			if (unlikely(res))
			{
				PERROR("i/o error while write!\n");
			}
		}
		kfree(src);
    }
    while (0);

    my_bio_complete(bio, res);
} // stackbd_io_fn_clone

static int stackbd_threadfn(void *data)
{
    struct bio *bio;

    set_user_nice(current, -20);

    while (!kthread_should_stop())
    {
        /* wake_up() is after adding bio to list. No need for condition */ 
        wait_event_interruptible(req_event, kthread_should_stop() ||
                !bio_list_empty(&stackbd.bio_list));

        spin_lock_irq(&stackbd.lock);
        if (bio_list_empty(&stackbd.bio_list))
        {
            spin_unlock_irq(&stackbd.lock);
            continue;
        }

        bio = bio_list_pop(&stackbd.bio_list);
        spin_unlock_irq(&stackbd.lock);

        p_stackbd_io_fn(bio);
    }

    return 0;
}

// Handle an I/O request.
static blk_qc_t stackbd_submit_bio(struct bio *bio)
{
    /*PINFO("stackbd: make request %-5s block %-12" SEC_FMT " #pages %-4hu total-size %-10u\n",
        bio_data_dir(bio) == WRITE ? "write" : "read",
        BIO_GET_SECTOR(bio),
        bio->bi_vcnt,
        BIO_GET_SIZE(bio)
    );*/

    spin_lock_irq(&stackbd.lock);
    if (!stackbd.tgt.bdev_raw)
    {
        PERROR("Request before bdev_raw is ready, aborting\n");
        goto abort;
    }
    if (!stackbd.is_active)
    {
        PERROR("Device not active yet, aborting\n");
        goto abort;
    }
    bio_list_add(&stackbd.bio_list, bio);
    wake_up(&req_event);
    spin_unlock_irq(&stackbd.lock);

    goto exit;

abort:
    spin_unlock_irq(&stackbd.lock);
    PERROR("<%p> Abort request\n", bio);
    bio_io_error(bio);
exit:
    return BLK_QC_T_NONE;
}

static int stackbd_target_open(stackbd_target_t *p_tdev)
{
    int res = 0;
    char *path = p_tdev->path;

    PINFO("Open %s\n", path);
    {
        struct block_device *bdev_raw = blkdev_get_by_path(path, p_tdev->mode, p_tdev);
        p_tdev->bdev_raw = bdev_raw;

        if (unlikely(IS_ERR(bdev_raw)))
        {
            res = PTR_ERR(bdev_raw);
            PINFO("error opening raw device %s <%d>\n", path, res);
        }

        p_tdev->is_bdev_raw_ok = !res;
        return res;
    }
}

static void stackbd_target_close(stackbd_target_t *p_tdev)
{
    if (p_tdev->is_bdev_raw_ok)
    {
        blkdev_put(p_tdev->bdev_raw, p_tdev->mode);
        p_tdev->bdev_raw = NULL;
        p_tdev->is_bdev_raw_ok = false;
    }
}

static int stackbd_start(char dev_path[])
{
    unsigned max_sectors;
    sector_t lba;

    stackbd_target_t *p_tgt = &stackbd.tgt;
    strcpy(p_tgt->path, dev_path);
    p_tgt->mode = STACKBD_BDEV_MODE;

    if(stackbd_target_open(p_tgt) < 0)
    {
        PERROR("Error while stackbd_target_open(..)!");
        return -EFAULT;
    }

    /* Set up our internal device */
    lba = i_size_read(p_tgt->bdev_raw->bd_inode) >> KERNEL_SECTOR_SHIFT;

    stackbd.capacity = lba;//get_capacity(stackbd.bdev_raw->bd_disk);
    PINFO("Device real capacity: %" SEC_FMT "\n", stackbd.capacity);

    set_capacity(stackbd.gd, stackbd.capacity);

    max_sectors = queue_max_hw_sectors(bdev_get_queue(p_tgt->bdev_raw));
    blk_queue_max_hw_sectors(stackbd.queue, max_sectors);
    PINFO("Max sectors: %u\n", max_sectors);

    stackbd.thread = kthread_create(stackbd_threadfn, NULL,
           stackbd.gd->disk_name);
    if (IS_ERR(stackbd.thread))
    {
        PERROR("error kthread_create <%lu>\n", PTR_ERR(stackbd.thread));
        goto error_after_bdev;
    }

    PINFO("done initializing successfully\n");
    stackbd.is_active = 1;
    wake_up_process(stackbd.thread);

    return 0;

error_after_bdev:
    stackbd_target_close(p_tgt);

    return -EFAULT;
}

static int stackbd_ioctl(struct block_device *bdev, fmode_t mode,
		     unsigned int cmd, unsigned long arg)
{
    char dev_path[80];
    void __user *argp = (void __user *)arg;

    switch (cmd)
    {
    case STACKBD_DO_IT:
        PINFO("\n*** DO IT!!!!!!! ***\n\n");

        if (copy_from_user(dev_path, argp, sizeof(dev_path)))
            return -EFAULT;

        return stackbd_start(dev_path);
    default:
        return -ENOTTY;
    }
}

/*
 * The HDIO_GETGEO ioctl is handled in blkdev_ioctl(), which
 * calls this. We need to implement getgeo, since we can't
 * use tools such as fdisk to partition the drive otherwise.
 */
int stackbd_getgeo(struct block_device * block_device, struct hd_geometry * geo)
{
	long size;

	/* We have no real geometry, of course, so make something up. */
	size = stackbd.capacity * (LOGICAL_BLOCK_SIZE / KERNEL_SECTOR_SIZE);
	geo->cylinders = (size & ~0x3f) >> 6;
	geo->heads = 4;
	geo->sectors = 16;
	geo->start = 0;
	return 0;
}

/*
 * The device operations structure.
 */
static struct block_device_operations stackbd_ops = {
    .owner  = THIS_MODULE,
    .submit_bio = stackbd_submit_bio,
    .getgeo = stackbd_getgeo,
    .ioctl  = stackbd_ioctl,
};

static int __init stackbd_init(void)
{
    PINFO("is_remap=%d\n", is_remap);

    if (is_remap)
    {
        p_stackbd_io_fn = stackbd_io_fn_remap;
    }
    else
    {
        p_stackbd_io_fn = stackbd_io_fn_clone;
    }

    /* Set up our internal device */
    spin_lock_init(&stackbd.lock);

    /* Get registered */
    if ((major_num = register_blkdev(major_num, STACKBD_NAME)) < 0)
    {
        PERROR("unable to get major number\n");
        goto error_after_alloc_queue;
    }

    /* Gendisk structure */
    if (!(stackbd.gd = blk_alloc_disk(NUMA_NO_NODE)))
    {
        PERROR("unable to alloc disk\n");
        goto error_after_register_blkdev;
    }

    stackbd.gd->major = major_num;
    stackbd.gd->first_minor = 0;
    stackbd.gd->minors = 1 << 4;
    stackbd.gd->fops = &stackbd_ops;
    stackbd.gd->private_data = &stackbd;
    strcpy(stackbd.gd->disk_name, STACKBD_NAME_0);
    stackbd.queue = stackbd.gd->queue;

    if(bioset_init(&bs, 64, 0, BIOSET_NEED_BVECS) < 0)
    //if(bioset_init(&bs, BIO_POOL_SIZE, 0, 0) < 0)
    {
        PERROR( "Cannot allocate bioset");
        goto error_after_register_blkdev;
    }

    if(add_disk(stackbd.gd) < 0)
    {
        PERROR("unable to add disk\n");
        goto error_after_register_blkdev;
    }

    PINFO("init done\n");

    return 0;

error_after_register_blkdev:
    unregister_blkdev(major_num, STACKBD_NAME);
error_after_alloc_queue:
    blk_cleanup_queue(stackbd.queue);

    return -EFAULT;
}

static void __exit stackbd_exit(void)
{
    PINFO("exit\n");

    if (stackbd.is_active)
    {
        kthread_stop(stackbd.thread);
        stackbd_target_close(&stackbd.tgt);
    }

    del_gendisk(stackbd.gd);
    put_disk(stackbd.gd);
    bioset_exit(&bs);
    unregister_blkdev(major_num, STACKBD_NAME);
    blk_cleanup_queue(stackbd.queue);
}

module_init(stackbd_init);
module_exit(stackbd_exit);

https://github.com/zenbooster/stackbd/blob/5.15.0-70-generic/module/main.c

 , ,

zenbooster
()

udevadm info не видит поля ID_FS_* для устройства самописного LKM

Форум — Development

Для linux есть самописный драйвер блочного устройства, похожий на драйвер loop. Создаёт по требованию устройства /dev/mycc0, /dev/mycc1 и т.д., смотрящие на некоторые устройства назначения.

После перезагрузки попал в dracut emergency shell указав параметр ядра rd.break=initqueue

Было создано два устройства /dev/loop0 и /dev/mycc0. Оба смотрят на /dev/sda2.

udevadm info для /dev/mycc0 не показывает поля вида ID_FS_UUID, ID_FS_TYPE и т.п. Для /dev/loop0 показывает.

При этом:

1: udevadm test-builtin blkid /sys/class/block/loop0 и udevadm test-builtin blkid /sys/class/block/mycc0 - совпадают! Присутствуют поля ID_FS_UUID, ID_FS_TYPE и т.п. …

2: stat и blkid для /dev/loop и для /dev/mycc0 совпадают

3: cmp -b -l /dev/loop0 /dev/mycc0 - различий не выявлено.

Пример того, что выводит udevadm info:

Выполнил udevadm info /dev/loop0:

P: /devices/virtual/block/loop0
N: loop0
L: 0
E: DEVPATH=/devices/virtual/block/loop0
E: DEVNAME=/dev/loop0
E: DEVTYPE=disk
E: DISKSEQ=4
E: MAJOR=7
E: MINOR=0
E: SUBSYSTEM=block
E: USEC_INITIALIZED=127559842
E: ID_FS_UUID=mvZqUU-Fa0z-F5j3-cEIW-g5XJ-86la-FxNVkH
E: ID_FS_UUID_ENC=mvZqUU-Fa0z-F5j3-cEIW-g5XJ-86la-FxNVkH
E: ID_FS_VERSION=LVM2 001
E: ID_FS_TYPE=LVM2_member
E: ID_FS_USAGE=raid

Выполнил udevadm info /dev/mycc0:

P: /devices/virtual/block/mycc0
N: mycc0
L: 0
E: DEVPATH=/devices/virtual/block/mycc0
E: DEVNAME=/dev/mycc0
E: DEVTYPE=disk
E: DISKSEQ=9
E: MAJOR=252
E: MINOR=0
E: SUBSYSTEM=block

В чём может быть дело?

P.S.: Оба драйвера используют /dev/sda2 для удобства тестирования. На запись я ничего не делаю, и если проверять по отдельности, только loop0 или только mycc0, то картина та же.

 ,

zenbooster
()

Как вызвать IOCTL из пространства ядра в ядре линукс версии 5.10?

Форум — Development

Обработчик IOCTL моего драйвера перенаправляет IOCTL запросы другому драйверу. Это прекрасно работало, но когда понадобилось добавить поддержку ядра 5.10, выяснилось, что старый способ больше не работает. Как теперь это можно провернуть?

    #define TARGET_ID "TGT"
    // ...
    char id[sizeof(TARGET_ID)];
    // ...
    mm_segment_t old_fs = get_fs();
    set_fs(KERNEL_DS);
    res = __blkdev_driver_ioctl(dev->bdev_raw, 0, SCSI_IOCTL_TARGET_ID, (unsigned long)id);
    set_fs(old_fs);

    if(0 == strcmp(id, TARGET_ID))
    {
        PINFO("*** target driver detected! ***\n");
        dev->is_target_driver = true;
    }
    else
    {
        ...

 , , ,

zenbooster
()

блочный LKM из initrd, после загрузки системы пытается использовать тот же номер устройства

Форум — Development

Есть модуль ядра, вроде loop, только его можно попросить создать устройство не для общения с файлом, а для общения с другим блочным устройством (попутно выполняя некоторые преобразования над данными). При старте системы модуль загружается из initrd, и создаёт устройство (по просьбе) /dev/xcc0 для общения с /dev/sda2. Далее, система успешно грузится с /dev/xcc0. После входа в систему, прошу модуль создать ещё одно устройство, для общения с /dev/loop0, а он создаёт мне опять /dev/xcc0. Без initrd всё работает как надо. При необходимости могу выложить код создания устройства, если предоставленной информации будет недостаточно. В чём может быть дело?

 , , , ,

zenbooster
()

вызов generic_make_request из обработчика запросов блочного устройства

Форум — Development

Есть проект: https://github.com/OrenKishon/stackbd - это блочное устройство, которое перенаправляет все запросы на некоторое другое устройство, попутно добавляя информацию об этих запросах в syslog. В качестве подхода к реализации обмена данными выбрано прямое выполнение запроса без использование очереди. Если же переделать код таким образом, что бы очередь использовалась, модуль повисает в том случае, если в устройство записать больше 8 секторов за раз (с помощью dd например, при count=9). С чтением при этом проблем нет.

Есть идеи, почему так, как лечить?

#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
 
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/fs.h>     /* everything... */
#include <linux/errno.h>  /* error codes */
#include <linux/types.h>  /* size_t */
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/kthread.h>
 
#include <trace/events/block.h>
 
#include "../common/stackbd.h"
 
#define USE_BLKMQ 1
 
#if USE_BLKMQ
#include <linux/blk-mq.h>
#endif
 
#define LOGOUT(lvl, fmt, args...) printk(lvl "%s [task=%p] %s: " fmt, THIS_MODULE->name, current, __func__, ## args)
#define PINFO(fmt, args...) LOGOUT(KERN_INFO, fmt, ## args)
#define PWARN(fmt, args...) LOGOUT(KERN_WARNING, fmt, ## args)
#define PERROR(fmt, args...) LOGOUT(KERN_ERR, fmt, ## args)
 
#define STACKBD_BDEV_MODE (FMODE_READ | FMODE_WRITE | FMODE_EXCL)
#define DEBUGGG printk("stackbd: %d\n", __LINE__);
/*
 * We can tweak our hardware sector size, but the kernel talks to us
 * in terms of small sectors, always.
 */
#define KERNEL_SECTOR_SHIFT 9
#define KERNEL_SECTOR_SIZE (1 << KERNEL_SECTOR_SHIFT)
#define KERNEL_PAGE_SHIFT 12
#define KERNEL_PAGE_SIZE (1 << KERNEL_PAGE_SHIFT)
 
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
#   define DECLARE_BIO_VEC struct bio_vec
#   define ACCESS_BIO_VEC(x) (x)
#else
#   define DECLARE_BIO_VEC struct bio_vec *
#   define ACCESS_BIO_VEC(x) (*(x))
#endif
 
MODULE_LICENSE("Dual BSD/GPL");
 
static int major_num = 0;
module_param(major_num, int, 0);
static int LOGICAL_BLOCK_SIZE = 4096;
module_param(LOGICAL_BLOCK_SIZE, int, 0);
 
/*
 * The internal representation of our device.
 */
static struct stackbd_t {
    sector_t capacity; /* Sectors */
    struct gendisk *gd;
    spinlock_t lock;
    struct bio_list bio_list;    
    struct task_struct *thread;
    int is_active;
    struct block_device *bdev_raw;
    /* Our request queue */
    struct request_queue *queue;
#if USE_BLKMQ
    struct blk_mq_tag_set tag_set;
#endif
} stackbd;
 
struct bio_private
{
    void *bi_private_old;
    void *data;
    bool is_ready;
};
 
typedef struct hidden_cmd_s
{
    long ret;
} hidden_cmd_t;
 
 
static DECLARE_WAIT_QUEUE_HEAD(req_event);
 
int ald_buffer_read(
    unsigned long sector,
    unsigned long nsect,
    char *buffer
)
{
    int result = 0;
    unsigned nsize = nsect << KERNEL_SECTOR_SHIFT;
    int npages = ((nsize - 1) >> KERNEL_PAGE_SHIFT) + 1;
    struct bio *bio = bio_alloc(GFP_ATOMIC, npages);
    struct block_device *bdev = stackbd.bdev_raw;
 
    PINFO("begin; sector=%ld; nsect=%ld; buffer=%p\n", sector, nsect, buffer);
 
    if(unlikely(!bio))
    {
        PINFO("bio_alloc failed!\n");
        result = -ENOMEM;
        return result;
    }
    bio_set_dev(bio, bdev);
    bio->bi_iter.bi_sector = sector;
    bio_set_op_attrs(bio, REQ_OP_READ, 0);
    {
        char *ptr = buffer;
        do
        {
            struct page *page;
            page = virt_to_page(ptr);
            if(unlikely(!page))
            {
                PINFO("virt_to_page failed!\n");
                result = -ENOMEM;
                break;
            }
 
            {
                unsigned this_step = min((unsigned)(PAGE_SIZE - offset_in_page(ptr)), nsize);
                bio_add_page(bio, page, this_step, offset_in_page(ptr));
                nsize -= this_step;
                ptr += this_step;
            }
        } while(nsize > 0);
 
        if(likely(!result))
        {
            result = submit_bio_wait(bio);
        }
        bio_put(bio);
    }
    PINFO("end (%d)\n", result);
    return result;
}
 
int ald_buffer_write(
    unsigned long sector,
    unsigned long nsect,
    char *buffer
)
{
    int result = 0;
    unsigned nsize = nsect << KERNEL_SECTOR_SHIFT;
    int npages = ((nsize - 1) >> KERNEL_PAGE_SHIFT) + 1;
    struct bio *bio = bio_alloc(GFP_ATOMIC, npages);
    struct block_device *bdev = stackbd.bdev_raw;
 
    PINFO("begin; sector=%ld; nsect=%ld; buffer=%p\n", sector, nsect, buffer);
 
    if(unlikely(!bio))
    {
        PINFO("bio_alloc failed!\n");
        result = -ENOMEM;
        return result;
    }
    bio_set_dev(bio, bdev);
    bio->bi_iter.bi_sector = sector;
    bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
    {
        char *ptr = buffer;
        do
        {
            struct page *page = virt_to_page(ptr);
 
            if(unlikely(!page))
            {
                PINFO("alloc page failed!\n");
                result = -ENOMEM;
                break;
            }
 
            {
                unsigned op = offset_in_page(ptr);
                unsigned this_step = min((unsigned)(KERNEL_PAGE_SIZE - op), nsize);
                bio_add_page(bio, page, this_step, op);
                nsize -= this_step;
                ptr += this_step;
            }
        } while(nsize > 0);
 
        if(likely(!result))
        {
            result = submit_bio_wait(bio);
        }
        bio_put(bio);
    }
    PINFO("end (%d)\n", result);
    return result;
}
 
#if USE_BLKMQ
static void pb_alloc(struct bio *bio, void *data)
{
    struct bio_private *pb = kmalloc(sizeof(struct bio_private), GFP_ATOMIC);
 
    pb->bi_private_old = bio->bi_private;
    pb->data = data;
    pb->is_ready = false;
    bio->bi_private = pb;
}
 
static void pb_free(struct bio *bio)
{
    struct bio_private *pb = bio->bi_private;
    void *t = bio->bi_private;
    bio->bi_private = pb->bi_private_old;
    kfree(t);
}
#endif
 
static void my_bio_complete(struct bio *bio, int ret)
{
#if USE_BLKMQ
   struct bio_private *pb = bio->bi_private;
   struct request *rq = pb->data;
 
   pb_free(bio);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
   blk_mq_end_request(rq, ret ? BLK_STS_IOERR : BLK_STS_OK);
#else
   blk_mq_end_io(rq, ret ? BLK_STS_IOERR : BLK_STS_OK);
#endif
 
#else // #if USE_BLKMQ
    bio_endio(bio);
#endif // #if USE_BLKMQ
}
 
 
static void stackbd_io_fn(struct bio *bio)
{
    sector_t sector = bio->bi_iter.bi_sector;
    int size = bio->bi_iter.bi_size;
    int nsect = size >> KERNEL_SECTOR_SHIFT;
    DECLARE_BIO_VEC bvec;
    struct bvec_iter iter;
    u8 *buffer = kmalloc(size, GFP_ATOMIC);
    u8 *ptr = buffer;
 
    if (bio_data_dir(bio) == READ)
    {
        ald_buffer_read(sector, nsect, ptr);
 
        bio_for_each_segment(bvec, bio, iter)
        {
            u8 *dst = page_address(ACCESS_BIO_VEC(bvec).bv_page) + ACCESS_BIO_VEC(bvec).bv_offset;
            int len = ACCESS_BIO_VEC(bvec).bv_len;
            memcpy(dst, ptr, len);
            ptr += len;
        }
    }
    else
    {
        bio_for_each_segment(bvec, bio, iter)
        {
            u8 *src = page_address(ACCESS_BIO_VEC(bvec).bv_page) + ACCESS_BIO_VEC(bvec).bv_offset;
            int len = ACCESS_BIO_VEC(bvec).bv_len;
            memcpy(ptr, src, len);
            ptr += len;
        }
        ald_buffer_write(sector, nsect, buffer);
    }
    kfree(buffer);
    my_bio_complete(bio, 0);
}
 
static int stackbd_threadfn(void *data)
{
    struct bio *bio;
 
    set_user_nice(current, -20);
 
    while (!kthread_should_stop())
    {
        /* wake_up() is after adding bio to list. No need for condition */ 
        wait_event_interruptible(req_event, kthread_should_stop() ||
                !bio_list_empty(&stackbd.bio_list));
 
        spin_lock_irq(&stackbd.lock);
        if (bio_list_empty(&stackbd.bio_list))
        {
            spin_unlock_irq(&stackbd.lock);
            continue;
        }
 
        bio = bio_list_pop(&stackbd.bio_list);
        spin_unlock_irq(&stackbd.lock);
 
        stackbd_io_fn(bio);
    }
 
    return 0;
}
 
#if USE_BLKMQ
//#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 3)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
static blk_status_t hidden_queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data* bd)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
static blk_status_t hidden_queue_rq(struct blk_mq_hw_ctx *hctx, struct request* rq, bool last)
#else
static blk_status_t hidden_queue_rq(struct blk_mq_hw_ctx *hctx, struct request* rq)
#endif
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
    struct request *rq = bd->rq;
#endif
    struct bio *bio = rq->bio;
    pb_alloc(bio, rq);
    spin_lock_irq(&stackbd.lock);
    if (!stackbd.bdev_raw)
    {
        printk("stackbd: Request before bdev_raw is ready, aborting\n");
        goto abort;
    }
    if (!stackbd.is_active)
    {
        printk("stackbd: Device not active yet, aborting\n");
        goto abort;
    }
 
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
    blk_mq_start_request(rq);
#endif
 
    bio_list_add(&stackbd.bio_list, bio);
    wake_up(&req_event);
exit:
    spin_unlock_irq(&stackbd.lock);
 
//exit:
    return BLK_STS_OK; //always return ok
abort:
    my_bio_complete(bio, -EIO);
    goto exit;
}
 
static struct blk_mq_ops _mq_ops =
{
    .queue_rq = hidden_queue_rq,
#if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 2, 0)
    .map_queue = blk_mq_map_queue
#endif
};
#else // #if USE_BLKMQ
/*
 * Handle an I/O request.
 */
static blk_qc_t stackbd_make_request(struct request_queue *q, struct bio *bio)
{
    printk("stackbd: make request %-5s block %-12lu #pages %-4hu total-size "
            "%-10u\n", bio_data_dir(bio) == WRITE ? "write" : "read",
            bio->bi_iter.bi_sector, bio->bi_vcnt, bio->bi_iter.bi_size);
 
//    printk("<%p> Make request %s %s %s\n", bio,
//           bio->bi_rw & REQ_SYNC ? "SYNC" : "",
//           bio->bi_rw & REQ_FLUSH ? "FLUSH" : "",
//           bio->bi_rw & REQ_NOIDLE ? "NOIDLE" : "");
//
    spin_lock_irq(&stackbd.lock);
    if (!stackbd.bdev_raw)
    {
        printk("stackbd: Request before bdev_raw is ready, aborting\n");
        goto abort;
    }
    if (!stackbd.is_active)
    {
        printk("stackbd: Device not active yet, aborting\n");
        goto abort;
    }
    bio_list_add(&stackbd.bio_list, bio);
    wake_up(&req_event);
    spin_unlock_irq(&stackbd.lock);
 
    goto exit;
 
abort:
    spin_unlock_irq(&stackbd.lock);
    printk("<%p> Abort request\n\n", bio);
    bio_io_error(bio);
exit:
    return BLK_QC_T_NONE;
}
#endif // #if USE_BLKMQ
 
static struct block_device *stackbd_bdev_open(char dev_path[])
{
    /* Open underlying device */
    struct block_device *bdev_raw = lookup_bdev(dev_path);
    printk("Opened %s\n", dev_path);
 
    if (IS_ERR(bdev_raw))
    {
        printk("stackbd: error opening raw device <%lu>\n", PTR_ERR(bdev_raw));
        return NULL;
    }
 
    if (!bdget(bdev_raw->bd_dev))
    {
        printk("stackbd: error bdget()\n");
        return NULL;
    }
 
    if (blkdev_get(bdev_raw, STACKBD_BDEV_MODE, &stackbd))
    {
        printk("stackbd: error blkdev_get()\n");
        bdput(bdev_raw);
        return NULL;
    }
 
    return bdev_raw;
}
 
static int stackbd_start(char dev_path[])
{
    unsigned max_sectors;
 
    if (!(stackbd.bdev_raw = stackbd_bdev_open(dev_path)))
        return -EFAULT;
 
    /* Set up our internal device */
    stackbd.capacity = get_capacity(stackbd.bdev_raw->bd_disk);
    printk("stackbd: Device real capacity: %lu\n", stackbd.capacity);
 
    set_capacity(stackbd.gd, stackbd.capacity);
 
    max_sectors = queue_max_hw_sectors(bdev_get_queue(stackbd.bdev_raw));
    blk_queue_max_hw_sectors(stackbd.queue, max_sectors);
    printk("stackbd: Max sectors: %u\n", max_sectors);
 
    stackbd.thread = kthread_create(stackbd_threadfn, NULL,
           stackbd.gd->disk_name);
    if (IS_ERR(stackbd.thread))
    {
        printk("stackbd: error kthread_create <%lu>\n",
               PTR_ERR(stackbd.thread));
        goto error_after_bdev;
    }
 
    printk("stackbd: done initializing successfully\n");
    stackbd.is_active = 1;
    wake_up_process(stackbd.thread);
 
    return 0;
 
error_after_bdev:
    blkdev_put(stackbd.bdev_raw, STACKBD_BDEV_MODE);
    bdput(stackbd.bdev_raw);
 
    return -EFAULT;
}
 
static int stackbd_ioctl(struct block_device *bdev, fmode_t mode,
             unsigned int cmd, unsigned long arg)
{
    char dev_path[80];
    void __user *argp = (void __user *)arg;    
 
    switch (cmd)
    {
    case STACKBD_DO_IT:
        printk("\n*** DO IT!!!!!!! ***\n\n");
 
        if (copy_from_user(dev_path, argp, sizeof(dev_path)))
            return -EFAULT;
 
        return stackbd_start(dev_path);
    default:
        return -ENOTTY;
    }
}
 
/*
 * The HDIO_GETGEO ioctl is handled in blkdev_ioctl(), which
 * calls this. We need to implement getgeo, since we can't
 * use tools such as fdisk to partition the drive otherwise.
 */
int stackbd_getgeo(struct block_device * block_device, struct hd_geometry * geo)
{
    long size;
 
    /* We have no real geometry, of course, so make something up. */
    size = stackbd.capacity * (LOGICAL_BLOCK_SIZE / KERNEL_SECTOR_SIZE);
    geo->cylinders = (size & ~0x3f) >> 6;
    geo->heads = 4;
    geo->sectors = 16;
    geo->start = 0;
    return 0;
}
 
/*
 * The device operations structure.
 */
static struct block_device_operations stackbd_ops = {
        .owner  = THIS_MODULE,
        .getgeo = stackbd_getgeo,
        .ioctl  = stackbd_ioctl,
};
 
static int __init stackbd_init(void)
{
    /* Set up our internal device */
    spin_lock_init(&stackbd.lock);
 
    /* blk_alloc_queue() instead of blk_init_queue() so it won't set up the
     * queue for requests.
     */
#if USE_BLKMQ
    stackbd.tag_set.ops = &_mq_ops;
    stackbd.tag_set.nr_hw_queues = 1;
    stackbd.tag_set.queue_depth = 128;
    stackbd.tag_set.numa_node = NUMA_NO_NODE;
    stackbd.tag_set.cmd_size = sizeof(hidden_cmd_t);
    stackbd.tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE | BLK_MQ_F_BLOCKING;
    stackbd.tag_set.driver_data = &stackbd;
 
    {
        int res = blk_mq_alloc_tag_set(&stackbd.tag_set);
        if (res)
        {
            PWARN("unable to allocate tag set (%d)\n", res);
            return -EFAULT;
        }
    }
    stackbd.queue = blk_mq_init_queue(&stackbd.tag_set);
    if (IS_ERR(stackbd.queue))
    {
        int res = PTR_ERR(stackbd.queue);
        PWARN("Failed to allocate queue (%d)", res);
        return -EFAULT;
    }
#else
    if (!(stackbd.queue = blk_alloc_queue(GFP_KERNEL)))
    {
        printk("stackbd: alloc_queue failed\n");
        return -EFAULT;
    }
 
    blk_queue_make_request(stackbd.queue, stackbd_make_request);
#endif
    blk_queue_logical_block_size(stackbd.queue, LOGICAL_BLOCK_SIZE);
 
    /* Get registered */
    if ((major_num = register_blkdev(major_num, STACKBD_NAME)) < 0)
    {
        printk("stackbd: unable to get major number\n");
        goto error_after_alloc_queue;
    }
 
    /* Gendisk structure */
    if (!(stackbd.gd = alloc_disk(16)))
        goto error_after_redister_blkdev;
    stackbd.gd->major = major_num;
    stackbd.gd->first_minor = 0;
    stackbd.gd->fops = &stackbd_ops;
    stackbd.gd->private_data = &stackbd;
    strcpy(stackbd.gd->disk_name, STACKBD_NAME_0);
    stackbd.gd->queue = stackbd.queue;
    add_disk(stackbd.gd);
 
    printk("stackbd: init done\n");
 
    return 0;
 
error_after_redister_blkdev:
    unregister_blkdev(major_num, STACKBD_NAME);
error_after_alloc_queue:
    blk_cleanup_queue(stackbd.queue);
 
    return -EFAULT;
}
 
static void __exit stackbd_exit(void)
{
    printk("stackbd: exit\n");
 
    if (stackbd.is_active)
    {
        kthread_stop(stackbd.thread);
        blkdev_put(stackbd.bdev_raw, STACKBD_BDEV_MODE);
        bdput(stackbd. bdev_raw);
    }
 
    del_gendisk(stackbd.gd);
    put_disk(stackbd.gd);
    unregister_blkdev(major_num, STACKBD_NAME);
    blk_cleanup_queue(stackbd.queue);
#if USE_BLKMQ
    if (stackbd.tag_set.tags)
        blk_mq_free_tag_set(&stackbd.tag_set);
#endif
}
 
module_init(stackbd_init);
module_exit(stackbd_exit);

 , , , ,

zenbooster
()

(usb) device not accepting address xx, error -62

Форум — Linux-hardware

версия ос: slackware 14.2; ядро: vmlinuz-huge-4.4.29 (no smp); железо: неттоп ebox 3350 mx ap (аналог pentium mmx), 512 mb RAM;

Проблема с подключением usb футсвича. Девайс должен определяться как usb keyboard, и для него должно создаваться устройство /dev/hidraw0, но вместо этого на ядре 4.4.29 имеем:

[ 1727.292545] usb 2-2: new low-speed USB device number 11 using ohci-pci
[ 1727.696464] usb 2-2: device not accepting address 11, error -62
[ 1727.853444] usb 2-2: new low-speed USB device number 12 using ohci-pci
[ 1728.257378] usb 2-2: device not accepting address 12, error -62
[ 1728.414344] usb 2-2: new low-speed USB device number 13 using ohci-pci
[ 1728.576310] usb 2-2: device descriptor read/64, error -62
[ 1728.839265] usb 2-2: device descriptor read/64, error -62
[ 1729.097225] usb 2-2: new low-speed USB device number 14 using ohci-pci
[ 1729.259194] usb 2-2: device descriptor read/64, error -62
[ 1729.522149] usb 2-2: device descriptor read/64, error -62
[ 1729.623174] usb usb2-port2: unable to enumerate USB device

Проблема возникла еще на дефолтном ядре (no smp), которое ставится при установке, 4.4.14 кажется... Но тогда все заработало после выполнения команды:

echo Y | tee /sys/module/usbcore/parameters/old_scheme_first
и пере подключения устройства. После того, как ядро обновилось этот способ (как и usbcore.old_scheme_first=1 в параметрах загрузки ядра) уже не работает.

lsusb устройство не видит.

Под windows устройство корректно распознается.

Под убунтой тоже:

[130596.678339] usb 2-2.1: new low-speed USB device number 4 using uhci_hcd
[130596.958525] usb 2-2.1: New USB device found, idVendor=4242, idProduct=e131
[130596.958529] usb 2-2.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[130596.958543] usb 2-2.1: Product: FSW-02A
[130596.958545] usb 2-2.1: Manufacturer: www.footswitch.ru
[130596.958546] usb 2-2.1: SerialNumber: 00101
[130597.358672] input: www.footswitch.ru FSW-02A as /devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/2-2/2-2.1/2-2.1:1.0/0003:4242:E131.0003/input/input7
[130597.458709] hid-generic 0003:4242:E131.0003: input,hidraw2: USB HID v1.01 Keyboard [www.footswitch.ru FSW-02A] on usb-0000:02:00.0-2.1/input0

 

zenbooster
()

RSS подписка на новые темы