Block devices, writing when inside a read request

From: Daniel Shane (daniel.shane@eicon.com)
Date: Mon Feb 25 2002 - 14:26:49 EST


Hi,

I am currently writing a driver that acts like a ramdisk except that when a
read takes place, I would like the driver to take the data from another
block device. My guess is that by doing this, all writes will stay in memory
(which is exactly what I would like) while reads are taken from another
block device.

I have written a driver for 2.4.7 by using the buffer cache only. Although
not perfect, it seems to work.

For 2.4.10 though many things have changed and I do not now really how to do
it best. I know that the page cache and the buffer cache have been merged,
but I'm at a total loss as to how to do the read/write in the
blkdev_pagecache_IO routine.

Here is what I tried to do (I only changed blkdev_pagecache and left
readpage, prepare_write, commit_write the same):

static int stackfs_blkdev_pagecache_IO(int rw, struct buffer_head * sbh, int
minor)
{
        struct address_space * mapping;
        unsigned long index;
        int offset, size, err;

        err = -EIO;
        err = 0;
        mapping = stackfs_bdev[minor]->bd_inode->i_mapping;

        index = sbh->b_rsector >> (PAGE_CACHE_SHIFT - 9);
        offset = (sbh->b_rsector << 9) & ~PAGE_CACHE_MASK;
        size = sbh->b_size;

        do {
                int count;
                struct page ** hash;
                struct page * page;
                char * src, * dst;
                int unlock = 0;

                count = PAGE_CACHE_SIZE - offset;
                if (count > size)
                        count = size;
                size -= count;

                hash = page_hash(mapping, index);
                page = __find_get_page(mapping, index, hash);
                if (!page) {
                        page = grab_cache_page(mapping, index);
                        err = -ENOMEM;
                        if (!page)
                                goto out;
                        err = 0;

                        if (!Page_Uptodate(page)) {
                                memset(kmap(page), 0, PAGE_CACHE_SIZE);
                                kunmap(page);
                                SetPageUptodate(page);
                        }

                        unlock = 1;
                }

                index++;

                if (rw == READ) {
                        struct file *file;
                        mm_segment_t fs;

                        file = stackfs_file[minor];

                        if (! file ) {
                          printk("STACKFS: file structure is empty.\n");
                          goto out;
                        }

                        if (! file->f_op ) {
                          printk("STACKFS: file->f_op is empty.\n");
                          goto out;
                        }

                        if (! file->f_op->read ) {
                                printk("STACKFS: file->f_op->read is
empty.\n");
                                goto out;
                        }
                        
                        src = kmap(page);
                        src += offset;

                        file->f_pos = offset;

                        fs = get_fs(); set_fs(get_ds());
                        err = file->f_op->read(file, src, size,
&file->f_pos);
                        set_fs(fs);

                        if (err < 0) {
                                printk("STACKFS: Read failed, error %d\n",
err);
                                kunmap(page);
                          goto out;
                        }

                        dst = bh_kmap(sbh);
                }
                else {
                        printk("STACKFS: write command, nothing to be
done\n");
                        dst = kmap(page);
                        dst += offset;
                        src = bh_kmap(sbh);
                }
                offset = 0;

                memcpy(dst, src, count);

                kunmap(page);
                bh_kunmap(sbh);

                if (rw == READ) {
                        printk("STACKFS: read command done, flushing the
page\n");
                        flush_dcache_page(page);
                } else {
                        printk("STACKFS: write command done, setting the
page dirty\n");
                        SetPageDirty(page);
                }
                if (unlock)
                        printk("STACKFS: unlocking the page???\n");
                        UnlockPage(page);
                __free_page(page);
        } while (size);

 out:
        return err;
}

Although this oops pretty bad when a read takes place (guess the kmap in
f_op->read() is not correct??). Is the approach bad in general?

Thanks!
Daniel Shane
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Feb 28 2002 - 21:00:17 EST