Skip to contentSkip to conversation

How to setup a buffer_head in a driver

DISCUSSION Brian Kelly 2 participants 3 messages Jan 14, 2003 – Jan 16, 2003

lore
Share & tools
lore
#0 lore raw

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]
#1 lore raw
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 to generic_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.

#2 lore raw
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 to generic_make_request().

Quoted 4 lines · Andrew Morton

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().

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() 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.

Fair enough, that seems like the right thing to do so I'll look into it.

Thanks,

Brian

Signature · 1 line
[email protected]