강좌 & 팁
안녕하세요 판다 이우영입니다.
복습!!
gendisk 등록 방법입니다.
typedef struct { void *priv; struct request_queue *queue; spinlock_t lock; struct gendisk *gd; } XXX_device; static XXX_device device[MAX_DEVICE]; ----------------------------------------------------------------------------------------------------------- int XXX_init( void) { .... for(lp = 0; lp < MAX_DEVICE; lp++) { device[lp].data = vdisk[lp]; device[lp].gd = alloc_disk(1); .... device[lp].gd->major = XXX; device[lp].gd->first_minor = lp; device[lp].gd->fops = &fops; ....
add_disk(device[lp].gd); } .... } |
중요한 gendisk 필드들입니다.
int major; | 디바이스 드라이버의 주 번호 |
int first_minor; | 디바이스 드라이버 부 번호 |
struct block_device_operations *fops; | 블록 오퍼레이션 등록 |
struct request_queue *queue; | 블록 디바이스마다 관리하는 요구 큐를 등록 |
char disk_name[DISK_NAME_LEN]; | 블록 디바이스의 기본이름을 입력 |
int flags; | 블록 디바이스의 특성 (제거가 가능하거나 CD-ROM) |
void *private_data; | request() 함수에서 디바이스 정보를 얻기위해 사용 |
복습은 간단하게 넘어가고 오늘내용 알아보겠습니다.
gendisk 등록 및 삭제
저번시간에 설명했던 gendisk 를 등록하는 방법과 제거하는 방법을 조금더 알아 보겠습니다.
gendisk는 alloc_disk()함수를 이용해서 생성한다고 했습니다.
함수원형은 다음과 같습니다.
struct gendisk
*alloc_disk(int minors);
인자값은 파티션의 수가 들어갑니다 만약 파티션의 수가 3개라면 블럭디바이스를 포함하여 4개를 넣어주셔야 합니다.
실제 소스 코드 입니다.
/block/genhd.c
1127struct gendisk *alloc_disk(int minors) 1128{ 1129 return alloc_disk_node(minors, -1); 1130} 1131EXPORT_SYMBOL(alloc_disk); 1132 1133struct gendisk *alloc_disk_node(int minors, int node_id) 1134{ 1135 struct gendisk *disk; 1136 1137 disk = kmalloc_node(sizeof(struct gendisk), 1138 GFP_KERNEL | __GFP_ZERO, node_id); 1139 if (disk) { 1140 if (!init_part_stats(&disk->part0)) { 1141 kfree(disk); 1142 return NULL; 1143 } 1144 disk->node_id = node_id; 1145 if (disk_expand_part_tbl(disk, 0)) { 1146 free_part_stats(&disk->part0); 1147 kfree(disk); 1148 return NULL; 1149 } 1150 disk->part_tbl->part[0] = &disk->part0; 1151 1152 disk->minors = minors; 1153 rand_initialize_disk(disk); 1154 disk_to_dev(disk)->class = &block_class; 1155 disk_to_dev(disk)->type = &disk_type; 1156 device_initialize(disk_to_dev(disk)); 1157 INIT_WORK(&disk->async_notify, 1158 media_change_notify_thread); 1159 } 1160 return disk; 1161} 1162EXPORT_SYMBOL(alloc_disk_node);
그리고 gendisk를 생성했다면 커널에 등록을 해주어야 겠죠?
void add_disk(struct gendisk *disk);
할당받은 gendisk를 넘겨주면 커널에 등록을 합니다.
/block/genhd.c
503/** 504 * add_disk - add partitioning information to kernel list 505 * @disk: per-device partitioning information 506 * 507 * This function registers the partitioning information in @disk 508 * with the kernel. 509 * 510 * FIXME: error handling 511 */ 512void add_disk(struct gendisk *disk) 513{ 514 struct backing_dev_info *bdi; 515 dev_t devt; 516 int retval; 517 518 /* minors == 0 indicates to use ext devt from part0 and should 519 * be accompanied with EXT_DEVT flag. Make sure all 520 * parameters make sense. 521 */ 522 WARN_ON(disk->minors && !(disk->major || disk->first_minor)); 523 WARN_ON(!disk->minors && !(disk->flags & GENHD_FL_EXT_DEVT)); 524 525 disk->flags |= GENHD_FL_UP; 526 527 retval = blk_alloc_devt(&disk->part0, &devt); 528 if (retval) { 529 WARN_ON(1); 530 return; 531 } 532 disk_to_dev(disk)->devt = devt; 533 534 /* ->major and ->first_minor aren't supposed to be 535 * dereferenced from here on, but set them just in case. 536 */ 537 disk->major = MAJOR(devt); 538 disk->first_minor = MINOR(devt); 539 540 blk_register_region(disk_devt(disk), disk->minors, NULL, 541 exact_match, exact_lock, disk); 542 register_disk(disk); 543 blk_register_queue(disk); 544 545 bdi = &disk->queue->backing_dev_info; 546 bdi_register_dev(bdi, disk_devt(disk)); 547 retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj, 548 "bdi"); 549 WARN_ON(retval); 550}
블록 디바이스 드라이버를 제거할때는 이 gendisk를 해제해야겠죠?
등록한 gendisk를 먼저 커널에서 제거합니다.
/fs/partitions/check.c
604void del_gendisk(struct gendisk *disk) 605{ 606 struct disk_part_iter piter; 607 struct hd_struct *part; 608 609 /* invalidate stuff */ 610 disk_part_iter_init(&piter, disk, 611 DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE); 612 while ((part = disk_part_iter_next(&piter))) { 613 invalidate_partition(disk, part->partno); 614 delete_partition(disk, part->partno); 615 } 616 disk_part_iter_exit(&piter); 617 618 invalidate_partition(disk, 0); 619 blk_free_devt(disk_to_dev(disk)->devt); 620 set_capacity(disk, 0); 621 disk->flags &= ~GENHD_FL_UP; 622 unlink_gendisk(disk); 623 part_stat_set_all(&disk->part0, 0); 624 disk->part0.stamp = 0; 625 626 kobject_put(disk->part0.holder_dir); 627 kobject_put(disk->slave_dir); 628 disk->driverfs_dev = NULL; 629#ifndef CONFIG_SYSFS_DEPRECATED 630 sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); 631#endif 632 device_del(disk_to_dev(disk)); 633}
마지막으로 gendisk의 할당을 해제하면 됩니다.
해제하는 함수는 다음과 같습니다.
void put_disk(struct gendisk *disk);
여기에는 할당받은 gendisk를 넘겨주면 끝입니다.
/block/genhd.c
1185void put_disk(struct gendisk *disk) 1186{ 1187 if (disk) 1188 kobject_put(&disk_to_dev(disk)->kobj); 1189}/lib/kobject.c
586void kobject_put(struct kobject *kobj) 587{ 588 if (kobj) { 589 if (!kobj->state_initialized) 590 WARN(1, KERN_WARNING "kobject: '%s' (%p): is not " 591 "initialized, yet kobject_put() is being " 592 "called.\n", kobject_name(kobj), kobj); 593 kref_put(&kobj->kref, kobject_release); 594 } 595}
그럼 오늘도 간단하게 끝을내겠습니다.
그럼 다음시간에 만나요~.