The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]



Индекс форумов
Составление сообщения

Исходное сообщение
"Фильтр block device в Линукс"
Отправлено Doublehead, 13-Ноя-18 21:44 
>>> Диск примонтирован? Может дисковый кэш. Что будет при команде 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");

 

Ваше сообщение
Имя*:
EMail:
Для отправки новых сообщений в текущей нити на email укажите знак ! перед адресом, например, !user@host.ru (!! - не показывать email).
Более тонкая настройка отправки ответов производится в профиле зарегистрированного участника форума.
Заголовок*:
Сообщение*:
 
При общении не допускается: неуважительное отношение к собеседнику, хамство, унизительное обращение, ненормативная лексика, переход на личности, агрессивное поведение, обесценивание собеседника, провоцирование флейма голословными и заведомо ложными заявлениями. Не отвечайте на сообщения, явно нарушающие правила - удаляются не только сами нарушения, но и все ответы на них. Лог модерирования.



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру