ubd_kern.c

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

C
1,656
字号
	if(fd > 0){		/* If mmapping is otherwise OK, but the first access to the		 * page is a write, then it's not mapped in yet.  So we have		 * to write the data to disk first, then we can map the disk		 * page in and continue normally from there.		 */		if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer)){			io_req->map_fd = dev->fd;			io_req->map_offset = io_req->offset +				dev->cow.data_offset;			dev->write_maps++;		}		else return(prepare_mmap_request(dev, fd, io_req->offset, req,						 io_req));	}	if(rq_data_dir(req) == READ)		dev->nomap_reads++;	else dev->nomap_writes++;	io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;	io_req->offsets[0] = 0;	io_req->offsets[1] = dev->cow.data_offset;	io_req->buffer = req->buffer;	io_req->sectorsize = 1 << 9;	if(dev->cow.file != NULL)		cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset,			   dev->cow.bitmap_len);	return(0);}/* Called with ubd_io_lock held */static void do_ubd_request(request_queue_t *q){	struct io_thread_req io_req;	struct request *req;	int err, n;	if(thread_fd == -1){		while((req = elv_next_request(q)) != NULL){			err = prepare_request(req, &io_req);			if(!err){				do_io(&io_req);				__ubd_finish(req, io_req.error);			}		}	}	else {		if(do_ubd || (req = elv_next_request(q)) == NULL)			return;		err = prepare_request(req, &io_req);		if(!err){			do_ubd = ubd_handler;			n = os_write_file(thread_fd, (char *) &io_req,					 sizeof(io_req));			if(n != sizeof(io_req))				printk("write to io thread failed, "				       "errno = %d\n", -n);		}	}}static int ubd_ioctl(struct inode * inode, struct file * file,		     unsigned int cmd, unsigned long arg){	struct hd_geometry __user *loc = (struct hd_geometry __user *) arg;	struct ubd *dev = inode->i_bdev->bd_disk->private_data;	struct hd_driveid ubd_id = {		.cyls		= 0,		.heads		= 128,		.sectors	= 32,	};	switch (cmd) {	        struct hd_geometry g;		struct cdrom_volctrl volume;	case HDIO_GETGEO:		if(!loc) return(-EINVAL);		g.heads = 128;		g.sectors = 32;		g.cylinders = dev->size / (128 * 32 * 512);		g.start = get_start_sect(inode->i_bdev);		return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0);	case HDIO_GET_IDENTITY:		ubd_id.cyls = 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 ubd_check_remapped(int fd, unsigned long address, int is_write,			      __u64 offset){	__u64 bitmap_offset;	unsigned long new_bitmap[2];	int i, err, n;	/* If it's not a write access, we can't do anything about it */	if(!is_write)		return(0);	/* We have a write */	for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){		struct ubd *dev = &ubd_dev[i];		if((dev->fd != fd) && (dev->cow.fd != fd))			continue;		/* It's a write to a ubd device */		if(!dev->openflags.w){			/* It's a write access on a read-only device - probably			 * shouldn't happen.  If the kernel is trying to change			 * something with no intention of writing it back out,			 * then this message will clue us in that this needs			 * fixing			 */			printk("Write access to mapped page from readonly ubd "			       "device %d\n", i);			return(0);		}		/* It's a write to a writeable ubd device - it must be COWed		 * because, otherwise, the page would have been mapped in		 * writeable		 */		if(!dev->cow.file)			panic("Write fault on writeable non-COW ubd device %d",			      i);		/* It should also be an access to the backing file since the		 * COW pages should be mapped in read-write		 */		if(fd == dev->fd)			panic("Write fault on a backing page of ubd "			      "device %d\n", i);		/* So, we do the write, copying the backing data to the COW		 * file...		 */		err = os_seek_file(dev->fd, offset + dev->cow.data_offset);		if(err < 0)			panic("Couldn't seek to %lld in COW file of ubd "			      "device %d, err = %d",			      offset + dev->cow.data_offset, i, -err);		n = os_write_file(dev->fd, (void *) address, PAGE_SIZE);		if(n != PAGE_SIZE)			panic("Couldn't copy data to COW file of ubd "			      "device %d, err = %d", i, -n);		/* ... updating the COW bitmap... */		cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset,			      dev->cow.bitmap, dev->cow.bitmap_offset,			      new_bitmap, dev->cow.bitmap_len);		err = os_seek_file(dev->fd, bitmap_offset);		if(err < 0)			panic("Couldn't seek to %lld in COW file of ubd "			      "device %d, err = %d", bitmap_offset, i, -err);		n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap));		if(n != sizeof(new_bitmap))			panic("Couldn't update bitmap  of ubd device %d, "			      "err = %d", i, -n);		/* Maybe we can map the COW page in, and maybe we can't.  If		 * it is a pre-V3 COW file, we can't, since the alignment will		 * be wrong.  If it is a V3 or later COW file which has been		 * moved to a system with a larger page size, then maybe we		 * can't, depending on the exact location of the page.		 */		offset += dev->cow.data_offset;		/* Remove the remapping, putting the original anonymous page		 * back.  If the COW file can be mapped in, that is done.		 * Otherwise, the COW page is read in.		 */		if(!physmem_remove_mapping((void *) address))			panic("Address 0x%lx not remapped by ubd device %d",			      address, i);		if((offset % UBD_MMAP_BLOCK_SIZE) == 0)			physmem_subst_mapping((void *) address, dev->fd,					      offset, 1);		else {			err = os_seek_file(dev->fd, offset);			if(err < 0)				panic("Couldn't seek to %lld in COW file of "				      "ubd device %d, err = %d", offset, i,				      -err);			n = os_read_file(dev->fd, (void *) address, PAGE_SIZE);			if(n != PAGE_SIZE)				panic("Failed to read page from offset %llx of "				      "COW file of ubd device %d, err = %d",				      offset, i, -n);		}		return(1);	}	/* It's not a write on a ubd device */	return(0);}static struct remapper ubd_remapper = {	.list	= LIST_HEAD_INIT(ubd_remapper.list),	.proc	= ubd_check_remapped,};static int ubd_remapper_setup(void){	if(ubd_do_mmap)		register_remapper(&ubd_remapper);	return(0);}__initcall(ubd_remapper_setup);static int same_backing_files(char *from_cmdline, char *from_cow, char *cow){	struct uml_stat buf1, buf2;	int err;	if(from_cmdline == NULL) return(1);	if(!strcmp(from_cmdline, from_cow)) return(1);	err = os_stat_file(from_cmdline, &buf1);	if(err < 0){		printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);		return(1);	}	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(1);	printk("Backing file mismatch - \"%s\" requested,\n"	       "\"%s\" specified in COW header of \"%s\"\n",	       from_cmdline, from_cow, cow);	return(0);}static int backing_file_mismatch(char *file, __u64 size, time_t mtime){	unsigned long modtime;	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,		  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, same, 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);        }	err = os_lock_file(fd, openflags->w);	if(err < 0){		printk("Failed to lock '%s', err = %d\n", file, -err);		goto out_close;	}	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);	if(backing_file_out == NULL) return(fd);	same = same_backing_files(*backing_file_out, backing_file, file);	if(!same && !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);			return(err);		}	}	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, 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;	if(req->op == UBD_MMAP){		/* Touch the page to force the host to do any necessary IO to		 * get it into memory		 */		n = *((volatile int *) req->buffer);		req->error = update_bitmap(req);		return;	}	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 */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(req));		if(n != sizeof(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(req));		if(n != sizeof(req))			printk("io_thread - write failed, fd = %d, err = %d\n",			       kernel_fd, -n);	}}/* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only.  This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-file-style: "linux" * End: */

⌨️ 快捷键说明

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