How to setup a buffer_head in a driver
Hi,
I'm writing a device driver that among other things needs to write data, manufactured by the driver itself, to a block device.
I have this data in block sized kmalloc()'d chunks. So what I'm doing is allocating a struct buffer_head, initialising it, fill out it's various fields and send it to generic_make_request(). Something like the following [inspired by looking at various drivers like loop and ram]:
do {
if((bh = kmem_cache_alloc(bh_cachep, SLAB_NOIO)) != NULL){
break;
}
run_task_queue(&tq_disk);
schedule_timeout(HZ);
} while (1);
memset(bh, 0, sizeof(*bh));
bh->b_size = size;
bh->b_dev = dev;
bh->b_rdev = dev;
bh->b_data = data;
init_waitqueue_head(&bh->b_wait);
bh->b_rsector = sect;
bh->b_end_io = write_done;
bh->b_private = NULL;
generic_make_request(WRITE, bh);Now this causes a panic in ll_rw_blk.c because the b_state isn't set correctly. I experimented with this a little but decided I needed some proper direction on this whole endeavour.
Soooo, what do I really need to do? What's the correct way to do what I want to do or could someone point me at an existing driver that does this sort of thing.
Thanks,
Brian
Signature · 1 line
[email protected]
Quoted 8 lines · Brian Kelly
Hi,
I'm writing a device driver that among other things needs to write data, manufactured by the driver itself, to a block device.I have this data in block sized kmalloc()'d chunks. So what I'm doing is allocating a struct
buffer_head, initialising it, fill out it's various fields and send it togeneric_make_request().
It's probably better to use submit_bh(). Set the BH_Lock and BH_Mapped bits, also set up b_end_io. Then do a wait_on_buffer(), wait for the IO to complete. There's some similar code in fs/jbd/journal.c:journal_write_metadata_buffer().
However, what you're doing is an odd thing. If there is already pagecache against that block device then the kernel doesn't know that you've changed the bytes on-disk and will cheerfully proceed to use (and write out) the cached data. You'll lose your modifications..
It would be better to use sb_getblk() or bread(), to lock the returned buffer_head, then copy your data into it and to then write it back with submit_bh() or ll_rw_block(). Or just leave it dirty and let the kernel write it out in due course.
Quoted 6 lines · I wrote:
I'm writing a device driver that among other things needs to write data, manufactured by the driver itself, to a block device.
I have this data in block sized kmalloc()'d chunks. So what I'm doing is allocating a struct
buffer_head, initialising it, fill out it's various fields and send it togeneric_make_request().
Quoted 4 lines · Andrew Morton
It's probably better to use
submit_bh(). Set theBH_LockandBH_Mappedbits, also set upb_end_io. Then do await_on_buffer(), wait for the IO to complete. There's some similar code in fs/jbd/journal.c:journal_write_metadata_buffer().
Thanks, that's exactly the sort of thing I was looking for.
Quoted 9 lines
However, what you're doing is an odd thing. If there is already pagecache against that block device then the kernel doesn't know that you've changed the bytes on-disk and will cheerfully proceed to use (and write out) the cached data. You'll lose your modifications..
It would be better to use
sb_getblk()orbread(), to lock the returnedbuffer_head, then copy your data into it and to then write it back withsubmit_bh()orll_rw_block(). Or just leave it dirty and let the kernel write it out in due course.
Fair enough, that seems like the right thing to do so I'll look into it.
Thanks,
Brian
Signature · 1 line
[email protected]