diff --git a/mars_device_sio.c b/mars_device_sio.c index 9f8b5bf8..1deedb17 100644 --- a/mars_device_sio.c +++ b/mars_device_sio.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "mars.h" @@ -19,6 +20,8 @@ ////////////////// own brick / input / output operations ////////////////// +// some code borrowed from the loopback driver + static int transfer_none(int cmd, struct page *raw_page, unsigned raw_off, struct page *loop_page, unsigned loop_off, @@ -38,7 +41,7 @@ static int transfer_none(int cmd, return 0; } -static int device_sio_write_aops(struct device_sio_output *output, struct mars_io *mio) +static int write_aops(struct device_sio_output *output, struct mars_io *mio) { struct bio *bio = mio->orig_bio; loff_t pos = ((loff_t)bio->bi_sector << 9); @@ -110,42 +113,145 @@ static int device_sio_write_aops(struct device_sio_output *output, struct mars_i mio->mars_endio(mio); +#if 1 blk_run_address_space(mapping); +#endif return ret; } +struct cookie_data { + struct device_sio_output *output; + struct mars_io *mio; + struct bio_vec *bvec; + unsigned int offset; +}; + +static int +device_sio_splice_actor(struct pipe_inode_info *pipe, + struct pipe_buffer *buf, + struct splice_desc *sd) +{ + struct cookie_data *p = sd->u.data; + //struct device_sio_output *output = p->output; + //struct mars_io *mio = p->mio; + struct page *page = buf->page; + sector_t IV; + int size, ret; + + MARS_DBG("now splice %p %p %p %p\n", output, mio, mio->orig_bio, p->bvec); + + ret = buf->ops->confirm(pipe, buf); + if (unlikely(ret)) + return ret; + + IV = ((sector_t) page->index << (PAGE_CACHE_SHIFT - 9)) + + (buf->offset >> 9); + size = sd->len; + if (size > p->bvec->bv_len) + size = p->bvec->bv_len; + + if (transfer_none(READ, page, buf->offset, p->bvec->bv_page, p->offset, size)) { + MARS_ERR("transfer error block %ld\n", p->bvec->bv_page->index); + size = -EINVAL; + } + + flush_dcache_page(p->bvec->bv_page); + + if (size > 0) + p->offset += size; + + return size; +} + +static int +device_sio_direct_splice_actor(struct pipe_inode_info *pipe, struct splice_desc *sd) +{ + return __splice_from_pipe(pipe, sd, device_sio_splice_actor); +} + +static int read_aops(struct device_sio_output *output, struct mars_io *mio) +{ + struct bio *bio = mio->orig_bio; + loff_t pos = ((loff_t)bio->bi_sector << 9); + struct bio_vec *bvec; + int i; + int ret = -EIO; + + bio_for_each_segment(bvec, bio, i) { + struct cookie_data cookie = { + .output = output, + .mio = mio, + .bvec = bvec, + .offset = bvec->bv_offset, + }; + struct splice_desc sd = { + .len = 0, + .total_len = bvec->bv_len, + .flags = 0, + .pos = pos, + .u.data = &cookie, + }; + + MARS_DBG("start splice %p %p %p %p\n", output, mio, bio, bvec); + ret = 0; + ret = splice_direct_to_actor(output->filp, &sd, device_sio_direct_splice_actor); + if (ret < 0) { + MARS_ERR("splice %p %p %p %p status=%d\n", output, mio, bio, bvec, ret); + break; + } + pos += bvec->bv_len; + bio->bi_size -= bvec->bv_len; + + } + + mio->mars_endio(mio); + return ret; +} + +static void sync_file(struct device_sio_output *output) +{ + struct file *file = output->filp; + int ret; +#if 1 + ret = vfs_fsync(file, file->f_path.dentry, 0); + if (unlikely(ret)) { + MARS_ERR("syncing pages failed: %d\n", ret); + } + return; +#endif +} + static int device_sio_mars_io(struct device_sio_output *output, struct mars_io *mio) { struct bio *bio = mio->orig_bio; int direction = bio->bi_rw & 1; - unsigned long sector = bio->bi_sector; - unsigned long long pos = sector << 9; //TODO: allow different sector sizes bool barrier = (direction != READ && bio_rw_flagged(bio, BIO_RW_BARRIER)); +#if 0 + unsigned long sector = bio->bi_sector; + loff_t pos = sector << 9; //TODO: allow different sector sizes struct bio_vec *bvec; int i; +#endif int ret = -EIO; if (barrier) { MARS_INF("got barrier request\n"); + sync_file(output); } -#if 1 - if (direction == READ) { - bio->bi_size = 0; - mio->mars_endio(mio); - return 0; - } -#endif - if (!output->filp) goto done; #if 1 - if (direction == WRITE) { - return device_sio_write_aops(output, mio); + if (direction == READ) { + return read_aops(output, mio); + } else { + ret = write_aops(output, mio); + if (barrier) + sync_file(output); + return ret; } -#endif - +#else // toter code, war ein erster versuch bio_for_each_segment(bvec, bio, i) { mm_segment_t oldfs; unsigned long long ppos = pos; @@ -176,27 +282,19 @@ static int device_sio_mars_io(struct device_sio_output *output, struct mars_io * goto done; } -#if 0 - if (direction == WRITE) { - struct inode *inode = output->filp->f_dentry->d_inode; - struct address_space *mapping = inode->i_mapping; - int res; - - res = sync_page_range(inode, mapping, pos, len); - if (res) { - MARS_ERR("syncing pages failed: %d\n", res); - } - } - -#endif pos += len; ret = 0; } +#endif done: - if (!ret) + if (!ret) { bio->bi_size = 0; + if (direction == WRITE && barrier) { + sync_file(output); + } + } mio->mars_endio(mio); return ret; } @@ -204,37 +302,51 @@ done: #ifdef WITH_THREAD static int device_sio_mars_queue(struct device_sio_output *output, struct mars_io *mio) { - MARS_DBG("queue %p\n", mio); - spin_lock_irq(&output->lock); - list_add_tail(&mio->io_head, &output->mio_list); - spin_unlock_irq(&output->lock); + int index = 0; + struct sio_threadinfo *tinfo; + int direction = mio->orig_bio->bi_rw & 1; + if (direction == READ) { + spin_lock_irq(&output->g_lock); + index = output->index++; + spin_unlock_irq(&output->g_lock); + index = (index % WITH_THREAD) + 1; + } + tinfo = &output->tinfo[index]; + MARS_DBG("queueing %p on %d\n", mio, index); + spin_lock_irq(&tinfo->lock); + list_add_tail(&mio->io_head, &tinfo->mio_list); + spin_unlock_irq(&tinfo->lock); - wake_up(&output->event); + wake_up(&tinfo->event); return 0; } static int device_sio_thread(void *data) { - struct device_sio_output *output = data; + struct sio_threadinfo *tinfo = data; + struct device_sio_output *output = tinfo->output; MARS_INF("kthread has started.\n"); //set_user_nice(current, -20); while (!kthread_should_stop()) { + struct list_head *tmp; struct mars_io *mio; - wait_event_interruptible(output->event, - !list_empty(&output->mio_list) || + wait_event_interruptible(tinfo->event, + !list_empty(&tinfo->mio_list) || kthread_should_stop()); - if (list_empty(&output->mio_list)) + if (list_empty(&tinfo->mio_list)) continue; - spin_lock_irq(&output->lock); - mio = container_of(output->mio_list.next, struct mars_io, io_head); - spin_unlock_irq(&output->lock); + spin_lock_irq(&tinfo->lock); + tmp = tinfo->mio_list.next; + list_del_init(tmp); + spin_unlock_irq(&tinfo->lock); + mio = container_of(tmp, struct mars_io, io_head); MARS_DBG("got %p\n", mio); device_sio_mars_io(output, mio); } @@ -257,6 +369,7 @@ static int device_sio_output_construct(struct device_sio_output *output) int flags = O_CREAT | O_RDWR | O_LARGEFILE; int prot = 0600; char *path = "/tmp/testfile.img"; + int index; oldfs = get_fs(); set_fs(get_ds()); @@ -279,17 +392,23 @@ static int device_sio_output_construct(struct device_sio_output *output) #endif #ifdef WITH_THREAD - spin_lock_init(&output->lock); - init_waitqueue_head(&output->event); - INIT_LIST_HEAD(&output->mio_list); - output->thread = kthread_create(device_sio_thread, output, "mars_sio%d", 0); - if (IS_ERR(output->thread)) { - int error = PTR_ERR(output->thread); - MARS_ERR("cannot create thread, status=%d\n", error); - filp_close(output->filp, NULL); - return error; + spin_lock_init(&output->g_lock); + output->index = 0; + for (index = 0; index <= WITH_THREAD; index++) { + struct sio_threadinfo *tinfo = &output->tinfo[index]; + tinfo->output = output; + spin_lock_init(&tinfo->lock); + init_waitqueue_head(&tinfo->event); + INIT_LIST_HEAD(&tinfo->mio_list); + tinfo->thread = kthread_create(device_sio_thread, tinfo, "mars_sio%d", index); + if (IS_ERR(tinfo->thread)) { + int error = PTR_ERR(tinfo->thread); + MARS_ERR("cannot create thread, status=%d\n", error); + filp_close(output->filp, NULL); + return error; + } + wake_up_process(tinfo->thread); } - wake_up_process(output->thread); #endif return 0; @@ -298,8 +417,11 @@ static int device_sio_output_construct(struct device_sio_output *output) static int device_sio_output_destruct(struct device_sio_output *output) { #ifdef WITH_THREAD - kthread_stop(output->thread); - output->thread = NULL; + int index; + for (index = 0; index <= WITH_THREAD; index++) { + kthread_stop(output->tinfo[index].thread); + output->tinfo[index].thread = NULL; + } #endif if (output->filp) { filp_close(output->filp, NULL); @@ -349,13 +471,13 @@ EXPORT_SYMBOL_GPL(device_sio_brick_type); static int __init init_device_sio(void) { - printk(MARS_INFO "init_device_sio()\n"); + MARS_INF("init_device_sio()\n"); return device_sio_register_brick_type(); } static void __exit exit_device_sio(void) { - printk(MARS_INFO "exit_device_sio()\n"); + MARS_INF("exit_device_sio()\n"); device_sio_unregister_brick_type(); } diff --git a/mars_device_sio.h b/mars_device_sio.h index a1e520cb..82baeb0b 100644 --- a/mars_device_sio.h +++ b/mars_device_sio.h @@ -1,5 +1,5 @@ // (c) 2010 Thomas Schoebel-Theuer / 1&1 Internet AG -//#define WITH_THREAD +#define WITH_THREAD 16 struct device_sio_brick { MARS_BRICK(device_sio); @@ -9,14 +9,24 @@ struct device_sio_input { MARS_INPUT(device_sio); }; -struct device_sio_output { - MARS_OUTPUT(device_sio); - struct file *filp; #ifdef WITH_THREAD +struct sio_threadinfo { + struct device_sio_output *output; struct list_head mio_list; struct task_struct *thread; wait_queue_head_t event; spinlock_t lock; +}; + +#endif + +struct device_sio_output { + MARS_OUTPUT(device_sio); + struct file *filp; +#ifdef WITH_THREAD + struct sio_threadinfo tinfo[WITH_THREAD+1]; + spinlock_t g_lock; + int index; #endif }; diff --git a/mars_if_device.c b/mars_if_device.c index 85b8dd0a..ecc8a0ed 100644 --- a/mars_if_device.c +++ b/mars_if_device.c @@ -30,6 +30,7 @@ static int if_device_endio(struct mars_io *mio) { struct bio *bio = mio->orig_bio; if (bio) { + mio->orig_bio = NULL; if (!bio->bi_size) { bio_endio(bio, 0); } else { @@ -166,6 +167,8 @@ static int if_device_input_construct(struct if_device_input *input) blk_queue_max_segment_size(q, MARS_MAX_SEGMENT_SIZE); blk_queue_bounce_limit(q, BLK_BOUNCE_ANY); q->unplug_fn = if_device_unplug; + spin_lock_init(&input->req_lock); + q->queue_lock = &input->req_lock; // needed! //blk_queue_ordered(q, QUEUE_ORDERED_DRAIN, NULL);//??? MARS_DBG("4\n"); @@ -180,13 +183,13 @@ static int if_device_input_construct(struct if_device_input *input) #if 0 // ??? blk_queue_merge_bvec(q, mars_merge_bvec); - q->queue_lock = &input->req_lock; /* needed since we use */ - /* plugging on a queue, that actually has no requests! */ #endif + // point of no return MARS_DBG("99999\n"); add_disk(disk); input->disk = disk; + //set_device_ro(input->bdev, 0); // TODO: implement modes input->mio_size = 1024; //TODO: make this dynamic return 0; } diff --git a/mars_if_device.h b/mars_if_device.h index f05a5f7d..e5cfd0d1 100644 --- a/mars_if_device.h +++ b/mars_if_device.h @@ -8,6 +8,7 @@ struct if_device_input { struct request_queue *q; struct gendisk *disk; struct block_device *bdev; + spinlock_t req_lock; int mio_size; }; diff --git a/mars_test.c b/mars_test.c index 030ca3c3..3934286b 100644 --- a/mars_test.c +++ b/mars_test.c @@ -22,7 +22,7 @@ static struct device_sio_brick *device_brick = NULL; void make_test_instance(void) { static char *names[] = { "brick" }; - int size = 1024; + int size = 4096; int status; void *mem = kzalloc(size, GFP_KERNEL); if (!mem) {