block i/o problem

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

I wrote a module to change the underlying block_device of a bio
structure. It works, but the first processed page is always filled with
junk. All the remaining pages are processed correctly.
I tried it under a 2.6.8 and a 2.6.19 kernel. Does anybody has an idea
what could be wrong?

Thanks and regards,
Jochen

---

/**
 *
 * Test module to play around with the bio structure in order to
 * redirect a READ from one block device to another.
 *
 *
 **/

#define MAJOR_NR	241
#define KERNEL_SECTOR_SIZE		512

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/syscalls.h>
#include <linux/blkdev.h>
#include <linux/bio.h>

#include <linux/slab.h>		/* kmalloc */
#include <linux/kernel.h>	/* printk() */
#include <linux/fs.h>		/* everything */
#include <linux/errno.h>	/* error codes */
#include <linux/types.h>        /* size_t */
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/interrupt.h>
#include <linux/delay.h>        /* udelay(int); */

#include <linux/spinlock.h>
#include <linux/ioctl.h>

MODULE_LICENSE("GPL");

/* The sector size of the block device. */
static int sect_size = 512;

struct pseudo_device {

	char * name;
	spinlock_t lock;
	struct request_queue *queue;
	struct gendisk *gendisk;
	struct block_device *bdev;
	

};

// the test device
struct pseudo_device *pd;

int register_device(struct pseudo_device *);


static int pd_ioctl(struct inode *inode, struct file *file,
			unsigned int cmd, unsigned long arg) {
	
	return 0;
	
}

static int pd_open(struct inode *inode, struct file *file) {

	return 0;

}

static struct block_device_operations pd_ops = {

	.owner = THIS_MODULE,
	.ioctl = pd_ioctl,
	.open = pd_open

};

static int pd_transfer_request(struct pseudo_device *pd, struct request
*req) {

	struct bio *bio;
	struct bio *cloned_bio;
	int nsect = 0;


	printk(KERN_WARNING "pd: pd_transfer_request\n");
	
	rq_for_each_bio(bio, req) {

		// Extend the bio.
		//extended = extend_bio(bio, pd_device);
		//bio -> bi_bdev = pd_device -> bdev;
		
		cloned_bio = bio_clone(bio, GFP_NOIO);
		cloned_bio -> bi_private = bio;
		cloned_bio -> bi_bdev = pd -> bdev;
		
		if(bio_data_dir(cloned_bio) == WRITE) {

			submit_bio(WRITE, cloned_bio);
		}
		else {

			submit_bio(READ, cloned_bio);
		}
		
		nsect += cloned_bio->bi_size/KERNEL_SECTOR_SIZE;

	}

	return nsect;

}

static void pd_full_request(request_queue_t *q) {

	struct request *req;
	int sectors_xferred;
	struct pseudo_device *pd = q->queuedata;

	printk(KERN_WARNING "pd: pd_full_request\n");

	while ((req = elv_next_request(q)) != NULL) {
		
		if (! blk_fs_request(req)) {
			printk (KERN_NOTICE "Skip non-fs request\n");
			end_request(req, 0);
			continue;
		}
		sectors_xferred = pd_transfer_request(pd, req);
		
		if (! end_that_request_first(req, 1, sectors_xferred)) {
			blkdev_dequeue_request(req);
			end_that_request_last(req, 0);
			
		}
	}
}

static int pd_init(void) {

	printk(KERN_INFO "pd: Initialize pseudo module\n");

	pd = kmalloc(sizeof(struct pseudo_device), GFP_KERNEL);
	memset(pd, 0, sizeof(*pd));
	
	pd -> name = "pd1";
	
	spin_lock_init(&pd->lock);
	
	//pd->queue = blk_init_queue(pd_full_request, &pd->lock);
	
	pd -> bdev = open_bdev_excl("/dev/sdb", 00000002, NULL);

	pd -> gendisk = alloc_disk(1);
	
	if(!pd -> gendisk) {

		printk(KERN_WARNING "pd: alloc_disk failure for control device.\n");
		goto abort;

	}
	
	pd -> gendisk -> major = MAJOR_NR;
	pd -> gendisk -> first_minor = 0;
	pd -> gendisk -> fops = &pd_ops;
	pd -> gendisk -> private_data = &pd;
	strcpy(pd->gendisk -> disk_name, pd -> name);
	set_capacity(pd -> gendisk, (pd->bdev->bd_disk->capacity));
	spin_lock_init(&pd -> lock);
	
	if( (pd -> queue = blk_init_queue(pd_full_request, &pd -> lock)) ==
NULL) {
		printk(KERN_WARNING "pd: register: no queue\n");
		goto abort;
	}

	blk_queue_hardsect_size(pd -> queue, sect_size);
	pd -> queue -> queuedata = pd;
	pd -> gendisk -> queue = pd -> queue;
	add_disk(pd -> gendisk);
	
	
	/* Create device node in /dev/ */
	/**
	 * mknod seems not to work in kernel land.
	 * "mknod /dev/pd1 b 241 0" does the job in the console.
	 */

	return 0;

	abort:
	return -1;

}

static void pd_exit(void) {

	printk(KERN_INFO "pd: Removing pseudo module from kernel\n");
	
	if(pd -> gendisk) {
	
		del_gendisk(pd->gendisk);
		put_disk(pd->gendisk);
	
	}

}

module_init(pd_init);
module_exit(pd_exit);

My Makefile looks like this:
obj-m += biomod.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean


And after creating the device node with "mknod /dev/pd1 b 241 0", I try
to read with: "dd if=/dev/pd1 of=./output count=2000"

The error occurs, regardless of the values for count (and skip).
-
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux