patch-2.3.45 linux/drivers/block/loop.c
Next file: linux/drivers/char/Makefile
Previous file: linux/drivers/block/cs5530.c
Back to the patch index
Back to the overall index
- Lines: 153
- Date:
Sun Feb 13 10:33:23 2000
- Orig file:
v2.3.44/linux/drivers/block/loop.c
- Orig date:
Sat Feb 12 11:22:10 2000
diff -u --recursive --new-file v2.3.44/linux/drivers/block/loop.c linux/drivers/block/loop.c
@@ -40,10 +40,10 @@
* it passes the underlying device's block number instead of the
* offset. This makes it change for a given block when the file is
* moved/restored/copied and also doesn't work over NFS.
- * AV, Feb 11, 2000: for files we pass the page index now. It should fix the
- * problem above. Since the granularity is PAGE_CACHE_SIZE now it seems to
- * be correct way. OTOH, taking the thing from x86 to Alpha may become
- * interesting, so we might want to rethink it.
+ * AV, Feb 12, 2000: we pass the logical block number now. It fixes the
+ * problem above. Encryption modules that used to rely on the old scheme
+ * should just call ->i_mapping->bmap() to calculate the physical block
+ * number.
*/
#include <linux/module.h>
@@ -164,7 +164,8 @@
loop_sizes[lo->lo_number] = size;
}
-static int lo_send(struct loop_device *lo, char *data, int len, loff_t pos)
+static int lo_send(struct loop_device *lo, char *data, int len, loff_t pos,
+ int blksize)
{
struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
struct address_space *mapping = lo->lo_dentry->d_inode->i_mapping;
@@ -177,6 +178,7 @@
index = pos >> PAGE_CACHE_SHIFT;
offset = pos & (PAGE_CACHE_SIZE - 1);
while (len > 0) {
+ int IV = index * (PAGE_CACHE_SIZE/blksize) + offset/blksize;
size = PAGE_CACHE_SIZE - offset;
if (size > len)
size = len;
@@ -187,7 +189,7 @@
if (aops->prepare_write(page, offset, offset+size))
goto unlock;
kaddr = (char*)page_address(page);
- if ((lo->transfer)(lo, WRITE, kaddr+offset, data, size, index))
+ if ((lo->transfer)(lo, WRITE, kaddr+offset, data, size, IV))
goto write_fail;
if (aops->commit_write(file, page, offset, offset+size))
goto unlock;
@@ -217,6 +219,7 @@
struct lo_read_data {
struct loop_device *lo;
char *data;
+ int blksize;
};
static int lo_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
@@ -225,12 +228,13 @@
unsigned long count = desc->count;
struct lo_read_data *p = (struct lo_read_data*)desc->buf;
struct loop_device *lo = p->lo;
+ int IV = page->index * (PAGE_CACHE_SIZE/p->blksize) + offset/p->blksize;
if (size > count)
size = count;
kaddr = (char*)kmap(page);
- if ((lo->transfer)(lo,READ,kaddr+offset,p->data,size,page->index)) {
+ if ((lo->transfer)(lo,READ,kaddr+offset,p->data,size,IV)) {
size = 0;
printk(KERN_ERR "loop: transfer error block %ld\n",page->index);
desc->error = -EINVAL;
@@ -243,7 +247,8 @@
return size;
}
-static int lo_receive(struct loop_device *lo, char *data, int len, loff_t pos)
+static int lo_receive(struct loop_device *lo, char *data, int len, loff_t pos,
+ int blksize)
{
struct file *file = lo->lo_backing_file;
struct lo_read_data cookie;
@@ -251,6 +256,7 @@
cookie.lo = lo;
cookie.data = data;
+ cookie.blksize = blksize;
desc.written = 0;
desc.count = len;
desc.buf = (char*)&cookie;
@@ -287,8 +293,6 @@
dest_addr = current_request->buffer;
len = current_request->current_nr_sectors << 9;
- if (lo->lo_flags & LO_FLAGS_DO_BMAP)
- goto file_backed;
blksize = BLOCK_SIZE;
if (blksize_size[MAJOR(lo->lo_device)]) {
@@ -296,6 +300,10 @@
if (!blksize)
blksize = BLOCK_SIZE;
}
+
+ if (lo->lo_flags & LO_FLAGS_DO_BMAP)
+ goto file_backed;
+
if (blksize < 512) {
block = current_request->sector * (512/blksize);
offset = 0;
@@ -357,10 +365,10 @@
pos = ((loff_t)current_request->sector << 9) + lo->lo_offset;
spin_unlock_irq(&io_request_lock);
if (current_request->cmd == WRITE) {
- if (lo_send(lo, dest_addr, len, pos))
+ if (lo_send(lo, dest_addr, len, pos, blksize))
goto error_out_lock;
} else {
- if (lo_receive(lo, dest_addr, len, pos))
+ if (lo_receive(lo, dest_addr, len, pos, blksize))
goto error_out_lock;
}
done:
@@ -416,6 +424,7 @@
a file structure */
lo->lo_backing_file = NULL;
} else if (S_ISREG(inode->i_mode)) {
+ struct address_space_operations *aops;
/* Backed by a regular file - we need to hold onto a file
structure for this file. Friggin' NFS can't live without
it on write and for reading we use do_generic_file_read(),
@@ -444,16 +453,23 @@
lo->lo_backing_file = NULL;
}
}
+ aops = lo->lo_dentry->d_inode->i_mapping->a_ops;
+ /*
+ * If we can't read - sorry. If we only can't write - well,
+ * it's going to be read-only.
+ */
+ if (!aops->readpage)
+ error = -EINVAL;
+ else if (!aops->prepare_write || !aops->commit_write)
+ lo->lo_flags |= LO_FLAGS_READ_ONLY;
}
if (error)
goto out_putf;
- if (IS_RDONLY (inode) || is_read_only(lo->lo_device)) {
+ if (IS_RDONLY (inode) || is_read_only(lo->lo_device))
lo->lo_flags |= LO_FLAGS_READ_ONLY;
- set_device_ro(dev, 1);
- } else {
- set_device_ro(dev, 0);
- }
+
+ set_device_ro(dev, (lo->lo_flags & LO_FLAGS_READ_ONLY)!=0);
lo->lo_dentry = dget(file->f_dentry);
lo->transfer = NULL;
FUNET's LINUX-ADM group, [email protected]
TCL-scripts by Sam Shen (who was at: [email protected])