Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kernel block device

I'm currently trying to implement a (not that ?) simple kernel block device driver.

I inspired mainly from the book Linux Device Drivers, 3rd Edition which is not totally up-to-date anymore as it was published in 2005.

Anyway the logic is still there and I learnt a lot from it. However examples are not really effective as many things have changed since 2005.

I found a github repository where examples should be updated to work on recent kernels but I think there is still some things to update as I can't adapt examples to make it work on kernel 4.9.0

Here is how my module is made:

At initialization :

  • Register the module as block device with register_blkdev
  • Allocate the device data buffer
  • Initialize spinlock
  • Initialize request queue
  • Configure request queue
  • Allocate gendisk structure
  • Fill gendisk structure
  • Create the disk with add_disk

Then I implemented a function to handle request events from request queue and treat read and write events on the block device.

Here is the function : (It's highly inspired from LLD-3rd with some modifications to match current kernel functions)

static void block_mod_request(struct request_queue *queue)
{
    printk(KERN_NOTICE "Entering request function\n");
    struct request *request;

    while(NULL != (request = blk_fetch_request(queue)))
    {
        blk_mod_t *self = request->rq_disk->private_data;
        // Check if request is a filesystem request (i.e. moves block of data)
        if(REQ_TYPE_FS != request->cmd_type)
        {
            // Close request with unsuccessful status
            printk(KERN_WARNING "Skip non-fs request\n");
            __blk_end_request_cur(request, -EIO);
            continue;
        }
        // Treat request
        block_mod_transfer(self, blk_rq_pos(request), blk_rq_cur_sectors(request), request->buffer, rq_data_dir(request));
        // Close request with successful status
        __blk_end_request_cur(request, 0);
    }
    return;
}

However at compiling I got the following error:

block_mod.c:82:91: error: ‘struct request’ has no member named ‘buffer’
         block_mod_transfer(self, blk_rq_pos(request), blk_rq_cur_sectors(request), request->buffer, rq_data_dir(request));

After checking file blkdev.h into kernel v4.9.0 headers, it seems that the field buffer no longer exists into struct request.
However I'm not able to find any information on how things have evolved and how to modify the code to make it work.

If I understand well, the buffer field is supposed to be a pointer to a virtual kernel address. I suppose that once this buffer filled/read the kernel handles the transfer of data to/from userspace.

I'm kinda lost because I can't find where I should find the kernel virtual address if it's not given by the request anymore.

How am I supposed to know where to transfert data?

like image 220
Arkaik Avatar asked Apr 11 '18 17:04

Arkaik


People also ask

What is block device in Linux?

Block devices are nonvolatile mass storage devices whose information can be accessed in any order. Hard disks, floppy disks, and CD-ROMs are examples of block devices. OpenBoot typically uses block devices for booting.

What is block device in OS?

Block devices − A block device is one with which the driver communicates by sending entire blocks of data. For example, Hard disks, USB cameras, Disk-On-Key etc. Character devices − A character device is one with which the driver communicates by sending and receiving single characters (bytes, octets).

Is Ram a block device?

Block devices are characterized by random access to data organized in fixed-size blocks. Examples of such devices are hard drives, CD-ROM drives, RAM disks, etc.

How do I access a blocked device in Linux?

The block devices on a system can be discovered with the lsblk (list block devices) command. Try it in the VM below. Type lsblk at the command prompt and then press Enter.


Video Answer


1 Answers

The message from the commit containing the culprit change, authored by Ming Lei:

block: remove struct request buffer member

This was used in the olden days, back when onions were proper yellow. Basically it mapped to the current buffer to be transferred. With highmem being added more than a decade ago, most drivers map pages out of a bio, and rq->buffer isn't pointing at anything valid.

Convert old style drivers to just use bio_data().

There are some good resources for reading about BIO, such as this post on lwn. A relevant snippet:

char *bio_data(struct bio *bio)

  Returns the kernel virtual address for the data buffer.

So it looks like you will have more success using bio_data(rq->bio) in place of rq->buffer.

Edit by author:
Also found this link which is in two parts and presents in first part the bio layer and in second part the request layer.

like image 146
HolyHoratio Avatar answered Oct 14 '22 15:10

HolyHoratio