|
@@ -35,14 +35,17 @@
|
|
|
static int dcssblk_open(struct inode *inode, struct file *filp);
|
|
|
static int dcssblk_release(struct inode *inode, struct file *filp);
|
|
|
static int dcssblk_make_request(struct request_queue *q, struct bio *bio);
|
|
|
+static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
|
|
|
+ unsigned long *data);
|
|
|
|
|
|
static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
|
|
|
|
|
|
static int dcssblk_major;
|
|
|
static struct block_device_operations dcssblk_devops = {
|
|
|
- .owner = THIS_MODULE,
|
|
|
- .open = dcssblk_open,
|
|
|
- .release = dcssblk_release,
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+ .open = dcssblk_open,
|
|
|
+ .release = dcssblk_release,
|
|
|
+ .direct_access = dcssblk_direct_access,
|
|
|
};
|
|
|
|
|
|
static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf,
|
|
@@ -641,6 +644,20 @@ dcssblk_make_request(request_queue_t *q, struct bio *bio)
|
|
|
/* Request beyond end of DCSS segment. */
|
|
|
goto fail;
|
|
|
}
|
|
|
+ /* verify data transfer direction */
|
|
|
+ if (dev_info->is_shared) {
|
|
|
+ switch (dev_info->segment_type) {
|
|
|
+ case SEG_TYPE_SR:
|
|
|
+ case SEG_TYPE_ER:
|
|
|
+ case SEG_TYPE_SC:
|
|
|
+ /* cannot write to these segments */
|
|
|
+ if (bio_data_dir(bio) == WRITE) {
|
|
|
+ PRINT_WARN("rejecting write to ro segment %s\n", dev_info->dev.bus_id);
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
index = (bio->bi_sector >> 3);
|
|
|
bio_for_each_segment(bvec, bio, i) {
|
|
|
page_addr = (unsigned long)
|
|
@@ -661,7 +678,26 @@ dcssblk_make_request(request_queue_t *q, struct bio *bio)
|
|
|
bio_endio(bio, bytes_done, 0);
|
|
|
return 0;
|
|
|
fail:
|
|
|
- bio_io_error(bio, bytes_done);
|
|
|
+ bio_io_error(bio, bio->bi_size);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
|
|
|
+ unsigned long *data)
|
|
|
+{
|
|
|
+ struct dcssblk_dev_info *dev_info;
|
|
|
+ unsigned long pgoff;
|
|
|
+
|
|
|
+ dev_info = bdev->bd_disk->private_data;
|
|
|
+ if (!dev_info)
|
|
|
+ return -ENODEV;
|
|
|
+ if (secnum % (PAGE_SIZE/512))
|
|
|
+ return -EINVAL;
|
|
|
+ pgoff = secnum / (PAGE_SIZE / 512);
|
|
|
+ if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start)
|
|
|
+ return -ERANGE;
|
|
|
+ *data = (unsigned long) (dev_info->start+pgoff*PAGE_SIZE);
|
|
|
return 0;
|
|
|
}
|
|
|
|