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, §orsize, &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 + -
显示快捷键?