在引导时挂载映射设备

时间:2017-02-15 09:40:29

标签: linux linux-kernel boot initrd device-mapper

我有一个2.4内核版本的Linux系统。我需要通过 device-mapper 为根分区创建一个映射设备,并在启动时挂载它。

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

我使用this文章作为起点。我在代码中做了一些更改,现在它看起来像这样:

#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

bh->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

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

我需要帮助!

0 个答案:

没有答案