ubd_kern.c

来自「linux 内核源代码」· C语言 代码 · 共 1,485 行 · 第 1/3 页

C
1,485
字号
		ubd_close_dev(ubd_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++){		if(cow_mask != NULL)			ubd_set_bit(i, (unsigned char *) cow_mask);		if(ubd_test_bit(sector + i, (unsigned char *) bitmap))			continue;		update_bitmap = 1;		ubd_set_bit(sector + i, (unsigned char *) bitmap);	}	if(!update_bitmap)		return;	*cow_offset = sector / (sizeof(unsigned long) * 8);	/* This takes care of the case where we're exactly at the end of the	 * device, and *cow_offset + 1 is off the end.  So, just back it up	 * by one word.  Thanks to Lynn Kerby for the fix and James McMechan	 * for the original diagnosis.	 */	if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) /			   sizeof(unsigned long) - 1))		(*cow_offset)--;	bitmap_words[0] = bitmap[*cow_offset];	bitmap_words[1] = bitmap[*cow_offset + 1];	*cow_offset *= sizeof(unsigned long);	*cow_offset += bitmap_offset;}static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,		       __u64 bitmap_offset, __u64 bitmap_len){	__u64 sector = req->offset >> 9;	int i;	if(req->length > (sizeof(req->sector_mask) * 8) << 9)		panic("Operation too long");	if(req->op == UBD_READ) {		for(i = 0; i < req->length >> 9; i++){			if(ubd_test_bit(sector + i, (unsigned char *) bitmap))				ubd_set_bit(i, (unsigned char *)					    &req->sector_mask);		}	}	else cowify_bitmap(req->offset, req->length, &req->sector_mask,			   &req->cow_offset, bitmap, bitmap_offset,			   req->bitmap_words, bitmap_len);}/* Called with dev->lock held */static void prepare_request(struct request *req, struct io_thread_req *io_req,			    unsigned long long offset, int page_offset,			    int len, struct page *page){	struct gendisk *disk = req->rq_disk;	struct ubd *ubd_dev = disk->private_data;	io_req->req = req;	io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :		ubd_dev->fd;	io_req->fds[1] = ubd_dev->fd;	io_req->cow_offset = -1;	io_req->offset = offset;	io_req->length = len;	io_req->error = 0;	io_req->sector_mask = 0;	io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;	io_req->offsets[0] = 0;	io_req->offsets[1] = ubd_dev->cow.data_offset;	io_req->buffer = page_address(page) + page_offset;	io_req->sectorsize = 1 << 9;	if(ubd_dev->cow.file != NULL)		cowify_req(io_req, ubd_dev->cow.bitmap,			   ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);}/* Called with dev->lock held */static void do_ubd_request(struct request_queue *q){	struct io_thread_req *io_req;	struct request *req;	int n, last_sectors;	while(1){		struct ubd *dev = q->queuedata;		if(dev->end_sg == 0){			struct request *req = elv_next_request(q);			if(req == NULL)				return;			dev->request = req;			blkdev_dequeue_request(req);			dev->start_sg = 0;			dev->end_sg = blk_rq_map_sg(q, req, dev->sg);		}		req = dev->request;		last_sectors = 0;		while(dev->start_sg < dev->end_sg){			struct scatterlist *sg = &dev->sg[dev->start_sg];			req->sector += last_sectors;			io_req = kmalloc(sizeof(struct io_thread_req),					 GFP_ATOMIC);			if(io_req == NULL){				if(list_empty(&dev->restart))					list_add(&dev->restart, &restart);				return;			}			prepare_request(req, io_req,					(unsigned long long) req->sector << 9,					sg->offset, sg->length, sg_page(sg));			last_sectors = sg->length >> 9;			n = os_write_file(thread_fd, &io_req,					  sizeof(struct io_thread_req *));			if(n != sizeof(struct io_thread_req *)){				if(n != -EAGAIN)					printk("write to io thread failed, "					       "errno = %d\n", -n);				else if(list_empty(&dev->restart))					list_add(&dev->restart, &restart);				kfree(io_req);				return;			}			dev->start_sg++;		}		dev->end_sg = 0;		dev->request = NULL;	}}static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo){	struct ubd *ubd_dev = bdev->bd_disk->private_data;	geo->heads = 128;	geo->sectors = 32;	geo->cylinders = ubd_dev->size / (128 * 32 * 512);	return 0;}static int ubd_ioctl(struct inode * inode, struct file * file,		     unsigned int cmd, unsigned long arg){	struct ubd *ubd_dev = inode->i_bdev->bd_disk->private_data;	struct hd_driveid ubd_id = {		.cyls		= 0,		.heads		= 128,		.sectors	= 32,	};	switch (cmd) {		struct cdrom_volctrl volume;	case HDIO_GET_IDENTITY:		ubd_id.cyls = ubd_dev->size / (128 * 32 * 512);		if(copy_to_user((char __user *) arg, (char *) &ubd_id,				 sizeof(ubd_id)))			return -EFAULT;		return 0;	case CDROMVOLREAD:		if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))			return -EFAULT;		volume.channel0 = 255;		volume.channel1 = 255;		volume.channel2 = 255;		volume.channel3 = 255;		if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))			return -EFAULT;		return 0;	}	return -EINVAL;}static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow){	struct uml_stat buf1, buf2;	int err;	if(from_cmdline == NULL)		return 0;	if(!strcmp(from_cmdline, from_cow))		return 0;	err = os_stat_file(from_cmdline, &buf1);	if(err < 0){		printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);		return 0;	}	err = os_stat_file(from_cow, &buf2);	if(err < 0){		printk("Couldn't stat '%s', err = %d\n", from_cow, -err);		return 1;	}	if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))		return 0;	printk("Backing file mismatch - \"%s\" requested,\n"	       "\"%s\" specified in COW header of \"%s\"\n",	       from_cmdline, from_cow, cow);	return 1;}static int backing_file_mismatch(char *file, __u64 size, time_t mtime){	unsigned long modtime;	unsigned long long actual;	int err;	err = os_file_modtime(file, &modtime);	if(err < 0){		printk("Failed to get modification time of backing file "		       "\"%s\", err = %d\n", file, -err);		return err;	}	err = os_file_size(file, &actual);	if(err < 0){		printk("Failed to get size of backing file \"%s\", "		       "err = %d\n", file, -err);		return err;	}	if(actual != size){		/*__u64 can be a long on AMD64 and with %lu GCC complains; so		 * the typecast.*/		printk("Size mismatch (%llu vs %llu) of COW header vs backing "		       "file\n", (unsigned long long) size, actual);		return -EINVAL;	}	if(modtime != mtime){		printk("mtime mismatch (%ld vs %ld) of COW header vs backing "		       "file\n", mtime, modtime);		return -EINVAL;	}	return 0;}int read_cow_bitmap(int fd, void *buf, int offset, int len){	int err;	err = os_seek_file(fd, offset);	if(err < 0)		return err;	err = os_read_file(fd, buf, len);	if(err < 0)		return err;	return 0;}int open_ubd_file(char *file, struct openflags *openflags, int shared,		  char **backing_file_out, int *bitmap_offset_out,		  unsigned long *bitmap_len_out, int *data_offset_out,		  int *create_cow_out){	time_t mtime;	unsigned long long size;	__u32 version, align;	char *backing_file;	int fd, err, sectorsize, asked_switch, mode = 0644;	fd = os_open_file(file, *openflags, mode);	if (fd < 0) {		if ((fd == -ENOENT) && (create_cow_out != NULL))			*create_cow_out = 1;		if (!openflags->w ||		    ((fd != -EROFS) && (fd != -EACCES)))			return fd;		openflags->w = 0;		fd = os_open_file(file, *openflags, mode);		if (fd < 0)			return fd;	}	if(shared)		printk("Not locking \"%s\" on the host\n", file);	else {		err = os_lock_file(fd, openflags->w);		if(err < 0){			printk("Failed to lock '%s', err = %d\n", file, -err);			goto out_close;		}	}	/* Successful return case! */	if(backing_file_out == NULL)		return fd;	err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,			      &size, &sectorsize, &align, bitmap_offset_out);	if(err && (*backing_file_out != NULL)){		printk("Failed to read COW header from COW file \"%s\", "		       "errno = %d\n", file, -err);		goto out_close;	}	if(err)		return fd;	asked_switch = path_requires_switch(*backing_file_out, backing_file, file);	/* Allow switching only if no mismatch. */	if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) {		printk("Switching backing file to '%s'\n", *backing_file_out);		err = write_cow_header(file, fd, *backing_file_out,				       sectorsize, align, &size);		if (err) {			printk("Switch failed, errno = %d\n", -err);			goto out_close;		}	} else {		*backing_file_out = backing_file;		err = backing_file_mismatch(*backing_file_out, size, mtime);		if (err)			goto out_close;	}	cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,		  bitmap_len_out, data_offset_out);	return fd; out_close:	os_close_file(fd);	return err;}int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,		    int sectorsize, int alignment, int *bitmap_offset_out,		    unsigned long *bitmap_len_out, int *data_offset_out){	int err, fd;	flags.c = 1;	fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL);	if(fd < 0){		err = fd;		printk("Open of COW file '%s' failed, errno = %d\n", cow_file,		       -err);		goto out;	}	err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,			    bitmap_offset_out, bitmap_len_out,			    data_offset_out);	if(!err)		return fd;	os_close_file(fd); out:	return err;}static int update_bitmap(struct io_thread_req *req){	int n;	if(req->cow_offset == -1)		return 0;	n = os_seek_file(req->fds[1], req->cow_offset);	if(n < 0){		printk("do_io - bitmap lseek failed : err = %d\n", -n);		return 1;	}	n = os_write_file(req->fds[1], &req->bitmap_words,			  sizeof(req->bitmap_words));	if(n != sizeof(req->bitmap_words)){		printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,		       req->fds[1]);		return 1;	}	return 0;}void do_io(struct io_thread_req *req){	char *buf;	unsigned long len;	int n, nsectors, start, end, bit;	int err;	__u64 off;	nsectors = req->length / req->sectorsize;	start = 0;	do {		bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask);		end = start;		while((end < nsectors) &&		      (ubd_test_bit(end, (unsigned char *)				    &req->sector_mask) == bit))			end++;		off = req->offset + req->offsets[bit] +			start * req->sectorsize;		len = (end - start) * req->sectorsize;		buf = &req->buffer[start * req->sectorsize];		err = os_seek_file(req->fds[bit], off);		if(err < 0){			printk("do_io - lseek failed : err = %d\n", -err);			req->error = 1;			return;		}		if(req->op == UBD_READ){			n = 0;			do {				buf = &buf[n];				len -= n;				n = os_read_file(req->fds[bit], buf, len);				if (n < 0) {					printk("do_io - read failed, err = %d "					       "fd = %d\n", -n, req->fds[bit]);					req->error = 1;					return;				}			} while((n < len) && (n != 0));			if (n < len) memset(&buf[n], 0, len - n);		} else {			n = os_write_file(req->fds[bit], buf, len);			if(n != len){				printk("do_io - write failed err = %d "				       "fd = %d\n", -n, req->fds[bit]);				req->error = 1;				return;			}		}		start = end;	} while(start < nsectors);	req->error = update_bitmap(req);}/* Changed in start_io_thread, which is serialized by being called only * from ubd_init, which is an initcall. */int kernel_fd = -1;/* Only changed by the io thread. XXX: currently unused. */static int io_count = 0;int io_thread(void *arg){	struct io_thread_req *req;	int n;	ignore_sigwinch_sig();	while(1){		n = os_read_file(kernel_fd, &req,				 sizeof(struct io_thread_req *));		if(n != sizeof(struct io_thread_req *)){			if(n < 0)				printk("io_thread - read failed, fd = %d, "				       "err = %d\n", kernel_fd, -n);			else {				printk("io_thread - short read, fd = %d, "				       "length = %d\n", kernel_fd, n);			}			continue;		}		io_count++;		do_io(req);		n = os_write_file(kernel_fd, &req,				  sizeof(struct io_thread_req *));		if(n != sizeof(struct io_thread_req *))			printk("io_thread - write failed, fd = %d, err = %d\n",			       kernel_fd, -n);	}	return 0;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?