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 + -
显示快捷键?