Skip to content

Latest commit

 

History

History
126 lines (114 loc) · 3.7 KB

md-moduleioctl-setarrayinfo.md

File metadata and controls

126 lines (114 loc) · 3.7 KB

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