0

我有一个 2.4 内核版本的 Linux 系统。我需要通过设备映射器为根分区制作一个映射设备,并在启动时挂载到它。

我需要使用特殊的映射器类型(不是像线性镜像这样的标准映射器)。因此,我尝试编写自己的内核模块,实现必要的功能(现在它只是将查询传输到真实设备)。

我以这篇文章为起点。我已经对其代码进行了一些更改,所以现在它看起来像这样:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/device-mapper.h>

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
#include <linux/bio.h>
#endif

#include <linux/fs.h>
#include <linux/kdev_t.h>

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
#include <linux/mm.h>
#endif

struct Sddm_target
{
    struct dm_dev *dev;
    sector_t start;
};

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
static int sddm_target_map(struct dm_target *ti, struct buffer_head *bh, int rw, union map_info *map_context)
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,32)
static int sddm_target_map(struct dm_target *ti, struct bio *bio, union map_info *map_context)
#else
static int sddm_target_map(struct dm_target *ti, struct bio *bio)
#endif
{
    struct Sddm_target *mdt;

    mdt = (struct Sddm_target *) ti->private;

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
    bh->b_dev = mdt->dev->bdev->bd_dev;
#else
    bio->bi_bdev = mdt->dev->bdev;
#endif

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
    submit_bh(rw, bh);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,32)
    submit_bio(bio->bi_rw, bio);
#else
    submit_bio(bio);
#endif

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
    return 0;
#else
    return DM_MAPIO_SUBMITTED;
#endif
}

static int sddm_target_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
    struct Sddm_target *mdt;
    unsigned long start;
    unsigned long len;
    int err;

    if (argc != 2)
    {
        ti->error = "Invalid argument count";
        return -EINVAL;
    }

    mdt = (struct Sddm_target*)kmalloc(sizeof(struct Sddm_target), GFP_KERNEL);

    if (mdt == NULL)
    {
        printk(KERN_CRIT "\n Mdt is null\n");
        ti->error = "dm-basic_target: Cannot allocate linear context";
        return -ENOMEM;
    }       

    if (sscanf(argv[1], "%lu", &start) != 1)
    {
        ti->error = "dm-basic_target: Invalid deviceee sector";
        kfree(mdt);
        printk(KERN_CRIT "\n>>out function basic_target_ctr with errorrrrrrrrrr \n");           
        return -EINVAL;
    }

    mdt->start = (sector_t)start;

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
    err = dm_get_device(ti, argv[0], ti->begin, ti->len, dm_table_get_mode(ti->table), &mdt->dev);
#else
    err = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &mdt->dev);
#endif
    if (err)
    {
        ti->error = "dm-basic_target: Device lookup failed";
        kfree(mdt);
        return -EINVAL;
    }

    ti->private = mdt;

    return 0;
}

static void sddm_target_dtr(struct dm_target *ti)
{
    struct Sddm_target *mdt = (struct Sddm_target *) ti->private;

    dm_put_device(ti, mdt->dev);
    kfree(mdt);
}

static struct target_type sddm_target = {
        .name = "sddm_target",
        .version = {1,0,0},
        .module = THIS_MODULE,
        .ctr = sddm_target_ctr,
        .dtr = sddm_target_dtr,
        .map = sddm_target_map,
};

static int __init init_sddm_target(void)
{
    int result;

    result = dm_register_target(&sddm_target);

    return 0;
}

static void __exit cleanup_sddm_target(void)
{
    dm_unregister_target(&sddm_target);
}

module_init(init_sddm_target);

module_exit(cleanup_sddm_target);

MODULE_LICENSE("GPL");

您会看到,主要功能是将目标设备更改为另一个(真实)并重新提交查询:

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
    bh->b_dev = MKDEV(3, 3);
#else
    bio->bi_bdev = mdt->dev->bdev;
#endif

#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
    submit_bh(rw, bh);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,32)
    submit_bio(bio->bi_rw, bio);
#else
    submit_bio(bio);
#endif

Rowbh->b_dev = MKDEV(3, 3);是错误的,但不知道合适的设备号在哪里,所以我尝试自己计算。

我的下一步是更改其中的initrd映像和linuxrc文件:

#!/bin/nash

echo "Loading dm-mod.o module"
insmod /lib/dm-mod.o 
echo "Loading scsi_mod.o module"
insmod /lib/scsi_mod.o 
echo "Loading sd_mod.o module"
insmod /lib/sd_mod.o 
echo "Loading cdrom.o module"
insmod /lib/cdrom.o 
echo "Loading sr_mod.o module"
insmod /lib/sr_mod.o 
echo "Loading sg.o module"
insmod /lib/sg.o 
echo "Loading usbcore.o module"
insmod /lib/usbcore.o 
echo "Loading usb-storage.o module"
insmod /lib/usb-storage.o 
sleep 5
echo "Loading jbd.o module"
insmod /lib/jbd.o 
echo "Loading ext3.o module"
insmod /lib/ext3.o 
insmod /lib//sddm_target.o
echo Mounting /proc filesystem
mount -t proc /proc /proc
echo Creating block devices
mkdevices /dev
echo Creating root device

echo "======================================"
ld-linux.so.2 /bin/dmsetup create root_part /opt/bin/table
echo "======================================"

mkrootdev /dev/root
echo 0x0100 > /proc/sys/kernel/real-root-dev

echo "MOUNT START==============="
mount -o acl,nosecdel,secrm --ro -t ext3 /dev/mapper/root_part /sysroot
echo "MOUNT DONE==============="

pivot_root /sysroot /sysroot/initrd
umount /initrd/proc

其中sddm_target - 是我的内核模块。

表文件包含:

0 62814150 sddm_target /dev/hda3 0

映射设备出现在给定的目录中,所以看起来一切都很好。但是当我尝试引导我的系统时,我运行了几次 sddm_target_map函数,并通过设备安装调用,然后引导保持并显示以下消息:

kjournald started. Commit intervel 5 seconds

一些谷歌搜索帮助我理解,这条消息是由文件系统检查程序打印的。但它的原因是什么 - 我不知道。

我需要帮助!

4

0 回答 0