rediffed against pre13 (I'm passing the bd_inode to the ->open/release,
so we can modify the a_ops of the physical address space, ramdisk needs
that in rd_open())
diff -urN ramdisk-ref/drivers/block/rd.c ramdisk/drivers/block/rd.c
--- ramdisk-ref/drivers/block/rd.c Fri Sep 21 08:28:04 2001
+++ ramdisk/drivers/block/rd.c Fri Sep 21 08:06:02 2001
@@ -186,17 +186,77 @@
#endif
+/*
+ * Copyright (C) 2000 Linus Torvalds.
+ * 2000 Transmeta Corp.
+ * aops copied from ramfs.
+ */
+static int ramdisk_readpage(struct file *file, struct page * page)
+{
+ if (!Page_Uptodate(page)) {
+ memset(kmap(page), 0, PAGE_CACHE_SIZE);
+ kunmap(page);
+ flush_dcache_page(page);
+ SetPageUptodate(page);
+ }
+ UnlockPage(page);
+ return 0;
+}
+
+/*
+ * Writing: just make sure the page gets marked dirty, so that
+ * the page stealer won't grab it.
+ */
+static int ramdisk_writepage(struct page *page)
+{
+ SetPageDirty(page);
+ UnlockPage(page);
+ return 0;
+}
+
+static int ramdisk_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+{
+ void *addr = kmap(page);
+ if (!Page_Uptodate(page)) {
+ memset(addr, 0, PAGE_CACHE_SIZE);
+ flush_dcache_page(page);
+ SetPageUptodate(page);
+ }
+ SetPageDirty(page);
+ return 0;
+}
+
+static int ramdisk_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+{
+ kunmap(page);
+ return 0;
+}
+
+struct address_space_operations ramdisk_aops = {
+ readpage: ramdisk_readpage,
+ writepage: ramdisk_writepage,
+ prepare_write: ramdisk_prepare_write,
+ commit_write: ramdisk_commit_write,
+};
+
static int rd_blkdev_pagecache_IO(int rw, struct buffer_head * sbh, int minor)
{
- struct address_space * mapping = rd_inode[minor]->i_mapping;
+ struct address_space * mapping;
unsigned long index;
- int offset, size, err = 0;
+ int offset, size, err;
- if (sbh->b_page->mapping == mapping) {
- if (rw != READ)
- SetPageDirty(sbh->b_page);
+ err = -EIO;
+ /*
+ * If we did BLKFLSBUF just before doing read/write,
+ * we could see a rd_inode before the opener had a chance
+ * to return from rd_open(), that's ok, as soon as we
+ * see the inode we can use its i_mapping, and the inode
+ * cannot go away from under us.
+ */
+ if (!rd_inode[minor])
goto out;
- }
+ err = 0;
+ mapping = rd_inode[minor]->i_mapping;
index = sbh->b_rsector >> (PAGE_CACHE_SHIFT - 9);
offset = (sbh->b_rsector << 9) & ~PAGE_CACHE_MASK;
@@ -206,8 +266,7 @@
int count;
struct page ** hash;
struct page * page;
- const char * src;
- char * dst;
+ char * src, * dst;
int unlock = 0;
count = PAGE_CACHE_SIZE - offset;
@@ -217,20 +276,24 @@
hash = page_hash(mapping, index);
page = __find_get_page(mapping, index, hash);
- if (!page && rw != READ) {
+ 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);
+ flush_dcache_page(page);
+ SetPageUptodate(page);
+ }
+
unlock = 1;
}
index++;
- if (!page) {
- offset = 0;
- continue;
- }
if (rw == READ) {
src = kmap(page);
@@ -321,6 +384,13 @@
struct block_device * bdev = inode->i_bdev;
down(&bdev->bd_sem);
+ /*
+ * We're the only users here, protected by the
+ * bd_sem, but first check if we didn't just
+ * flushed the ramdisk.
+ */
+ if (!rd_inode[minor])
+ goto unlock;
if (bdev->bd_openers > 2) {
up(&bdev->bd_sem);
return -EBUSY;
@@ -328,8 +398,16 @@
bdev->bd_openers--;
bdev->bd_cache_openers--;
iput(rd_inode[minor]);
+ /*
+ * Make sure the cache is flushed from here
+ * and not from close(2), somebody
+ * could reopen the device before we have a
+ * chance to close it ourself.
+ */
+ truncate_inode_pages(rd_inode[minor]->i_mapping, 0);
rd_inode[minor] = NULL;
rd_blocksizes[minor] = rd_blocksize;
+ unlock:
up(&bdev->bd_sem);
}
break;
@@ -420,6 +498,8 @@
/* bdev->bd_sem is held by caller */
bdev->bd_openers++;
bdev->bd_cache_openers++;
+
+ bdev->bd_inode->i_mapping->a_ops = &ramdisk_aops;
}
}
diff -urN ramdisk-ref/fs/block_dev.c ramdisk/fs/block_dev.c
--- ramdisk-ref/fs/block_dev.c Fri Sep 21 07:48:12 2001
+++ ramdisk/fs/block_dev.c Fri Sep 21 08:25:29 2001
@@ -736,7 +736,7 @@
if (bdev->bd_op) {
ret = 0;
if (bdev->bd_op->open)
- ret = bdev->bd_op->open(inode,filp);
+ ret = bdev->bd_op->open(bdev->bd_inode,filp);
if (!ret) {
bdev->bd_openers++;
bdev->bd_cache_openers++;
@@ -835,7 +835,7 @@
/* release the device driver */
if (bdev->bd_op->release)
- ret = bdev->bd_op->release(inode, NULL);
+ ret = bdev->bd_op->release(bd_inode, NULL);
if (!--bdev->bd_openers) {
bdev->bd_op = NULL;
bdev->bd_inode = NULL;
Andrea
-
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/