ioctl-SET_ARRAY_INFO

mdadm 툴은 다음과 같이 SET_ARRAY_INFO 명령을 실행합니다.

int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info)
{
......
        if ((vers % 100) >= 1) { /* can use different versions */
        mdu_array_info_t inf;
        memset(&inf, 0, sizeof(inf));
        inf.major_version = info->array.major_version;
        inf.minor_version = info->array.minor_version;
        rv = ioctl(mdfd, SET_ARRAY_INFO, &inf);

md 모듈에서는 다음과 같이 SET_ARRAY_INFO 명령의 처리를 시작합니다.

다음은 사용자로부터 받은 mdu_array_info_t 객체를 커널 영역의 info 변수로 복사하는 것입니다.

    if (cmd == SET_ARRAY_INFO) {
        mdu_array_info_t info;
        if (!arg)
            memset(&info, 0, sizeof(info));
        else if (copy_from_user(&info, argp, sizeof(info))) {
            err = -EFAULT;
            goto unlock;
        }

gdb를 이용해서 복사된 정보가 무엇인지 확인해보면 major_version과 minor_version이 복사된 것을 알 수 있습니다.

(gdb) p info
$36 = {major_version = 1, minor_version = 2, patch_version = 0, ctime = 0, level = 0, size = 0, 
  nr_disks = 0, raid_disks = 0, md_minor = 0, not_persistent = 0, utime = 0, state = 0, 
  active_disks = 0, working_disks = 0, failed_disks = 0, spare_disks = 0, layout = 0, 
  chunk_size = 0}

다음은 mddev가 이미 존재하던 객체인지를 확인하는 코드입니다.

        if (mddev->pers) {
            err = update_array_info(mddev, &info);
            if (err) {
                printk(KERN_WARNING "md: couldn't update"
                       " array info. %d\n", err);
                goto unlock;
            }
            goto unlock;
        }
        if (!list_empty(&mddev->disks)) {
            printk(KERN_WARNING
                   "md: array %s already has disks!\n",
                   mdname(mddev));
            err = -EBUSY;
            goto unlock;
        }
        if (mddev->raid_disks) {
            printk(KERN_WARNING
                   "md: array %s already initialised!\n",
                   mdname(mddev));
            err = -EBUSY;
            goto unlock;
        }

우리가 만든 md0 디스크는 아직 생성이 안된 디스크이기때문에 mddev 객체에는 아무 정보도 없습니다. 다음과 같이 gdb로 확인이 가능합니다.

(gdb) p mddev->pers
$39 = (struct md_personality *) 0x0 <irq_stack_union>
(gdb) p mddev->raid_disks
$37 = 0
(gdb) p mddev->disks
$38 = {next = 0xffff880006832818, prev = 0xffff880006832818}

결국 커널에서는 다음과 같이 set_array_info 함수가 호출됩니다.

        err = set_array_info(mddev, &info);
        if (err) {
            printk(KERN_WARNING "md: couldn't set"
                   " array info. %d\n", err);
            goto unlock;
        }
        goto unlock;
    }

set_array_info함수는 다음과 같이 mddev 객체의 major_version, minor_version, patch_version 필드에 사용자로부터 받은 값을 저장하는 함수입니다. 지금은 각각 1, 2, 0이 저장됩니다.

Breakpoint 4, md_ioctl (bdev=0xffff880006174000, mode=<optimised out>, cmd=1078462755, 
    arg=<optimised out>) at drivers/md/md.c:6828
6828            err = set_array_info(mddev, &info);
(gdb) s
set_array_info (info=<optimised out>, mddev=<optimised out>) at drivers/md/md.c:6348
6348        if (info->raid_disks == 0) {
(gdb) n
6350            if (info->major_version < 0 ||
(gdb) n
6352                super_types[info->major_version].name == NULL) {
(gdb) n
6351                info->major_version >= ARRAY_SIZE(super_types) ||
(gdb) n
6359            mddev->major_version = info->major_version;
(gdb) n
6360            mddev->minor_version = info->minor_version;
(gdb) n
6361            mddev->patch_version = info->patch_version;
(gdb) n
6362            mddev->persistent = !info->not_persistent;
(gdb) n
6366            mddev->ctime         = get_seconds();
(gdb) n

함수가 종료된뒤 mddev객체의 major_version, minor_version의 값을 확인해봤습니다.

(gdb) p mddev->major_version
$43 = 1
(gdb) p mddev->minor_version
$44 = 2

results matching ""

    No results matching ""