patch-2.4.10 linux/drivers/block/rd.c
Next file: linux/drivers/block/xd.c
Previous file: linux/drivers/block/ps2esdi.c
Back to the patch index
Back to the overall index
- Lines: 401
- Date:
Sun Sep 23 09:44:37 2001
- Orig file:
v2.4.9/linux/drivers/block/rd.c
- Orig date:
Wed Jul 25 17:10:19 2001
diff -u --recursive --new-file v2.4.9/linux/drivers/block/rd.c linux/drivers/block/rd.c
@@ -100,7 +100,7 @@
static int rd_blocksizes[NUM_RAMDISKS]; /* Size of 1024 byte blocks :) */
static int rd_kbsize[NUM_RAMDISKS]; /* Size in blocks of 1024 bytes */
static devfs_handle_t devfs_handle;
-static struct inode *rd_inode[NUM_RAMDISKS]; /* Protected device inodes */
+static struct block_device *rd_bdev[NUM_RAMDISKS];/* Protected device data */
/*
* Parameters for the boot-loading of the RAM disk. These are set by
@@ -187,6 +187,132 @@
#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)
+{
+ if (!Page_Uptodate(page)) {
+ void *addr = page_address(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)
+{
+ return 0;
+}
+
+static 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;
+ unsigned long index;
+ int offset, size, err;
+
+ err = -EIO;
+ err = 0;
+ mapping = rd_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);
+ flush_dcache_page(page);
+ SetPageUptodate(page);
+ }
+
+ unlock = 1;
+ }
+
+ index++;
+
+ if (rw == READ) {
+ src = kmap(page);
+ src += offset;
+ dst = bh_kmap(sbh);
+ } else {
+ dst = kmap(page);
+ dst += offset;
+ src = bh_kmap(sbh);
+ }
+ offset = 0;
+
+ memcpy(dst, src, count);
+
+ kunmap(page);
+ bh_kunmap(sbh);
+
+ if (rw != READ)
+ SetPageDirty(page);
+ if (unlock)
+ UnlockPage(page);
+ __free_page(page);
+ } while (size);
+
+ out:
+ return err;
+}
+
+/*
* Basically, my strategy here is to set up a buffer-head which can't be
* deleted, and make that my Ramdisk. If the request is outside of the
* allocated size, we must get rid of it...
@@ -198,10 +324,7 @@
{
unsigned int minor;
unsigned long offset, len;
- struct buffer_head *rbh;
- char *bdata;
-
minor = MINOR(sbh->b_rdev);
if (minor >= NUM_RAMDISKS)
@@ -221,20 +344,8 @@
goto fail;
}
- rbh = getblk(sbh->b_rdev, sbh->b_rsector/(sbh->b_size>>9), sbh->b_size);
- /* I think that it is safe to assume that rbh is not in HighMem, though
- * sbh might be - NeilBrown
- */
- bdata = bh_kmap(sbh);
- if (rw == READ) {
- if (sbh != rbh)
- memcpy(bdata, rbh->b_data, rbh->b_size);
- } else
- if (sbh != rbh)
- memcpy(rbh->b_data, bdata, rbh->b_size);
- bh_kunmap(sbh);
- mark_buffer_protected(rbh);
- brelse(rbh);
+ if (rd_blkdev_pagecache_IO(rw, sbh, minor))
+ goto fail;
sbh->b_end_io(sbh,1);
return 0;
@@ -245,10 +356,11 @@
static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
+ int error = -EINVAL;
unsigned int minor;
if (!inode || !inode->i_rdev)
- return -EINVAL;
+ goto out;
minor = MINOR(inode->i_rdev);
@@ -259,26 +371,29 @@
/* special: we want to release the ramdisk memory,
it's not like with the other blockdevices where
this ioctl only flushes away the buffer cache. */
- if ((atomic_read(&inode->i_bdev->bd_openers) > 2))
- return -EBUSY;
- destroy_buffers(inode->i_rdev);
- rd_blocksizes[minor] = 0;
+ error = -EBUSY;
+ down(&inode->i_bdev->bd_sem);
+ if (inode->i_bdev->bd_openers <= 2) {
+ truncate_inode_pages(inode->i_mapping, 0);
+ error = 0;
+ }
+ up(&inode->i_bdev->bd_sem);
break;
-
case BLKGETSIZE: /* Return device size */
- if (!arg) return -EINVAL;
- return put_user(rd_kbsize[minor] << 1, (long *) arg);
-
+ if (!arg)
+ break;
+ error = put_user(rd_kbsize[minor] << 1, (long *) arg);
+ break;
+ case BLKGETSIZE64:
+ error = put_user((u64)rd_kbsize[minor]<<10, (u64*)arg);
+ break;
case BLKROSET:
case BLKROGET:
case BLKSSZGET:
- return blk_ioctl(inode->i_rdev, cmd, arg);
-
- default:
- return -EINVAL;
+ error = blk_ioctl(inode->i_rdev, cmd, arg);
};
-
- return 0;
+out:
+ return error;
}
@@ -304,12 +419,11 @@
lock_kernel();
if (!--initrd_users) {
- blkdev_put(inode->i_bdev, BDEV_FILE);
- iput(inode);
free_initrd_mem(initrd_start, initrd_end);
initrd_start = 0;
}
unlock_kernel();
+ blkdev_put(inode->i_bdev, BDEV_FILE);
return 0;
}
@@ -324,8 +438,10 @@
static int rd_open(struct inode * inode, struct file * filp)
{
+ int unit = DEVICE_NR(inode->i_rdev);
+
#ifdef CONFIG_BLK_DEV_INITRD
- if (DEVICE_NR(inode->i_rdev) == INITRD_MINOR) {
+ if (unit == INITRD_MINOR) {
if (!initrd_start) return -ENODEV;
initrd_users++;
filp->f_op = &initrd_fops;
@@ -333,16 +449,16 @@
}
#endif
- if (DEVICE_NR(inode->i_rdev) >= NUM_RAMDISKS)
+ if (unit >= NUM_RAMDISKS)
return -ENXIO;
/*
* Immunize device against invalidate_buffers() and prune_icache().
*/
- if (rd_inode[DEVICE_NR(inode->i_rdev)] == NULL) {
- if (!inode->i_bdev) return -ENXIO;
- if ((rd_inode[DEVICE_NR(inode->i_rdev)] = igrab(inode)) != NULL)
- atomic_inc(&rd_inode[DEVICE_NR(inode->i_rdev)]->i_bdev->bd_openers);
+ if (rd_bdev[unit] == NULL) {
+ rd_bdev[unit] = bdget(kdev_t_to_nr(inode->i_rdev));
+ rd_bdev[unit]->bd_openers++;
+ rd_bdev[unit]->bd_inode->i_mapping->a_ops = &ramdisk_aops;
}
MOD_INC_USE_COUNT;
@@ -356,7 +472,7 @@
return 0;
}
-static struct block_device_operations fd_fops = {
+static struct block_device_operations rd_bd_op = {
open: rd_open,
release: rd_release,
ioctl: rd_ioctl,
@@ -369,13 +485,10 @@
int i;
for (i = 0 ; i < NUM_RAMDISKS; i++) {
- if (rd_inode[i]) {
- /* withdraw invalidate_buffers() and prune_icache() immunity */
- atomic_dec(&rd_inode[i]->i_bdev->bd_openers);
- /* remove stale pointer to module address space */
- rd_inode[i]->i_bdev->bd_op = NULL;
- iput(rd_inode[i]);
- }
+ struct block_device *bdev = rd_bdev[i];
+ rd_bdev[i] = NULL;
+ if (bdev)
+ blkdev_put(bdev, BDEV_FILE);
destroy_buffers(MKDEV(MAJOR_NR, i));
}
@@ -400,7 +513,7 @@
rd_blocksize = BLOCK_SIZE;
}
- if (register_blkdev(MAJOR_NR, "ramdisk", &fd_fops)) {
+ if (register_blkdev(MAJOR_NR, "ramdisk", &rd_bd_op)) {
printk("RAMDISK: Could not get major %d", MAJOR_NR);
return -EIO;
}
@@ -418,14 +531,14 @@
devfs_register_series (devfs_handle, "%u", NUM_RAMDISKS,
DEVFS_FL_DEFAULT, MAJOR_NR, 0,
S_IFBLK | S_IRUSR | S_IWUSR,
- &fd_fops, NULL);
+ &rd_bd_op, NULL);
for (i = 0; i < NUM_RAMDISKS; i++)
- register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &fd_fops, rd_size<<1);
+ register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &rd_bd_op, rd_size<<1);
#ifdef CONFIG_BLK_DEV_INITRD
/* We ought to separate initrd operations here */
- register_disk(NULL, MKDEV(MAJOR_NR,INITRD_MINOR), 1, &fd_fops, rd_size<<1);
+ register_disk(NULL, MKDEV(MAJOR_NR,INITRD_MINOR), 1, &rd_bd_op, rd_size<<1);
#endif
hardsect_size[MAJOR_NR] = rd_hardsec; /* Size of the RAM disk blocks */
@@ -451,6 +564,8 @@
MODULE_PARM (rd_blocksize, "i");
MODULE_PARM_DESC(rd_blocksize, "Blocksize of each RAM disk in bytes.");
+MODULE_LICENSE("GPL");
+
/* End of non-loading portions of the RAM disk driver */
#ifdef RD_LOADER
@@ -595,8 +710,10 @@
outfile.f_op = &def_blk_fops;
init_special_inode(out_inode, S_IFBLK | S_IRUSR | S_IWUSR, kdev_t_to_nr(ram_device));
- if (blkdev_open(inode, &infile) != 0)
+ if (blkdev_open(inode, &infile) != 0) {
+ iput(out_inode);
goto free_inode;
+ }
if (blkdev_open(out_inode, &outfile) != 0)
goto free_inodes;
@@ -659,14 +776,15 @@
if (i && (i % devblocks == 0)) {
printk("done disk #%d.\n", i/devblocks);
rotate = 0;
- invalidate_buffers(device);
- if (infile.f_op->release)
- infile.f_op->release(inode, &infile);
+ if (infile.f_op->release(inode, &infile) != 0) {
+ printk("Error closing the disk.\n");
+ goto noclose_input;
+ }
printk("Please insert disk #%d and press ENTER\n", i/devblocks+1);
wait_for_keypress();
if (blkdev_open(inode, &infile) != 0) {
printk("Error opening disk.\n");
- goto done;
+ goto noclose_input;
}
infile.f_pos = 0;
printk("Loading disk #%d... ", i/devblocks+1);
@@ -684,18 +802,20 @@
kfree(buf);
successful_load:
- invalidate_buffers(device);
ROOT_DEV = MKDEV(MAJOR_NR, unit);
if (ROOT_DEVICE_NAME != NULL) strcpy (ROOT_DEVICE_NAME, "rd/0");
done:
- if (infile.f_op->release)
- infile.f_op->release(inode, &infile);
+ infile.f_op->release(inode, &infile);
+noclose_input:
+ blkdev_close(out_inode, &outfile);
+ iput(inode);
+ iput(out_inode);
set_fs(fs);
return;
free_inodes: /* free inodes on error */
iput(out_inode);
- blkdev_put(inode->i_bdev, BDEV_FILE);
+ infile.f_op->release(inode, &infile);
free_inode:
iput(inode);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)