📄 ubd_kern.c
字号:
* happen on CPU 0. */int intr_count = 0;/* call ubd_finish if you need to serialize */static void __ubd_finish(struct request *req, int error){ int nsect; if(error){ end_request(req, 0); return; } nsect = req->current_nr_sectors; req->sector += nsect; req->buffer += nsect << 9; req->errors = 0; req->nr_sectors -= nsect; req->current_nr_sectors = 0; end_request(req, 1);}static inline void ubd_finish(struct request *req, int error){ spin_lock(&ubd_io_lock); __ubd_finish(req, error); spin_unlock(&ubd_io_lock);}/* Called without ubd_io_lock held */static void ubd_handler(void){ struct io_thread_req req; struct request *rq = elv_next_request(ubd_queue); int n; do_ubd = NULL; intr_count++; n = os_read_file(thread_fd, &req, sizeof(req)); if(n != sizeof(req)){ printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " "err = %d\n", os_getpid(), -n); spin_lock(&ubd_io_lock); end_request(rq, 0); spin_unlock(&ubd_io_lock); return; } ubd_finish(rq, req.error); reactivate_fd(thread_fd, UBD_IRQ); do_ubd_request(ubd_queue);}static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused){ ubd_handler(); return(IRQ_HANDLED);}/* Only changed by ubd_init, which is an initcall. */static int io_pid = -1;void kill_io_thread(void){ if(io_pid != -1) os_kill_process(io_pid, 1);}__uml_exitcall(kill_io_thread);static int ubd_file_size(struct ubd *dev, __u64 *size_out){ char *file; file = dev->cow.file ? dev->cow.file : dev->file; return(os_file_size(file, size_out));}static void ubd_close(struct ubd *dev){ os_close_file(dev->fd); if(dev->cow.file == NULL) return; os_close_file(dev->cow.fd); vfree(dev->cow.bitmap); dev->cow.bitmap = NULL;}static int ubd_open_dev(struct ubd *dev){ struct openflags flags; char **back_ptr; int err, create_cow, *create_ptr; dev->openflags = dev->boot_openflags; create_cow = 0; create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL; back_ptr = dev->no_cow ? NULL : &dev->cow.file; dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr, &dev->cow.bitmap_offset, &dev->cow.bitmap_len, &dev->cow.data_offset, create_ptr); if((dev->fd == -ENOENT) && create_cow){ dev->fd = create_cow_file(dev->file, dev->cow.file, dev->openflags, 1 << 9, PAGE_SIZE, &dev->cow.bitmap_offset, &dev->cow.bitmap_len, &dev->cow.data_offset); if(dev->fd >= 0){ printk(KERN_INFO "Creating \"%s\" as COW file for " "\"%s\"\n", dev->file, dev->cow.file); } } if(dev->fd < 0){ printk("Failed to open '%s', errno = %d\n", dev->file, -dev->fd); return(dev->fd); } if(dev->cow.file != NULL){ err = -ENOMEM; dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len); if(dev->cow.bitmap == NULL){ printk(KERN_ERR "Failed to vmalloc COW bitmap\n"); goto error; } flush_tlb_kernel_vm(); err = read_cow_bitmap(dev->fd, dev->cow.bitmap, dev->cow.bitmap_offset, dev->cow.bitmap_len); if(err < 0) goto error; flags = dev->openflags; flags.w = 0; err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL, NULL, NULL); if(err < 0) goto error; dev->cow.fd = err; } return(0); error: os_close_file(dev->fd); return(err);}static int ubd_new_disk(int major, u64 size, int unit, struct gendisk **disk_out) { struct gendisk *disk; char from[sizeof("ubd/nnnnn\0")], to[sizeof("discnnnnn/disc\0")]; int err; disk = alloc_disk(1 << UBD_SHIFT); if(disk == NULL) return(-ENOMEM); disk->major = major; disk->first_minor = unit << UBD_SHIFT; disk->fops = &ubd_blops; set_capacity(disk, size / 512); if(major == MAJOR_NR){ sprintf(disk->disk_name, "ubd%c", 'a' + unit); sprintf(disk->devfs_name, "ubd/disc%d", unit); sprintf(from, "ubd/%d", unit); sprintf(to, "disc%d/disc", unit); err = devfs_mk_symlink(from, to); if(err) printk("ubd_new_disk failed to make link from %s to " "%s, error = %d\n", from, to, err); } else { sprintf(disk->disk_name, "ubd_fake%d", unit); sprintf(disk->devfs_name, "ubd_fake/disc%d", unit); } /* sysfs register (not for ide fake devices) */ if (major == MAJOR_NR) { ubd_dev[unit].pdev.id = unit; ubd_dev[unit].pdev.name = DRIVER_NAME; platform_device_register(&ubd_dev[unit].pdev); disk->driverfs_dev = &ubd_dev[unit].pdev.dev; } disk->private_data = &ubd_dev[unit]; disk->queue = ubd_queue; add_disk(disk); *disk_out = disk; return 0;}#define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9))static int ubd_add(int n){ struct ubd *dev = &ubd_dev[n]; int err; err = -ENODEV; if(dev->file == NULL) goto out; if (ubd_open_dev(dev)) goto out; err = ubd_file_size(dev, &dev->size); if(err < 0) goto out_close; dev->size = ROUND_BLOCK(dev->size); err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]); if(err) goto out_close; if(fake_major != MAJOR_NR) ubd_new_disk(fake_major, dev->size, n, &fake_gendisk[n]); /* perhaps this should also be under the "if (fake_major)" above */ /* using the fake_disk->disk_name and also the fakehd_set name */ if (fake_ide) make_ide_entries(ubd_gendisk[n]->disk_name); err = 0;out_close: ubd_close(dev);out: return err;}static int ubd_config(char *str){ int n, err; str = uml_strdup(str); if(str == NULL){ printk(KERN_ERR "ubd_config failed to strdup string\n"); return(1); } err = ubd_setup_common(str, &n); if(err){ kfree(str); return(-1); } if(n == -1) return(0); spin_lock(&ubd_lock); err = ubd_add(n); if(err) ubd_dev[n].file = NULL; spin_unlock(&ubd_lock); return(err);}static int ubd_get_config(char *name, char *str, int size, char **error_out){ struct ubd *dev; int n, len = 0; n = parse_unit(&name); if((n >= MAX_DEV) || (n < 0)){ *error_out = "ubd_get_config : device number out of range"; return(-1); } dev = &ubd_dev[n]; spin_lock(&ubd_lock); if(dev->file == NULL){ CONFIG_CHUNK(str, size, len, "", 1); goto out; } CONFIG_CHUNK(str, size, len, dev->file, 0); if(dev->cow.file != NULL){ CONFIG_CHUNK(str, size, len, ",", 0); CONFIG_CHUNK(str, size, len, dev->cow.file, 1); } else CONFIG_CHUNK(str, size, len, "", 1); out: spin_unlock(&ubd_lock); return(len);}static int ubd_id(char **str, int *start_out, int *end_out){ int n; n = parse_unit(str); *start_out = 0; *end_out = MAX_DEV - 1; return n;}static int ubd_remove(int n){ struct ubd *dev; int err = -ENODEV; spin_lock(&ubd_lock); if(ubd_gendisk[n] == NULL) goto out; dev = &ubd_dev[n]; if(dev->file == NULL) goto out; /* you cannot remove a open disk */ err = -EBUSY; if(dev->count > 0) goto out; del_gendisk(ubd_gendisk[n]); put_disk(ubd_gendisk[n]); ubd_gendisk[n] = NULL; if(fake_gendisk[n] != NULL){ del_gendisk(fake_gendisk[n]); put_disk(fake_gendisk[n]); fake_gendisk[n] = NULL; } platform_device_unregister(&dev->pdev); *dev = ((struct ubd) DEFAULT_UBD); err = 0;out: spin_unlock(&ubd_lock); return err;}static struct mc_device ubd_mc = { .name = "ubd", .config = ubd_config, .get_config = ubd_get_config, .id = ubd_id, .remove = ubd_remove,};static int ubd_mc_init(void){ mconsole_register_dev(&ubd_mc); return 0;}__initcall(ubd_mc_init);static struct platform_driver ubd_driver = { .driver = { .name = DRIVER_NAME, },};int ubd_init(void){ int i; devfs_mk_dir("ubd"); if (register_blkdev(MAJOR_NR, "ubd")) return -1; ubd_queue = blk_init_queue(do_ubd_request, &ubd_io_lock); if (!ubd_queue) { unregister_blkdev(MAJOR_NR, "ubd"); return -1; } if (fake_major != MAJOR_NR) { char name[sizeof("ubd_nnn\0")]; snprintf(name, sizeof(name), "ubd_%d", fake_major); devfs_mk_dir(name); if (register_blkdev(fake_major, "ubd")) return -1; } platform_driver_register(&ubd_driver); for (i = 0; i < MAX_DEV; i++) ubd_add(i); return 0;}late_initcall(ubd_init);int ubd_driver_init(void){ unsigned long stack; int err; /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/ if(global_openflags.s){ printk(KERN_INFO "ubd: Synchronous mode\n"); /* Letting ubd=sync be like using ubd#s= instead of ubd#= is * enough. So use anyway the io thread. */ } stack = alloc_stack(0, 0); io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), &thread_fd); if(io_pid < 0){ printk(KERN_ERR "ubd : Failed to start I/O thread (errno = %d) - " "falling back to synchronous I/O\n", -io_pid); io_pid = -1; return(0); } err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, SA_INTERRUPT, "ubd", ubd_dev); if(err != 0) printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); return(err);}device_initcall(ubd_driver_init);static int ubd_open(struct inode *inode, struct file *filp){ struct gendisk *disk = inode->i_bdev->bd_disk; struct ubd *dev = disk->private_data; int err = 0; if(dev->count == 0){ err = ubd_open_dev(dev); if(err){ printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n", disk->disk_name, dev->file, -err); goto out; } } dev->count++; set_disk_ro(disk, !dev->openflags.w); /* This should no more be needed. And it didn't work anyway to exclude * read-write remounting of filesystems.*/ /*if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){ if(--dev->count == 0) ubd_close(dev); err = -EROFS; }*/ out: return(err);}static int ubd_release(struct inode * inode, struct file * file){ struct gendisk *disk = inode->i_bdev->bd_disk; struct ubd *dev = disk->private_data; if(--dev->count == 0) ubd_close(dev); return(0);}static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, __u64 *cow_offset, unsigned long *bitmap, __u64 bitmap_offset, unsigned long *bitmap_words, __u64 bitmap_len){ __u64 sector = io_offset >> 9; int i, update_bitmap = 0; for(i = 0; i < length >> 9; i++){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -