Study KVM internal 2

The C Preprocessor

- เพื่อให้ทำความเข้าใจ Code ของ KVM ได้ดียิ่งขึ้น จึงศึกษาเกี่ยวกับ Preprocessor เพิ่มเติม ที่ The C Preprocessor ยกตัวอย่างบางส่วนที่น่าสนใจและมีอยู่ใน Code ของ KVM คือ Macros ซึ่งมีสัญลักษณ์แปลก ๆ เช่น ## ที่ปรากฏอยู่ในหัวข้อ Concatenation

- เพื่อให้เข้าใจถึงกลไกของ Compiler ในการจัดการกับ Preprocessor ให้มากขึ้น จึงทดลองเขียนโปรแกรมที่มี Preprocessor อยู่ใน Code และทดลองใช้ Compiler ทำการ Compile แล้วดูผลลัพธ์ที่ได้จาก Preprocessor

- เขียนโปรแกรมภาษา C ง่าย ๆ

- ทำการ Compile โดยใช้คำสั่ง gcc -E เพื่อให้ Compiler ทำงานเฉพาะในส่วนของ Preprocessor ได้ผลดังภาพ

- สังเกตผลที่ได้ และ นำความรู้ในส่วนนี้ ไปประยุกต์ใช้ในการศึกษา Code ของ KVM ในหัวข้อต่อ ๆ ไป

Study block_init()

- ศึกษา block_init() จากไฟล์ module.h

 16 ...
 17 /* This should not be used directly.  Use block_init etc. instead.  */
 18 #define module_init(function, type)
 19 static void __attribute__((constructor)) do_qemu_init_ ## function(void) {
 20     register_module_init(function, type);
 21 }
 22
 23 typedef enum {
 24     MODULE_INIT_BLOCK,
 25     MODULE_INIT_DEVICE,
 26     MODULE_INIT_MACHINE,
 27     MODULE_INIT_MAX
 28 } module_init_type;
 29
 30 #define block_init(function) module_init(function, MODULE_INIT_BLOCK)
 31 #define device_init(function) module_init(function, MODULE_INIT_DEVICE)
 32 #define machine_init(function) module_init(function, MODULE_INIT_MACHINE)
 33
 34 void register_module_init(void (*fn)(void), module_init_type type);
 35 ...

- เขียนโปรแกรมอย่างง่าย โดยทำการ #include “module.h” เข้าไปด้วย บันทึกชื่อ block_init.c
- เรียกใช้ block_init(bdrv_qcow2_init) และ block_init(bdrv_raw_init)

- ใช้ Compiler ตรวจสอบการทำงานของ Preprocessor ด้วยคำสั่ง gcc -E block_init.c

- ผลที่ได้พบว่าเมื่อเรียกใช้ block_init(bdrv_qcow2_init) จะถูกเปลี่ยนเป็น

static void __attribute__((constructor)) do_qemu_init_bdrv_qcow2_init(void) {
    register_module_init(bdrv_qcow2_init, MODULE_INIT_BLOCK);
};

- และ block_init(bdrv_raw_init) ก็เช่นกัน

static void __attribute__((constructor)) do_qemu_init_bdrv_raw_init(void) {
    register_module_init(bdrv_raw_init, MODULE_INIT_BLOCK);
};

- ศึกษาเกี่ยวกับ Program Library Howto ในส่วนของ ((constructor)) พบว่า ฟังก์ชันที่ได้จาก Preprocessor ดังกล่าว อันได้แก่ do_qemu_init_bdrv_qcow2_init() และ do_qemu_init_bdrv_raw_init() จะทำงานในขณะโปรแกรมกำลังโหลดเข้าสู่ระบบ นั่นคือ ก่อนที่ dlopen() จะ return หรือก่อนเข้าฟังก์ชัน main()

- เพื่อให้เข้าใจมากขึ้นจึงเขียนโปรแกรม ที่มีการเรียกใช้ ((constructor))

- ทำการ Compile และ Run พบว่า ฟังก์ชัน hello() ทำงานก่อน main()

Study bdrv_open() and bdrv_close()

- ศึกษา Data Structure ที่เกี่ยวข้องกับฟังก์ชัน bdrv_open() และ bdrv_close() มีดังนี้

 ...
 356 int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
 357                BlockDriver *drv)
 ...
 ...
 507 void bdrv_close(BlockDriverState *bs)
 ...

- มี 4 ตัว แต่ที่โครงสร้างค่อนข้างซับซ้อนมี 2 ตัว ได้แก่ BlockDriverState และ BlockDriver

- ศึกษา BlockDriverState จาก block_int.h

125
126 struct BlockDriverState {
127     int64_t total_sectors; /* if we are reading a disk image, give its
128                               size in sectors */
129     int read_only; /* if true, the media is read only */
130     int removable; /* if true, the media can be removed */
131     int locked;    /* if true, the media cannot temporarily be ejected */
132     int encrypted; /* if true, the media is encrypted */
133     int valid_key; /* if true, a valid encryption key has been set */
134     int sg;        /* if true, the device is a /dev/sg* */
135     /* event callback when inserting/removing */
136     void (*change_cb)(void *opaque);
137     void *change_opaque;
138
139     BlockDriver *drv; /* NULL means no media */
140     void *opaque;
141
142     char filename[1024];
143     char backing_file[1024]; /* if non zero, the image is a diff of
144                                 this file image */
145     char backing_format[16]; /* if non-zero and backing_file exists */
146     int is_temporary;
147     int media_changed;
148
149     BlockDriverState *backing_hd;
150     /* async read/write emulation */
151
152     void *sync_aiocb;
153
154     /* I/O stats (display with "info blockstats"). */
155     uint64_t rd_bytes;
156     uint64_t wr_bytes;
157     uint64_t rd_ops;
158     uint64_t wr_ops;
159
160     /* Whether the disk can expand beyond total_sectors */
161     int growable;
162
163     /* the memory alignment required for the buffers handled by this driver
164     int buffer_alignment;
165
166     /* do we need to tell the quest if we have a volatile write cache? */
167     int enable_write_cache;
168
169     /* NOTE: the following infos are only hints for real hardware
170        drivers. They are not used by the block driver */
171     int cyls, heads, secs, translation;
172     int type;
173     char device_name[32];
174     unsigned long *dirty_bitmap;
175     BlockDriverState *next;
176     void *private;
177 };
178

- และศึกษา BlockDriver

 47
 48 struct BlockDriver {
 49     const char *format_name;
 50     int instance_size;
 51     int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename
 52     int (*bdrv_probe_device)(const char *filename);
 53     int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags);
 54     int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
 55                      uint8_t *buf, int nb_sectors);
 56     int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
 57                       const uint8_t *buf, int nb_sectors);
 58     void (*bdrv_close)(BlockDriverState *bs);
 59     int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
 60     void (*bdrv_flush)(BlockDriverState *bs);
 61     int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
 62                              int nb_sectors, int *pnum);
 63     int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
 64     int (*bdrv_make_empty)(BlockDriverState *bs);
 65     /* aio */
 66     BlockDriverAIOCB *(*bdrv_aio_readv)(BlockDriverState *bs,
 67         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 68         BlockDriverCompletionFunc *cb, void *opaque);
 69     BlockDriverAIOCB *(*bdrv_aio_writev)(BlockDriverState *bs,
 70         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
 71         BlockDriverCompletionFunc *cb, void *opaque);
 72     BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs,
 73         BlockDriverCompletionFunc *cb, void *opaque);
 74
 75     int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs,
 76         int num_reqs);
 77     int (*bdrv_merge_requests)(BlockDriverState *bs, BlockRequest* a,
 78         BlockRequest *b);
 79
 80
 81     const char *protocol_name;
 82     int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
 83     int64_t (*bdrv_getlength)(BlockDriverState *bs);
 84     int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num,
 85                                  const uint8_t *buf, int nb_sectors);
 86
 87     int (*bdrv_snapshot_create)(BlockDriverState *bs,
 88                                 QEMUSnapshotInfo *sn_info);
 89     int (*bdrv_snapshot_goto)(BlockDriverState *bs,
 90                               const char *snapshot_id);
 91     int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_i
 92     int (*bdrv_snapshot_list)(BlockDriverState *bs,
 93                               QEMUSnapshotInfo **psn_info);
 94     int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
 95
 96     int (*bdrv_save_vmstate)(BlockDriverState *bs, const uint8_t *buf,
 97                              int64_t pos, int size);
 98     int (*bdrv_load_vmstate)(BlockDriverState *bs, uint8_t *buf,
 99                              int64_t pos, int size);
