Re: 2. I need to do block I/O, both synchronously and asynchronously.

Jim Zelenka (jimz+@cs.cmu.edu)
Thu, 22 Apr 1999 09:40:46 -0400


Richard Dynes <rdynes@varcom.com> writes:
>> 2. I need to do block I/O, both synchronously and asynchronously.

>static struct wait_queue *data_wait_queue = NULL;

>interruptible_sleep_on(&data_wait_queue);
>wake_up_interruptible(&data_wait_queue);

I appreciate the hint, but things still aren't clear to me.
How do I issue the I/O? What's the right way to construct
a scatter-gather list? I believe I'm putting together a valid
set of buffer_head structures, but I'm getting bitten by
ll_rw_block() freaking out.

I'll append a sample of the code I'm talking about to this
message in case anyone's wondering...

Thanks,
Jim.Zelenka@cs.cmu.edu

(my apologies for the fact that this is not extensively
documented- these are the platform-specific back-ends
to a larger storage system that I'm porting into the
linux kernel)

/*
* Caller holds I/O lock here
*
* Take a list of buffers (entlist) and issue
* them asynchronously. This list is guaranteed to be
* contiguous on the disk, and either entirely reads or
* entirely writes.
*/
nasd_status_t
nasd_od_io_launch_internal(
nasd_odc_ent_t *entlist)
{
struct buffer_head *bharr[NASD_IO_MAX_COALESCE], *bh;
nasd_odc_ent_t *e;
int i, dir;

NASD_IO_INC_STAT(pull_ios);

dir = entlist->iodir;

nasd_printf("LAUNCH INTERNAL list 0x%lx\n", (unsigned long)entlist);
for(i=0,e=entlist;e;e=e->inext,i++) {
nasd_printf("LAUNCH INTERNAL sect %u\n", (unsigned)e->real_sectno);
NASD_ASSERT((e->io_flags&NASD_CI_DISPATCH) == NASD_CI_DISPATCH);
NASD_ASSERT(e->iodir == dir);
NASD_ASSERT(i < NASD_IO_MAX_COALESCE);
bh = bharr[i] = &e->rbh;

bh->b_next = NULL;
bh->b_blocknr = e->real_sectno;
bh->b_size = NASD_OD_BASIC_BLOCKSIZE;
bh->b_dev = nasd_od_linux_kdev;
bh->b_rdev = nasd_od_linux_kdev;
bh->b_rsector = e->real_sectno;
bh->b_this_page = NULL;
bh->b_state = 0;
bh->b_next_free = NULL;
bh->b_count = 1;

bh->b_data = e->data.buf;
bh->b_list = BUF_CLEAN;
bh->b_flushtime = 0;

init_waitqueue(&bh->b_wait);
bh->b_pprev = NULL;
bh->b_prev_free = NULL;
bh->b_reqnext = NULL;

bh->b_end_io = nasd_od_k_io_done;
bh->b_dev_id = e;

NASD_ASSERT((e->io_flags&NASD_CI_DISPATCH) == NASD_CI_DISPATCH);
NASD_ASSERT(e->iodir == dir);

#if NASD_DRIVE_DEBUG_PHYS_OUTSTANDING > 0
e->kbuf = bh;
#endif /* NASD_DRIVE_DEBUG_PHYS_OUTSTANDING > 0 */
}
NASD_ASSERT(i > 0);

entlist->io_flags |= NASD_CI_IOHEAD;

if (dir == NASD_U_READ) {
ll_rw_block(READA, i, bharr);
}
else if (dir == NASD_U_WRITE) {
ll_rw_block(WRITEA, i, bharr);
}
else {
NASD_PANIC();
}

return(NASD_SUCCESS);
}

nasd_status_t
nasd_od_k_blkio(
nasd_odc_ent_t *ent, /* not guaranteed to be "real" */
nasd_blkno_t sectno,
void *buf,
int len,
int iodir,
void (*finish_proc)(struct buffer_head *, int))
{
struct buffer_head *bh, real_bh;

bh = &real_bh;

nasd_printf("nasd_od_k_blkio %d bytes\n", len);
bh->b_next = NULL;
bh->b_blocknr = sectno;
bh->b_size = len;
bh->b_dev = nasd_od_linux_kdev;
bh->b_rdev = nasd_od_linux_kdev;
bh->b_rsector = sectno;
bh->b_this_page = NULL;
bh->b_state = 0;
bh->b_next_free = NULL;
bh->b_count = 1;

bh->b_data = buf;
bh->b_list = BUF_CLEAN;
bh->b_flushtime = 0;

init_waitqueue(&bh->b_wait);
bh->b_pprev = NULL;
bh->b_prev_free = NULL;
bh->b_reqnext = NULL;

bh->b_end_io = finish_proc;
bh->b_dev_id = ent;

nasd_od_io_sync_launch(sectno);

NASD_IO_TM_LAUNCH(ent);

if (iodir == NASD_U_READ) {
ll_rw_block(READA, 1, &bh);
}
else if (iodir == NASD_U_WRITE) {
ll_rw_block(WRITEA, 1, &bh);
}
else {
NASD_PANIC();
}

wait_on_buffer(bh);

NASD_IO_TM_COMPLETE(ent);

NASD_ASSERT(bh->b_count == 1);

if (test_bit(BH_Uptodate, &bh->b_state)) {
return(NASD_SUCCESS);
}
else {
nasd_printf("DRIVE ERROR: failed completing blkio\n");
NASD_PANIC();
return(NASD_FAIL);
}
}

void
nasd_od_io_sys_flush_block(
nasd_odc_ent_t *ent)
{
nasd_status_t rc;

nasd_printf("nasd_od_io_sys_flush_block\n");
NASD_IO_INC_SIZE_STAT(1,write);
nasd_od_io_sync_launch(ent->real_sectno);
NASD_IO_TM_LAUNCH(ent);
rc = nasd_od_k_blkio(ent, ent->real_sectno, ent->data.buf,
NASD_OD_BASIC_BLOCKSIZE, NASD_U_WRITE,
nasd_od_k_blkio_done);
if (rc != NASD_SUCCESS) {
NASD_PANIC();
}
NASD_IO_TM_COMPLETE(ent);

nasd_od_io_last_completed_sect = ent->real_sectno;
}

void
nasd_od_k_blkio_done(
struct buffer_head *bh,
int uptodate)
{
if (uptodate) {
set_bit(BH_Uptodate, &bh->b_state);
}
else {
clear_bit(BH_Uptodate, &bh->b_state);
}

nasd_printf("nasd_od_k_blkio_done\n");
/*
* This is for synchronous I/O, so the thread
* waiting on this block does the rest
*/
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/