Linuxã«ãŒãã«5.0ã¯ãã§ã«ãªãªãŒã¹ãããŠãããArchãopenSUSE TumbleweedãFedoraãªã©ã®å®éšçãªãã£ã¹ããªãã¥ãŒã·ã§ã³ã«å«ãŸããŠããŸãã

ãŸããUbuntu Disko DingoãšRed Hat 8ã®RCãã£ã¹ããªãã¥ãŒã·ã§ã³ãèŠããšãæããã«ãªããŸãããŸããªãã«ãŒãã«5.0ããã¡ã³ãã¹ã¯ãããããæ¬æ ŒçãªãµãŒããŒã«ç§»è¡ãããŸãã
誰ããèšãã ãã-ã ããäœã 次ã®ãªãªãŒã¹ãç¹å¥ãªãã®ã¯ãããŸããã ããã§ãLinus Torvaldsèªèº«ãèšã£ãïŒ
æ©èœããŒã¹ã®ãªãªãŒã¹ã¯è¡ã£ãŠããããã5.0ãã¯4.xã®æ°å€ã倧ãããªãå§ããŠæã足ããªããªã£ãããšãæå³ãããã®ã§ã¯ãªãããšãïŒãŸã ïŒææããããšæããŸããšã€ãŸå ã
ïŒ ç§ã¯ããäžåºŠç¹°ãè¿ããŸã-ç§ãã¡ã®ãªãªãŒã¹ã¯ç¹å®ã®æ©èœã«çµã³ä»ããããŠããªãã®ã§ãæ°ããããŒãžã§ã³5.0ã®çªå·ã¯ãããŒãžã§ã³4.xã®çªå·ä»ãã®ããã«ååãªæãšã€ãŸå ããŸã ãªãããšãæå³ããŸã ïŒ
ãã ãããããããŒãã£ã¹ã¯çšã®ã¢ãžã¥ãŒã«ïŒèª°ãç¥ããªã-ãããã¯èžãã±ããã·ã£ãã®ãµã€ãºã®ãã£ã¹ã¯ã§ã容éã¯1.44 MBïŒ-ä¿®æ£æžã¿...
çç±ã¯æ¬¡ã®ãšããã§ãã
ããã¯ãã¹ãŠãã«ããã¥ãŒãããã¯ã¬ã€ã€ãŒïŒblk-mqïŒã«ã€ããŠã§ãã ã€ã³ã¿ãŒãããã«é¢ãã圌ã®çŽ¹ä»èšäºã¯ãããããããŸãã®ã§ãèŠç¹ã説æããŸãããã blk-mqãžã®ç§»è¡ã¯ããªãåã«éå§ããããã£ãããšåé²ããŠããŸããã ãã«ããã¥ãŒscsiïŒã«ãŒãã«ãã©ã¡ãŒã¿ãŒscsi_mod.use_blk_mqïŒãç»å Žããæ°ããã¹ã±ãžã¥ãŒã©ãŒmq-deadlineãbfqãªã©ãç»å ŽããŸããâŠ
[root@fedora-29 sblkdev]# cat /sys/block/sda/queue/scheduler [mq-deadline] none
ãšããã§ãããªãã¯äœã§ããïŒ
å€ãæ¹æ³ã§åäœãããããã¯ããã€ã¹ãã©ã€ããŒã®æ°ãåæžãããŸããã ãŸãã5.0ã§ã¯ãblk_init_queueïŒïŒé¢æ°ã¯äžèŠãªããåé€ãããŸããã ãããŠä»ã2003幎ã®å€ãæ å ã®ã³ãŒãlwn.net/Articles/58720㯠ã è¡ãå ã倱ã£ãã ãã§ãªããé¢é£æ§ã倱ããŸããã ããã«ãä»å¹Žã®ãªãªãŒã¹ã«åããŠæºåäžã®æ°ãããã£ã¹ããªãã¥ãŒã·ã§ã³ã¯ãããã©ã«ãæ§æã§ãã«ããã¥ãŒãããã¯ã¬ã€ã€ãŒã䜿çšããŸãã ããšãã°ã18æ¥ã®Manjaroã§ã¯ãã«ãŒãã«ã¯ããŒãžã§ã³4.19ã§ãããããã©ã«ãã§ã¯blk-mqã§ãã
ãããã£ãŠãã«ãŒãã«5.0ã®blk-mqãžã®ç§»è¡ãå®äºãããšæ³å®ã§ããŸãã ç§ã«ãšã£ãŠããã¯éèŠãªã€ãã³ãã§ãããã³ãŒãã®æžãæããšè¿œå ã®ãã¹ããå¿ èŠã«ãªããŸãã ããèªäœã倧å°ã®ãã°ãããã³ããã€ãã®ã¯ã©ãã·ã¥ãããµãŒããŒã®åºçŸãçŽæããŸãïŒFedyaãå¿ èŠã§ãïŒïŒCïŒïŒã
ã¡ãªã¿ã«ã誰ããrhel8ã®å Žåãã«ãŒãã«ãããŒãžã§ã³4.18ã§ããã©ãã·ã¥ããããã®ã§ããã®è»¢æç¹ãæ¥ãŠããªããšæããªããããªãã¯ééã£ãŠããŸãã rhel8ã®æ°ããRCã§ã¯ã5.0ã®æ°ãã補åãæ¢ã«ç§»è¡ãããŠãããblk_init_queueïŒïŒé¢æ°ãåé€ãããŸããïŒãããããå¥ã®ãã§ãã¯ã€ã³ãgithub.com/torvalds/linuxãããœãŒã¹ã«ãã©ãã°ãããšãïŒã
äžè¬ã«ãSUSEãRed Hatãªã©ã®Linuxãã£ã¹ããªãã¥ãŒã¿åãã®ãããªãŒãºãããŒãžã§ã³ã®ã«ãŒãã«ã¯ãé·ãéããŒã±ãã£ã³ã°ã®æŠå¿µã§ããã ã·ã¹ãã ã¯ãããšãã°ããŒãžã§ã³ã4.4ã§ãããå®éã«ã¯æ©èœãæ°ãã4.8ããã©ã®ãã®ã§ããããšãå ±åããŸãã åæã«ãå ¬åŒãŠã§ããµã€ãã«ã¯ããæ°ãããã£ã¹ããªãã¥ãŒã·ã§ã³ã§ã¯ãå®å®ãã4.4ã«ãŒãã«ãçšæãããŠããŸãããšããéæãèªç€ºãããŠããŸãã
ããããç§ãã¡ã¯æ°ãåãããŸãã...
ã ããããã«ã ãããã©ã®ããã«æ©èœããããæ確ã«ããããã«ãæ°ããåçŽãªãããã¯ããã€ã¹ãã©ã€ããŒãå¿ èŠã§ãã
ãã®ããã github.com / CodeImp / sblkdevã®ãœãŒã¹ã ç§ã¯è°è«ããããšãææ¡ãããã«ãªã¯ãšã¹ããè¡ããåé¡ãéå§ããŸãã QAã¯ãŸã ãã¹ãããŠããŸããã
èšäºã®åŸåã§ããã®çç±ã説æããŸãã ãããã£ãŠãå€ãã®ã³ãŒãããããŸãã
Linuxã«ãŒãã«ã®ã³ãŒãã£ã³ã°ã¹ã¿ã€ã«ãå®å šã«å°éãããŠããªãããšãããã«è¬ããŸããããã§ã-gotoã¯å¥œãã§ã¯ãããŸããã
ããã§ã¯ããšã³ããªãŒãã€ã³ãããå§ããŸãããã
static int __init sblkdev_init(void) { int ret = SUCCESS; _sblkdev_major = register_blkdev(_sblkdev_major, _sblkdev_name); if (_sblkdev_major <= 0){ printk(KERN_WARNING "sblkdev: unable to get major number\n"); return -EBUSY; } ret = sblkdev_add_device(); if (ret) unregister_blkdev(_sblkdev_major, _sblkdev_name); return ret; } static void __exit sblkdev_exit(void) { sblkdev_remove_device(); if (_sblkdev_major > 0) unregister_blkdev(_sblkdev_major, _sblkdev_name); } module_init(sblkdev_init); module_exit(sblkdev_exit);
æããã«ãã¢ãžã¥ãŒã«ãããŒãããããšãsblkdev_exitïŒïŒãã¢ã³ããŒãããããšãsblkdev_initïŒïŒé¢æ°ãèµ·åãããŸãã
register_blkdevïŒïŒé¢æ°ã¯ããããã¯ããã€ã¹ãç»é²ããŸãã 圌ã«ã¯ã¡ãžã£ãŒçªå·ãå²ãåœãŠãããŠããŸãã unregister_blkdevïŒïŒ-ãã®çªå·ã解æŸããŸãã
ã¢ãžã¥ãŒã«ã®äž»èŠãªæ§é ã¯sblkdev_device_tã§ãã
// The internal representation of our device typedef struct sblkdev_device_s { sector_t capacity; // Device size in bytes u8* data; // The data aray. u8 - 8 bytes atomic_t open_counter; // How many openers struct blk_mq_tag_set tag_set; struct request_queue *queue; // For mutual exclusion struct gendisk *disk; // The gendisk structure } sblkdev_device_t;
ããã«ã¯ãã«ãŒãã«ã¢ãžã¥ãŒã«ã«å¿ èŠãªããã€ã¹ã«é¢ãããã¹ãŠã®æ å ±ãç¹ã«ãããã¯ããã€ã¹ã®å®¹éãããŒã¿èªäœïŒåçŽã§ãïŒããã£ã¹ã¯ãžã®ãã€ã³ã¿ããã¥ãŒãå«ãŸããŠããŸãã
ãã¹ãŠã®ãããã¯ããã€ã¹ã®åæåã¯ãsblkdev_add_deviceïŒïŒé¢æ°ã§å®è¡ãããŸãã
static int sblkdev_add_device(void) { int ret = SUCCESS; sblkdev_device_t* dev = kzalloc(sizeof(sblkdev_device_t), GFP_KERNEL); if (dev == NULL) { printk(KERN_WARNING "sblkdev: unable to allocate %ld bytes\n", sizeof(sblkdev_device_t)); return -ENOMEM; } _sblkdev_device = dev; do{ ret = sblkdev_allocate_buffer(dev); if(ret) break; #if 0 //simply variant with helper function blk_mq_init_sq_queue. It`s available from kernel 4.20 (vanilla). {//configure tag_set struct request_queue *queue; dev->tag_set.cmd_size = sizeof(sblkdev_cmd_t); dev->tag_set.driver_data = dev; queue = blk_mq_init_sq_queue(&dev->tag_set, &_mq_ops, 128, BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE); if (IS_ERR(queue)) { ret = PTR_ERR(queue); printk(KERN_WARNING "sblkdev: unable to allocate and initialize tag set\n"); break; } dev->queue = queue; } #else // more flexible variant {//configure tag_set dev->tag_set.ops = &_mq_ops; dev->tag_set.nr_hw_queues = 1; dev->tag_set.queue_depth = 128; dev->tag_set.numa_node = NUMA_NO_NODE; dev->tag_set.cmd_size = sizeof(sblkdev_cmd_t); dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE; dev->tag_set.driver_data = dev; ret = blk_mq_alloc_tag_set(&dev->tag_set); if (ret) { printk(KERN_WARNING "sblkdev: unable to allocate tag set\n"); break; } } {//configure queue struct request_queue *queue = blk_mq_init_queue(&dev->tag_set); if (IS_ERR(queue)) { ret = PTR_ERR(queue); printk(KERN_WARNING "sblkdev: Failed to allocate queue\n"); break; } dev->queue = queue; } #endif dev->queue->queuedata = dev; {// configure disk struct gendisk *disk = alloc_disk(1); //only one partition if (disk == NULL) { printk(KERN_WARNING "sblkdev: Failed to allocate disk\n"); ret = -ENOMEM; break; } disk->flags |= GENHD_FL_NO_PART_SCAN; //only one partition //disk->flags |= GENHD_FL_EXT_DEVT; disk->flags |= GENHD_FL_REMOVABLE; disk->major = _sblkdev_major; disk->first_minor = 0; disk->fops = &_fops; disk->private_data = dev; disk->queue = dev->queue; sprintf(disk->disk_name, "sblkdev%d", 0); set_capacity(disk, dev->capacity); dev->disk = disk; add_disk(disk); } printk(KERN_WARNING "sblkdev: simple block device was created\n"); }while(false); if (ret){ sblkdev_remove_device(); printk(KERN_WARNING "sblkdev: Failed add block device\n"); } return ret; }
æ§é ã«ã¡ã¢ãªãå²ãåœãŠãããŒã¿ãä¿åããããã®ãããã¡ãå²ãåœãŠãŸãã ããã§ã¯ç¹å¥ãªããšã¯äœããããŸããã
次ã«ã1ã€ã®é¢æ°blk_mq_init_sq_queueïŒïŒãŸãã¯äžåºŠã«2ã€ã®é¢æ°blk_mq_alloc_tag_setïŒïŒ+ blk_mq_init_queueïŒïŒã§èŠæ±åŠçãã¥ãŒãåæåããŸãã
ãšããã§ãblk_mq_init_sq_queueïŒïŒé¢æ°ã®ãœãŒã¹ã³ãŒããèŠããšãããã¯4.20ã«ãŒãã«ã«ç»å Žããblk_mq_alloc_tag_setïŒïŒããã³blk_mq_init_queueïŒïŒé¢æ°ã®åãªãã©ãããŒã§ããããšãããããŸãã ããã«ããã¥ãŒã®å€ãã®ãã©ã¡ãŒã¿ãŒãé衚瀺ã«ããŸãããã¯ããã«ç°¡åã«èŠããŸãã ã©ã¡ãã®ãªãã·ã§ã³ãåªããŠããããéžæããå¿ èŠããããŸãããç§ã¯ããæ瀺çãªãªãã·ã§ã³ã奜ã¿ãŸãã
ãã®ã³ãŒãã®ããŒã¯ãã°ããŒãã«å€æ°_mq_opsã§ãã
static struct blk_mq_ops _mq_ops = { .queue_rq = queue_rq, };
ããã¯ããªã¯ãšã¹ãåŠçãæäŸããé¢æ°ãé 眮ãããå Žæã§ãããããã«ã€ããŠã¯å°ãåŸã§èª¬æããŸãã äž»ãªããšã¯ããªã¯ãšã¹ããã³ãã©ãžã®ãšã³ããªãã€ã³ããæå®ããããšã§ãã
ãã¥ãŒãäœæããã®ã§ããã£ã¹ã¯ã®ã€ã³ã¹ã¿ã³ã¹ãäœæã§ããŸãã
倧ããªå€æŽã¯ãããŸããã ãã£ã¹ã¯ãå²ãåœãŠããããã©ã¡ãŒã¿ãŒãèšå®ããããã£ã¹ã¯ãã·ã¹ãã ã«è¿œå ãããŸãã disk-> flagsãã©ã¡ãŒã¿ã«ã€ããŠèª¬æããããšæããŸãã ããã«ãããã·ã¹ãã ã«ãªã ãŒããã«ãã©ã€ãããŸãã¯ãããšãã°ãããŒãã£ã·ã§ã³ãå«ãŸããŠãããããããæ¢ãå¿ èŠããªãããšãã·ã¹ãã ã«äŒããããšãã§ããŸãã
ãã£ã¹ã¯ç®¡ççšã®_fopsæ§é ããããŸãã
static const struct block_device_operations _fops = { .owner = THIS_MODULE, .open = _open, .release = _release, .ioctl = _ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = _compat_ioctl, #endif };
åçŽãªãããã¯ããã€ã¹ã¢ãžã¥ãŒã«ã®ãšã³ããªãã€ã³ã_openãš_releaseã¯ããŸã ããŸãèå³æ·±ããã®ã§ã¯ãããŸããã ã¢ãããã¯ã€ã³ã¯ãªã¡ã³ãããã³ãã¯ãªã¡ã³ãã«ãŠã³ã¿ãŒã«å ããŠãäœããããŸããã ãŸãã64ãããã«ãŒãã«ãš32ããããŠãŒã¶ãŒç©ºéç°å¢ãåããã·ã¹ãã ã®ããŒãžã§ã³ã¯ãç§ã«ã¯ææã§ã¯ãªãããã«æããã®ã§ãcompat_ioctlãå®è£ ããã«æ®ããŸããã
ãã ãã_ioctlã䜿çšãããšããã®ãã©ã€ãã«å¯Ÿããã·ã¹ãã èŠæ±ãåŠçã§ããŸãã ãã£ã¹ã¯ã衚瀺ããããšãã·ã¹ãã ã¯ããã«ã€ããŠããã«åŠç¿ããããšããŸãã èªåã®è£éã§ãããã€ãã®ã¯ãšãªã«çããããšãã§ããŸãïŒããšãã°ãæ°ããCDã®ãµãããããªã©ïŒãããããäžè¬çãªã«ãŒã«ã¯æ¬¡ã®ãšããã§ããèå³ã®ãªãã¯ãšãªã«çããããªãå Žåã¯ããšã©ãŒã³ãŒã-ENOTTYãè¿ãã ãã§ãã ãšããã§ãå¿ èŠã«å¿ããŠããã®ç¹å®ã®ãã©ã€ãã«é¢ãããªã¯ãšã¹ããã³ãã©ãè¿œå ã§ããŸãã
ãã®ãããããã€ã¹ãè¿œå ããŸãã-ãªãœãŒã¹ã®ãªãªãŒã¹ã«æ³šæããå¿ èŠããããŸãã ãã³ã¯
static void sblkdev_remove_device(void) { sblkdev_device_t* dev = _sblkdev_device; if (dev){ if (dev->disk) del_gendisk(dev->disk); if (dev->queue) { blk_cleanup_queue(dev->queue); dev->queue = NULL; } if (dev->tag_set.tags) blk_mq_free_tag_set(&dev->tag_set); if (dev->disk) { put_disk(dev->disk); dev->disk = NULL; } sblkdev_free_buffer(dev); kfree(dev); _sblkdev_device = NULL; printk(KERN_WARNING "sblkdev: simple block device was removed\n"); } }
ååãšããŠããã¹ãŠãæããã§ããã·ã¹ãã ãããã£ã¹ã¯ãªããžã§ã¯ããåé€ãããã¥ãŒã解æŸããŸãããã®åŸããããã¡ãŒïŒããŒã¿é åïŒã解æŸããŸãã
ãããŠä»ãæãéèŠãªããšã¯queue_rqïŒïŒé¢æ°ã§ã®ã¯ãšãªåŠçã§ãã
static blk_status_t queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data* bd) { blk_status_t status = BLK_STS_OK; struct request *rq = bd->rq; blk_mq_start_request(rq); //we cannot use any locks that make the thread sleep { unsigned int nr_bytes = 0; if (do_simple_request(rq, &nr_bytes) != SUCCESS) status = BLK_STS_IOERR; printk(KERN_WARNING "sblkdev: request process %d bytes\n", nr_bytes); #if 0 //simply and can be called from proprietary module blk_mq_end_request(rq, status); #else //can set real processed bytes count if (blk_update_request(rq, status, nr_bytes)) //GPL-only symbol BUG(); __blk_mq_end_request(rq, status); #endif } return BLK_STS_OK;//always return ok }
ãŸãããã©ã¡ãŒã¿ãŒãæ€èšããŸãã æåã¯struct blk_mq_hw_ctx * hctx-ããŒããŠã§ã¢ãã¥ãŒã®ç¶æ ã§ãã ç§ãã¡ã®ã±ãŒã¹ã§ã¯ãããŒããŠã§ã¢ãã¥ãŒããªãããã䜿çšãããŸããã
2çªç®ã®ãã©ã¡ãŒã¿ãŒã¯const struct blk_mq_queue_data * bdã§ããéåžžã«ç°¡æœãªæ§é ã®ãã©ã¡ãŒã¿ãŒã§ãããã®ãã©ã¡ãŒã¿ãŒå šäœã泚æããŠè¡šç€ºããããšãæããŸããã
struct blk_mq_queue_data { struct request *rq; bool last; };
æ¬è³ªçã«ã¯ãããã¯å¹Žä»£èšè elixir.bootlin.comããã¯ãèŠããŠããªãæããç§ãã¡ã«å±ããåããªã¯ãšã¹ãã§ããããšãå€æããŸããã ãã®ããããªã¯ãšã¹ããåãåã£ãŠåŠçãéå§ããããã«ã€ããŠblk_mq_start_requestïŒïŒãåŒã³åºããŠã«ãŒãã«ã«éç¥ããŸãã ãªã¯ãšã¹ãã®åŠçãå®äºããããblk_mq_end_requestïŒïŒé¢æ°ãåŒã³åºããŠãããã«ãŒãã«ã«éç¥ããŸãã
ã¡ãã£ãšãã泚æç¹ããããŸãïŒblk_mq_end_requestïŒïŒé¢æ°ã¯ãå®éã«ã¯blk_update_requestïŒïŒ+ __blk_mq_end_requestïŒïŒãžã®åŒã³åºãã®ã©ãããŒã§ãã blk_mq_end_requestïŒïŒé¢æ°ã䜿çšããå Žåãå®éã«åŠçããããã€ãæ°ãæå®ããããšã¯ã§ããŸããã ãã¹ãŠãåŠçãããŠãããšèããŠããŸãã
代æ¿ãªãã·ã§ã³ã«ã¯å¥ã®æ©èœããããŸãïŒblk_update_requesté¢æ°ã¯GPLå°çšã¢ãžã¥ãŒã«ã«å¯ŸããŠã®ã¿ãšã¯ã¹ããŒããããŸãã ã€ãŸããç¬èªã®ã«ãŒãã«ã¢ãžã¥ãŒã«ãäœæããå ŽåïŒPMããã®åä»ãªãã¹ããããªããæãããã«ããïŒãblk_update_requestïŒïŒã䜿çšããããšã¯ã§ããŸããã ãããã£ãŠãéžæã¯ããªã次第ã§ãã
ãã€ãããªã¯ãšã¹ããããããã¡ãžããŸãã¯ãã®éã«çŽæ¥ã·ããããŠãdo_simple_requestïŒïŒé¢æ°ãäœæããŸããã
static int do_simple_request(struct request *rq, unsigned int *nr_bytes) { int ret = SUCCESS; struct bio_vec bvec; struct req_iterator iter; sblkdev_device_t *dev = rq->q->queuedata; loff_t pos = blk_rq_pos(rq) << SECTOR_SHIFT; loff_t dev_size = (loff_t)(dev->capacity << SECTOR_SHIFT); printk(KERN_WARNING "sblkdev: request start from sector %ld \n", blk_rq_pos(rq)); rq_for_each_segment(bvec, rq, iter) { unsigned long b_len = bvec.bv_len; void* b_buf = page_address(bvec.bv_page) + bvec.bv_offset; if ((pos + b_len) > dev_size) b_len = (unsigned long)(dev_size - pos); if (rq_data_dir(rq))//WRITE memcpy(dev->data + pos, b_buf, b_len); else//READ memcpy(b_buf, dev->data + pos, b_len); pos += b_len; *nr_bytes += b_len; } return ret; }
æ°ããããšã¯äœããããŸãããrq_for_each_segmentã¯ãã¹ãŠã®bioãå埩åŠçãããã¹ãŠbio_vecæ§é ãæã£ãŠããããããªã¯ãšã¹ãããŒã¿ã®ããããŒãžã«ã¢ã¯ã»ã¹ã§ããŸãã
ããªãã®å°è±¡ã¯ïŒ ãã¹ãŠãã·ã³ãã«ã«èŠããïŒ äžè¬çãªãªã¯ãšã¹ãåŠçã¯ããªã¯ãšã¹ãããŒãžãšå éšãããã¡éã§ããŒã¿ãã³ããŒããã ãã§ãã åçŽãªãããã¯ããã€ã¹ãã©ã€ããŒã«ãµããããã§ããããïŒ
ããããåé¡ããããŸãïŒ ããã¯å®éã®äœ¿çšã®ããã§ã¯ãããŸããïŒ
åé¡ã®æ¬è³ªã¯ããªã¹ãããã®èŠæ±ãåŠçããã«ãŒãã§queue_rqïŒïŒèŠæ±åŠçé¢æ°ãåŒã³åºãããããšã§ãã ã¹ãã³ãŸãã¯RCUã§ãã®ãªã¹ãã®ã©ã®ããã¯ã䜿çšãããŠãããããããŸããïŒåãã€ããŸãã-誰ãç¥ã£ãŠããŸãããç§ãä¿®æ£ããŸãïŒããããšãã°ããªã¯ãšã¹ãåŠçæ©èœã§ãã¥ãŒããã¯ã¹ã䜿çšããããšãããšããããã°ã«ãŒãã«ã¯èªããŸãããã§ã¯äžå¯èœã§ãã ã€ãŸããããã»ã¹ãã¹ã¿ã³ãã€ç¶æ ã«ç§»è¡ã§ããªããããåŸæ¥ã®åæããŒã«ãŸãã¯ä»®æ³é£ç¶ã¡ã¢ãªïŒvmallocã䜿çšããŠå²ãåœãŠãããæé»çã«ã¹ã¯ããã«é¥ãå¯èœæ§ãããã¡ã¢ãªïŒã䜿çšããããšã¯äžå¯èœã§ãã
ãããã£ãŠã.. \ linux \ drivers \ block \ brd.cã§å®è£ ãããSpinãŸãã¯RCUã®ããã¯ãšããŒãžã®é åã®åœ¢åŒã®ãããã¡ãŒããŸãã¯ããªãŒããŸãã¯..ã§å®è£ ãããå¥ã®ã¹ã¬ããã§ã®é 延åŠçã®ãããã\ linux \ drivers \ block \ loop.c
ã¢ãžã¥ãŒã«ãçµã¿ç«ãŠãæ¹æ³ãã·ã¹ãã ã«ããŒãããæ¹æ³ãã¢ã³ããŒãããæ¹æ³ã説æããå¿ èŠã¯ãªããšæããŸãã ãã®é¢ã«æ°è£œåã¯ãããŸããããã®ããã«æè¬ããŸã:)ã ãã誰ãããããè©ŠããŠã¿ãããšæããªããç§ã¯ãããç解ããããšã確èªããŸãã ãæ°ã«å ¥ãã®ã©ãããããã§ããã«ãããªãã§ãã ããïŒ virtualochkaãäžããããå°ãªããšãããŒã«ãããã¯ã¢ããããŸãã
ã¡ãªã¿ã«ãVeeam Backup for Linux 3.0.1.1046ã¯ãã§ã«å©çšå¯èœã§ãã ã«ãŒãã«5.0以éã§VAL 3.0.1.1046ãå®è¡ããªãã§ãã ããã veeamsnapã¯ã¢ã»ã³ãã«ãããŸããã ãŸããããã€ãã®ãã«ããã¥ãŒã®æè¡é©æ°ã¯ãŸã ãã¹ã段éã«ãããŸãã