100
101     /* removable device specific */
102     int (*bdrv_is_inserted)(BlockDriverState *bs);
103     int (*bdrv_media_changed)(BlockDriverState *bs);
104     int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
105     int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
106
107     /* to control generic scsi devices */
108     int (*bdrv_ioctl)(BlockDriverState *bs, unsigned long int req, void *buf
109     BlockDriverAIOCB *(*bdrv_aio_ioctl)(BlockDriverState *bs,
110         unsigned long int req, void *buf,
111         BlockDriverCompletionFunc *cb, void *opaque);
112
113     /* List of options for creating images, terminated by name == NULL */
114     QEMUOptionParameter *create_options;
115
116
117     /* Returns number of errors in image, -errno for internal errors */
118     int (*bdrv_check)(BlockDriverState* bs);
119
120     /* Set if newly created images are not guaranteed to contain only zeros
121     int no_zero_init;
122
123     struct BlockDriver *next;
124 };
125

- สังเกต ตัวแปรที่ขีดเส้นใต้ จะเห็นได้ว่าเป็น Pointer และส่วนใหญ่เป็น Pointer ที่ชี้หา Data Type ชนิดเดียวกัน ดังนั้น Data Structure จึงเป็นไปในลักษณะ Linked List โดย BlockDriver และ BlockDriverState มีความสัมพันธ์กันดังนี้

                     +----+----------------------+----+
                     |    |                      |    |
         *backing_hd |    |                      |    | *next
 ... <-----------------o  |   BlockDriverState   |  o-----------------> ...
                     |    |                      |    |
                     +----+----------------------+----+
                     |                o               |
                     +----------------|---------------+
                                      | *drv
                                      |
                                      V
                          +----------------------+----+
                          |                      |    |
                          |      BlockDriver     |    | *next
                          |                      |  o-----------------> ...
                          |                      |    |
                          +----------------------+----+

- Find out ‘WHEN” and “WHERE” the bdrv_open() function is called (!!! กำลังดำเนินการ ยังไม่แล้วเสร็จ !!!)
- Draw the function call graph for the bdrv_open() function (!!! กำลังดำเนินการ ยังไม่แล้วเสร็จ !!!)
- Describe what happen to the data structure in 2) when the bdrv_open() function is called to open an overlay hard disk image (!!! กำลังดำเนินการ ยังไม่แล้วเสร็จ !!!)

- ศึกษา bdrv_open() โดยเพิ่ม Code ในฟังก์ชัน bdrv_open2() ดังนี้

 356 int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
 357                BlockDriver *drv)
 358 {
 359     // Add by Phithak Thaenkaew
 360     int phithak_seq = rand() % 10000;   // Sequence number
 361     printf("Enter bdrv_open2(), Seq %04d, Flag %2d, Filename: %s\n",
 362         phithak_seq, flags, filename);
 363
 364     printf(" Before --\n");
 365     printf("  filename: %s\n", bs->filename);
 366     printf("  backing_file: %s\n", bs->backing_file);
 367     printf("  backing_format: %s\n", bs->backing_format);
 368     printf("  read_only: %d\n", bs->read_only);
 369     printf("  removable: %d\n", bs->removable);
 370
 371     printf("  *drv: %s\n", (bs->drv==NULL)?"NULL":"NOT NULL");
 372     if (!(bs->drv==NULL)) {
 373         printf("   ->format_name: %s\n", bs->drv->format_name);
 374         printf("   ->protocol_name: %s\n", bs->drv->protocol_name);
 375     }
 376
 377     printf("  *backing_hd: %s\n", (bs->backing_hd==NULL)?"NULL":"NOT NULL");
 378     if (!(bs->backing_hd==NULL)) {
 379         printf("   ->filename: %s\n", bs->backing_hd->filename);
 380         printf("   ->backing_file: %s\n", bs->backing_hd->backing_file);
 381         printf("   ->backing_format: %s\n", bs->backing_hd->backing_format);
 382         printf("   ->read_only: %d\n", bs->backing_hd->read_only);
 383         printf("   ->removable: %d\n", bs->backing_hd->removable);
 384     }
 385
 386     printf("  *next: %s\n", (bs->next==NULL)?"NULL":"NOT NULL");
 387     if (!(bs->next==NULL)) {
 388         printf("   ->filename: %s\n", bs->next->filename);
 389         printf("   ->backing_file: %s\n", bs->next->backing_file);
 390         printf("   ->backing_format: %s\n", bs->next->backing_format);
 391         printf("   ->read_only: %d\n", bs->next->read_only);
 392         printf("   ->removable: %d\n", bs->next->removable);
 393     }
 ...
 ...
 ...
 540     printf(" After -- \n");
 541     printf("  filename: %s\n", bs->filename);
 542     printf("  backing_file: %s\n", bs->backing_file);
 543     printf("  backing_format: %s\n", bs->backing_format);
 544     printf("  read_only: %d\n", bs->read_only);
 545     printf("  removable: %d\n", bs->removable);
 546
 547     printf("  *drv: %s\n", (bs->drv==NULL)?"NULL":"NOT NULL");
 548     if (!(bs->drv==NULL)) {
 549         printf("   ->format_name: %s\n", bs->drv->format_name);
 550         printf("   ->protocol_name: %s\n", bs->drv->protocol_name);
 551     }
 552
 553     printf("  *backing_hd: %s\n", (bs->backing_hd==NULL)?"NULL":"NOT NULL");
 554     if (!(bs->backing_hd==NULL)) {
 555         printf("   ->filename: %s\n", bs->backing_hd->filename);
 556         printf("   ->backing_file: %s\n", bs->backing_hd->backing_file);
 557         printf("   ->backing_format: %s\n", bs->backing_hd->backing_format);
 558         printf("   ->read_only: %d\n", bs->backing_hd->read_only);
 559         printf("   ->removable: %d\n", bs->backing_hd->removable);
 560     }
 561
 562     printf("  *next: %s\n", (bs->next==NULL)?"NULL":"NOT NULL");
 563     if (!(bs->next==NULL)) {
 564         printf("   ->filename: %s\n", bs->next->filename);
 565         printf("   ->backing_file: %s\n", bs->next->backing_file);
 566         printf("   ->backing_format: %s\n", bs->next->backing_format);
 567         printf("   ->read_only: %d\n", bs->next->read_only);
 568         printf("   ->removable: %d\n", bs->next->removable);
 569     }
 570     // Add by Phithak
 571     printf(" Exit bdrv_open2(), Seq %04d, Flag %2d, Filename: %s\n",
 572         phithak_seq, flags, filename);
 573     printf("----------------------------------------------------------\n");
 574
 575     return 0;
 576 }

- ผลที่ได้จากจากเรียกใช้โปรแกรมที่ทำการแก้ไข โดยกำหนดให้ใช้ centos_ovl2.img คือ

phithak@phithak-laptop hw04 $ qemu-system-x86_64 -hda centos_ovl2.img -boot c -m 256
Enter bdrv_open2(), Seq 9383, Flag  0, Filename: centos_ovl2.img
 Before --
  filename:
  backing_file:
  backing_format:
  read_only: 0
  removable: 0
  *drv: NULL
  *backing_hd: NULL
  *next: NULL
Enter bdrv_open2(), Seq 0886, Flag 16, Filename: centos_ovl2.img
 Before --
  filename:
  backing_file:
  backing_format:
  read_only: 0
  removable: 0
  *drv: NULL
  *backing_hd: NULL
  *next: NULL
 After --
  filename: centos_ovl2.img
  backing_file:
  backing_format:
  read_only: 1
  removable: 0
  *drv: NOT NULL
   ->format_name: raw
   ->protocol_name: (null)
  *backing_hd: NULL
  *next: NULL
 Exit bdrv_open2(), Seq 0886, Flag 16, Filename: centos_ovl2.img
----------------------------------------------------------
Enter bdrv_open2(), Seq 2777, Flag 18, Filename: centos_ovl2.img
 Before --
  filename:
  backing_file:
  backing_format:
  read_only: 0
  removable: 0
  *drv: NULL
  *backing_hd: NULL
  *next: NULL
 After --
  filename: centos_ovl2.img
  backing_file:
  backing_format:
  read_only: 0
  removable: 0
  *drv: NOT NULL
   ->format_name: raw
   ->protocol_name: (null)
  *backing_hd: NULL
  *next: NULL
 Exit bdrv_open2(), Seq 2777, Flag 18, Filename: centos_ovl2.img
----------------------------------------------------------
Enter bdrv_open2(), Seq 6915, Flag  2, Filename: centos_base.img
 Before --
  filename:
  backing_file:
  backing_format:
  read_only: 0
  removable: 0
  *drv: NULL
  *backing_hd: NULL
  *next: NULL
Enter bdrv_open2(), Seq 7793, Flag 16, Filename: centos_base.img
 Before --
  filename:
  backing_file:
  backing_format:
  read_only: 0
  removable: 0
  *drv: NULL
  *backing_hd: NULL
  *next: NULL
 After --
  filename: centos_base.img
  backing_file:
  backing_format:
  read_only: 1
  removable: 0
  *drv: NOT NULL
   ->format_name: raw
   ->protocol_name: (null)
  *backing_hd: NULL
  *next: NULL
 Exit bdrv_open2(), Seq 7793, Flag 16, Filename: centos_base.img
----------------------------------------------------------
Enter bdrv_open2(), Seq 8335, Flag 18, Filename: centos_base.img
 Before --
  filename:
  backing_file:
  backing_format:
  read_only: 0
  removable: 0
  *drv: NULL
  *backing_hd: NULL
  *next: NULL
 After --
  filename: centos_base.img
  backing_file:
  backing_format:
  read_only: 0
  removable: 0
  *drv: NOT NULL
   ->format_name: raw
   ->protocol_name: (null)
  *backing_hd: NULL
  *next: NULL
 Exit bdrv_open2(), Seq 8335, Flag 18, Filename: centos_base.img
----------------------------------------------------------
 After --
  filename: centos_base.img
  backing_file:
  backing_format:
  read_only: 0
  removable: 0
  *drv: NOT NULL
   ->format_name: qcow2
   ->protocol_name: (null)
  *backing_hd: NULL
  *next: NULL
 Exit bdrv_open2(), Seq 6915, Flag  2, Filename: centos_base.img
----------------------------------------------------------
 After --
  filename: centos_ovl2.img
  backing_file: centos_base.img
  backing_format:
  read_only: 0
  removable: 0
  *drv: NOT NULL
   ->format_name: qcow2
   ->protocol_name: (null)
  *backing_hd: NOT NULL
   ->filename: centos_base.img
   ->backing_file:
   ->backing_format:
   ->read_only: 0
   ->removable: 0
  *next: NULL
 Exit bdrv_open2(), Seq 9383, Flag  0, Filename: centos_ovl2.img
----------------------------------------------------------

Tools

grep, vi editor, gcc

References

http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html
http://www.faqs.org/docs/Linux-HOWTO/Program-Library-HOWTO.html#INIT-AND-CLEANUP

Mirror Site

- http://phithak.com/study-kvm-internal-2
- http://phithak.wordpress.com/2010/08/26/study-kvm-internal-2/

(ที่มา: การบ้าน หัวข้อ CS797 Exercise 6 – Study KVM internal 2 วิชา CS797 Advanced Topics in Computer Science – Introduction to Computer Virtualization ภาคเรียนที่ 1/2553 อาจารย์ผู้สอน ดร.กษิดิศ ชาญเชี่ยว ภาควิชาวิทยาการคอมพิวเตอร์ คณะวิทยาศาสตร์และเทคโนโลยี มหาวิทยาลัยธรรมศาสตร์)

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.