ubd_kern.c
来自「linux 内核源代码」· C语言 代码 · 共 1,485 行 · 第 1/3 页
C
1,485 行
ubd_end_request(req, 0, 0); return; } ubd_end_request(req, bytes, 1);}static LIST_HEAD(restart);/* XXX - move this inside ubd_intr. *//* Called without dev->lock held, and only in interrupt context. */static void ubd_handler(void){ struct io_thread_req *req; struct request *rq; struct ubd *ubd; struct list_head *list, *next_ele; unsigned long flags; int n; while(1){ n = os_read_file(thread_fd, &req, sizeof(struct io_thread_req *)); if(n != sizeof(req)){ if(n == -EAGAIN) break; printk(KERN_ERR "spurious interrupt in ubd_handler, " "err = %d\n", -n); return; } rq = req->req; rq->nr_sectors -= req->length >> 9; if(rq->nr_sectors == 0) ubd_finish(rq, rq->hard_nr_sectors << 9); kfree(req); } reactivate_fd(thread_fd, UBD_IRQ); list_for_each_safe(list, next_ele, &restart){ ubd = container_of(list, struct ubd, restart); list_del_init(&ubd->restart); spin_lock_irqsave(&ubd->lock, flags); do_ubd_request(ubd->queue); spin_unlock_irqrestore(&ubd->lock, flags); }}static irqreturn_t ubd_intr(int irq, void *dev){ 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 inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out){ char *file; file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file; return os_file_size(file, size_out);}static void ubd_close_dev(struct ubd *ubd_dev){ os_close_file(ubd_dev->fd); if(ubd_dev->cow.file == NULL) return; os_close_file(ubd_dev->cow.fd); vfree(ubd_dev->cow.bitmap); ubd_dev->cow.bitmap = NULL;}static int ubd_open_dev(struct ubd *ubd_dev){ struct openflags flags; char **back_ptr; int err, create_cow, *create_ptr; int fd; ubd_dev->openflags = ubd_dev->boot_openflags; create_cow = 0; create_ptr = (ubd_dev->cow.file != NULL) ? &create_cow : NULL; back_ptr = ubd_dev->no_cow ? NULL : &ubd_dev->cow.file; fd = open_ubd_file(ubd_dev->file, &ubd_dev->openflags, ubd_dev->shared, back_ptr, &ubd_dev->cow.bitmap_offset, &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset, create_ptr); if((fd == -ENOENT) && create_cow){ fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file, ubd_dev->openflags, 1 << 9, PAGE_SIZE, &ubd_dev->cow.bitmap_offset, &ubd_dev->cow.bitmap_len, &ubd_dev->cow.data_offset); if(fd >= 0){ printk(KERN_INFO "Creating \"%s\" as COW file for " "\"%s\"\n", ubd_dev->file, ubd_dev->cow.file); } } if(fd < 0){ printk("Failed to open '%s', errno = %d\n", ubd_dev->file, -fd); return fd; } ubd_dev->fd = fd; if(ubd_dev->cow.file != NULL){ blk_queue_max_sectors(ubd_dev->queue, 8 * sizeof(long)); err = -ENOMEM; ubd_dev->cow.bitmap = vmalloc(ubd_dev->cow.bitmap_len); if(ubd_dev->cow.bitmap == NULL){ printk(KERN_ERR "Failed to vmalloc COW bitmap\n"); goto error; } flush_tlb_kernel_vm(); err = read_cow_bitmap(ubd_dev->fd, ubd_dev->cow.bitmap, ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len); if(err < 0) goto error; flags = ubd_dev->openflags; flags.w = 0; err = open_ubd_file(ubd_dev->cow.file, &flags, ubd_dev->shared, NULL, NULL, NULL, NULL, NULL); if(err < 0) goto error; ubd_dev->cow.fd = err; } return 0; error: os_close_file(ubd_dev->fd); return err;}static void ubd_device_release(struct device *dev){ struct ubd *ubd_dev = dev->driver_data; blk_cleanup_queue(ubd_dev->queue); *ubd_dev = ((struct ubd) DEFAULT_UBD);}static int ubd_disk_register(int major, u64 size, int unit, struct gendisk **disk_out){ struct gendisk *disk; 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); else sprintf(disk->disk_name, "ubd_fake%d", unit); /* sysfs register (not for ide fake devices) */ if (major == MAJOR_NR) { ubd_devs[unit].pdev.id = unit; ubd_devs[unit].pdev.name = DRIVER_NAME; ubd_devs[unit].pdev.dev.release = ubd_device_release; ubd_devs[unit].pdev.dev.driver_data = &ubd_devs[unit]; platform_device_register(&ubd_devs[unit].pdev); disk->driverfs_dev = &ubd_devs[unit].pdev.dev; } disk->private_data = &ubd_devs[unit]; disk->queue = ubd_devs[unit].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, char **error_out){ struct ubd *ubd_dev = &ubd_devs[n]; int err = 0; if(ubd_dev->file == NULL) goto out; err = ubd_file_size(ubd_dev, &ubd_dev->size); if(err < 0){ *error_out = "Couldn't determine size of device's file"; goto out; } ubd_dev->size = ROUND_BLOCK(ubd_dev->size); INIT_LIST_HEAD(&ubd_dev->restart); sg_init_table(ubd_dev->sg, MAX_SG); err = -ENOMEM; ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock); if (ubd_dev->queue == NULL) { *error_out = "Failed to initialize device queue"; goto out; } ubd_dev->queue->queuedata = ubd_dev; blk_queue_max_hw_segments(ubd_dev->queue, MAX_SG); err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]); if(err){ *error_out = "Failed to register device"; goto out_cleanup; } if(fake_major != MAJOR_NR) ubd_disk_register(fake_major, ubd_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: return err;out_cleanup: blk_cleanup_queue(ubd_dev->queue); goto out;}static int ubd_config(char *str, char **error_out){ int n, ret; /* This string is possibly broken up and stored, so it's only * freed if ubd_setup_common fails, or if only general options * were set. */ str = kstrdup(str, GFP_KERNEL); if (str == NULL) { *error_out = "Failed to allocate memory"; return -ENOMEM; } ret = ubd_setup_common(str, &n, error_out); if (ret) goto err_free; if (n == -1) { ret = 0; goto err_free; } mutex_lock(&ubd_lock); ret = ubd_add(n, error_out); if (ret) ubd_devs[n].file = NULL; mutex_unlock(&ubd_lock);out: return ret;err_free: kfree(str); goto out;}static int ubd_get_config(char *name, char *str, int size, char **error_out){ struct ubd *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; } ubd_dev = &ubd_devs[n]; mutex_lock(&ubd_lock); if(ubd_dev->file == NULL){ CONFIG_CHUNK(str, size, len, "", 1); goto out; } CONFIG_CHUNK(str, size, len, ubd_dev->file, 0); if(ubd_dev->cow.file != NULL){ CONFIG_CHUNK(str, size, len, ",", 0); CONFIG_CHUNK(str, size, len, ubd_dev->cow.file, 1); } else CONFIG_CHUNK(str, size, len, "", 1); out: mutex_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, char **error_out){ struct gendisk *disk = ubd_gendisk[n]; struct ubd *ubd_dev; int err = -ENODEV; mutex_lock(&ubd_lock); ubd_dev = &ubd_devs[n]; if(ubd_dev->file == NULL) goto out; /* you cannot remove a open disk */ err = -EBUSY; if(ubd_dev->count > 0) goto out; ubd_gendisk[n] = NULL; if(disk != NULL){ del_gendisk(disk); put_disk(disk); } if(fake_gendisk[n] != NULL){ del_gendisk(fake_gendisk[n]); put_disk(fake_gendisk[n]); fake_gendisk[n] = NULL; } err = 0; platform_device_unregister(&ubd_dev->pdev);out: mutex_unlock(&ubd_lock); return err;}/* All these are called by mconsole in process context and without * ubd-specific locks. The structure itself is const except for .list. */static struct mc_device ubd_mc = { .list = LIST_HEAD_INIT(ubd_mc.list), .name = "ubd", .config = ubd_config, .get_config = ubd_get_config, .id = ubd_id, .remove = ubd_remove,};static int __init ubd_mc_init(void){ mconsole_register_dev(&ubd_mc); return 0;}__initcall(ubd_mc_init);static int __init ubd0_init(void){ struct ubd *ubd_dev = &ubd_devs[0]; mutex_lock(&ubd_lock); if(ubd_dev->file == NULL) ubd_dev->file = "root_fs"; mutex_unlock(&ubd_lock); return 0;}__initcall(ubd0_init);/* Used in ubd_init, which is an initcall */static struct platform_driver ubd_driver = { .driver = { .name = DRIVER_NAME, },};static int __init ubd_init(void){ char *error; int i, err; if (register_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); if (register_blkdev(fake_major, "ubd")) return -1; } platform_driver_register(&ubd_driver); mutex_lock(&ubd_lock); for (i = 0; i < MAX_DEV; i++){ err = ubd_add(i, &error); if(err) printk(KERN_ERR "Failed to initialize ubd device %d :" "%s\n", i, error); } mutex_unlock(&ubd_lock); return 0;}late_initcall(ubd_init);static int __init 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, IRQF_DISABLED, "ubd", ubd_devs); if(err != 0) printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); return 0;}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 *ubd_dev = disk->private_data; int err = 0; if(ubd_dev->count == 0){ err = ubd_open_dev(ubd_dev); if(err){ printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n", disk->disk_name, ubd_dev->file, -err); goto out; } } ubd_dev->count++; set_disk_ro(disk, !ubd_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) && !ubd_dev->openflags.w){ if(--ubd_dev->count == 0) ubd_close_dev(ubd_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 *ubd_dev = disk->private_data; if(--ubd_dev->count == 0)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?