>>> Диск примонтирован? Может дисковый кэш. Что будет при команде sync?
>> Без разницы смонтирован диск или нет, на устройстве может вообще не быть
>> никакой ФС, так как вызов make_request_fn в данном случае лежит сразу
>> над драйвером физического устройства.
> Удалось разобраться ?Сорри, поторопился я с ответом. Сейчас в код глянул, там вот такое. Насколько я помню, это работает и на запись и на чтение, но при большой нагрузке валит систему. Разбираться почему это происходит было, честно говоря уже лень. Если разберетесь, не забудьте поделиться :)
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
#define PARTITION_NAME "/dev/sdb"
char *ptr;
int i;
struct block_device *bd;
make_request_fn *orig_mrqfn;
bio_end_io_t *old_endio;
// BIOs set
struct bio_set * bs;
// HOOKs
static struct kmem_cache *my_hooks;
// HOOK
struct hook{
void *old_private;
bio_end_io_t *old_endio;
struct bio *clone;
};
// read bi_end_io
static void read_endio(struct bio *b, unsigned done, int error)
{
printk(KERN_INFO "filter: my bio_endio err=%d size=%u sector=%lu vi_vcnt=%d",error,done,b->bi_sector,b->bi_vcnt);
struct hook *hook = b->bi_private;
b->bi_end_io = hook->old_endio;
b->bi_private = hook->old_private;
unsigned int count=0;
printk(KERN_INFO " clone_size=%u clone_sector=%lu", hook->clone->bi_size, hook->clone->bi_sector );
int segno=0;
struct bio_vec *bvec;
bio_for_each_segment(bvec,hook->clone,segno){
char *buffer = __bio_kmap_atomic(hook->clone,segno, KM_USER0);
for(i=hook->clone->bi_io_vec[segno].bv_offset;i<hook->clone->bi_io_vec[segno].bv_len+hook->clone->bi_io_vec[segno].bv_offset;i++){
// printk("%c",buffer[i]);
buffer[i]=~buffer[i];
}
__bio_kunmap_atomic(buffer, KM_USER0);
}
//printk(KERN_INFO "filter: my bio_endio count=%d",count);
kmem_cache_free(my_hooks,hook);
b->bi_end_io(b,error);
};
// write bi_end_io - unused
static void write_endio(struct bio *b, unsigned done, int error){
printk(KERN_INFO "filter: write_endio err=%d size=%u sector=%lu",error,done,b->bi_sector);
b->bi_end_io(b,error);
}
// filter make_request_fn()
static void filter_mrqfn(struct request_queue *rq, struct bio *b)
{
printk(KERN_INFO "filter: Sector=%lu Size=%d bi_rw=%lu rw_bit=%lu\n", b->bi_sector, b->bi_size, b->bi_rw, (b->bi_rw & 1));
// direction WRITE
if(bio_data_dir(b)==WRITE){
printk(KERN_INFO "filter: write Sector=%lu Size=%d bi_rw=%lu rw_bit=%lu\n", b->bi_sector, b->bi_size, b->bi_rw, (b->bi_rw & 1));
struct hook *hook=NULL;
hook = kmem_cache_alloc(my_hooks,GFP_NOIO|__GFP_NOFAIL);
*hook = (struct hook){
.old_private = b->bi_private,
.old_endio = b->bi_end_io,
.clone = bio_clone_bioset(b,GFP_NOIO,bs),
};
b->bi_end_io = read_endio;
b->bi_private = hook;
ptr=(char *)bio_data(b);
for(i=0;i<b->bi_size;i++) //4096 as bio is going to be in 4kb chunk
{
//printk("%c",*ptr);
ptr[i]=~ptr[i];
}
/* calling the original make_request_fn() */
orig_mrqfn(rq, b);
}
// direction READ
if(bio_data_dir(b)==READ){
//printk(KERN_INFO "filter: read Sector=%lu Size=%d bi_rw=%lu rw_bit=%lu\n", b->bi_sector, b->bi_size, b->bi_rw, (b->bi_rw & 1));
struct hook *hook=NULL;
hook = kmem_cache_alloc(my_hooks,GFP_NOIO|__GFP_NOFAIL);
*hook = (struct hook){
.old_private = b->bi_private,
.old_endio = b->bi_end_io,
.clone = bio_clone_bioset(b,GFP_NOIO,bs),
};
b->bi_end_io = read_endio;
b->bi_private = hook;
/* calling the original make_request_fn() */
orig_mrqfn(rq, b);
}
}
/*
* set_mrqfn() - Change the original make_request_fn() to our
* modules request function
*/
static void set_mrqfn(void)
{
struct super_block *sb;
/* lock filesystem to prevent any further changes */
fsync_bdev(bd);
sb = freeze_bdev(bd);
if (bd->bd_disk->queue->make_request_fn == filter_mrqfn) {
printk(KERN_INFO "filter: modules request function is already active\n");
} else {
/* save the pointer to the original make_request_fn() */
orig_mrqfn = bd->bd_disk->queue->make_request_fn;
/* replace the original with our modules request function */
bd->bd_disk->queue->make_request_fn = filter_mrqfn;
}
/* unlock filesystem */
thaw_bdev(bd, sb);
}
/*
* restore_mrqfn() - Restore the original make_request_fn()
*/
static void restore_mrqfn(void)
{
struct super_block *sb = bd->bd_super;
if (orig_mrqfn) {
/* lock filesystem to prevent any further changes */
fsync_bdev(bd);
sb = freeze_bdev(bd);
/* restore the original request function */
bd->bd_disk->queue->make_request_fn = orig_mrqfn;
/* unlock filesystem */
thaw_bdev(bd, sb);
}
orig_mrqfn = NULL;
}
static int __init filter_init(void)
{
printk(KERN_DEBUG "filter: %s\n", __FUNCTION__);
orig_mrqfn = NULL;
// Read block device from path
bd = blkdev_get_by_path(PARTITION_NAME, FMODE_READ, NULL);
if (IS_ERR(bd)) {
printk(KERN_ERR "filter: failed to get block device\n");
return 0;
}
printk(KERN_INFO "filter: found block device with major number %d\n", bd->bd_disk->major);
printk(KERN_INFO "filter: file system block size %d\n", bd->bd_block_size);
printk(KERN_INFO "filter: start sector %lu\n", (unsigned long)bd->bd_part->start_sect);
printk(KERN_INFO "filter: number of sectors %lu\n", (unsigned long)bd->bd_part->nr_sects);
printk(KERN_INFO "filter: logical block size %d\n", bdev_logical_block_size(bd));
printk(KERN_INFO "filter: physical block size %d\n", bdev_physical_block_size(bd));
set_mrqfn();
if(!(my_hooks = kmem_cache_create("my_hooks",sizeof(struct hook), __alignof__(struct hook),0 ,NULL))){
return 1; // fail!!!
};
return 0;
}
static void __exit filter_exit(void)
{
printk(KERN_DEBUG "filter: %s\n", __FUNCTION__);
restore_mrqfn();
// clear HOOKs
if(my_hooks){
kmem_cache_destroy(my_hooks);
}
if (!IS_ERR(bd)) {
blkdev_put(bd, FMODE_READ);
}
}
module_init(filter_init);
module_exit(filter_exit);
MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("VV");