Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read a sector using bio request in Linux kernel

I want to read only one sector from hard disk to a specific page in memory, this page is reserved and is not mapped to any address mapping. I found this solution but I don't know how to translate a file to a block device and a sector. For example, in function do_generic_file_read in file mm/filemap.c there is this line:

error = mapping->a_ops->readpage(filp, page);

since the target page is not of any mapping I cannot use the same function, but I need to translate the filp to a device and a sector to be able to generate my own bio request. how can I do this?

Edit 1

I tried this as a possible solution, by adding this, It first calculates the sector, then directly calls ext2_get_block to get the device, It then adds the desired page location and submits the bio request:

struct page *myPage;
int myRet;
struct buffer_head bh;
struct bio *bio = bio_alloc(GFP_NOIO,1);
myPage = pfn_to_page(Some_Location);
bio_init(bio);
bio->bi_sector = (sector_t)page_offset << (PAGE_CACHE_SHIFT - mapping->host->i_blkbits);
myRet = ext2_get_block(mapping->host, bio->bi_sector, &bh, 0);
bio->bi_bdev = bh.b_bdev;
bio->bi_next = NULL;
bio->bi_size = PAGE_SIZE;
bio_add_page(bio, myPage, PAGE_SIZE, 0);
submit_bio(READ, bio);

This uses the existing address mapping in the function to create the bio request, since the desired page does not have an address mapping. It only has one problem, the submit_bio line causes this:

[    4.792142] ------------[ cut here ]------------
[    4.792892] WARNING: at arch/x86/kernel/pci-nommu.c:63 nommu_map_sg+0xd9/0x100()
[    4.793674] Hardware name: Standard PC (i440FX + PIIX, 1996)
[    4.794149] Modules linked in:
[    4.794607] Pid: 153, comm: kblockd/0 Not tainted 2.6.32.65 #308
[    4.795077] Call Trace:
[    4.795545]  [<ffffffff81056875>] ? warn_slowpath_common+0x65/0xa0
[    4.796024]  [<ffffffff810380a9>] ? nommu_map_sg+0xd9/0x100
[    4.796446]  [<ffffffff8121ef4a>] ? ide_dma_prepare+0xda/0x180
[    4.796900]  [<ffffffff81219923>] ? do_rw_taskfile+0x253/0x330
[    4.797532]  [<ffffffff8122311c>] ? ide_do_rw_disk+0x22c/0x320
[    4.797983]  [<ffffffff81215c3a>] ? do_ide_request+0x11a/0x600
[    4.798416]  [<ffffffff81051450>] ? __dequeue_entity+0x30/0x40
[    4.798854]  [<ffffffff810519a1>] ? finish_task_switch.constprop.110+0x31/0xc0
[    4.799391]  [<ffffffff8141fdd6>] ? thread_return+0x2a/0x1d4
[    4.799816]  [<ffffffff81052116>] ? check_preempt_wakeup+0x76/0xe0
[    4.800279]  [<ffffffff811a3be0>] ? blk_unplug_work+0x0/0x20
[    4.800754]  [<ffffffff811a5b2a>] ? generic_unplug_device+0x1a/0x30
[    4.801218]  [<ffffffff810661dc>] ? worker_thread+0x13c/0x210
[    4.802710]  [<ffffffff81069cb0>] ? autoremove_wake_function+0x0/0x30
[    4.804130]  [<ffffffff810660a0>] ? worker_thread+0x0/0x210
[    4.805357]  [<ffffffff810660a0>] ? worker_thread+0x0/0x210
[    4.806356]  [<ffffffff81069907>] ? kthread+0x77/0x80
[    4.807302]  [<ffffffff81033eaa>] ? child_rip+0xa/0x20
[    4.808500]  [<ffffffff81069890>] ? kthread+0x0/0x80
[    4.809060]  [<ffffffff81033ea0>] ? child_rip+0x0/0x20
[    4.809620] ---[ end trace 61d7e1478dbb58eb ]---

and later causes this:

[    4.871857] hda: task_pio_intr: status=0x58 { DriveReady SeekComplete DataRequest }
[    4.872553] hda: possibly failed opcode: 0x29
[    4.873346] hda: DMA disabled
[    4.885478] Clocksource tsc unstable (delta = 115822911 ns)
[    4.886364] Switching to clocksource jiffies
[    4.919051] ide0: reset: success

and this:

[   48.957807] hda: lost interrupt

I added this to function __do_page_cache_readahead in mm/readahead.c but it can be added similarly to mm/filemap.c or similar functions. maybe someone can fix that problem!

like image 894
Mohamd Omran Avatar asked Apr 21 '15 03:04

Mohamd Omran


1 Answers

The way you're calculating the sector seems fine, although I don't think you're gonna end up with the precise sector you want. That being said, you're fetching the block device all wrong. Don't invoke ext2_get_block, because not only is it file system specific but you don't seem to really understand what it does and it's so much more confusing than the standard way of getting the block device. Instead, just use

bio.bi_bdev = I_BDEV(mapping->host);

Also, if you want to test this out and see it in action, then just compile it into a module and set up a hook so that when you open a certain block device (that you've created) it will trigger the function. Your current method of adding it into existing functions can interfere with whatever the kernel is currently doing and it will mess up your testing.

like image 136
randomusername Avatar answered Oct 21 '22 18:10

randomusername