diff -Naur -X exclude-files ac_cur/arch/um/drivers/ubd.c ac/arch/um/drivers/ubd.c --- ac_cur/arch/um/drivers/ubd.c Fri Oct 5 14:15:35 2001 +++ ac/arch/um/drivers/ubd.c Fri Oct 5 15:18:23 2001 @@ -16,6 +16,7 @@ #include "linux/ctype.h" #include "linux/capability.h" #include "linux/mm.h" +#include "linux/vmalloc.h" #include "asm/segment.h" #include "asm/uaccess.h" #include "asm/irq.h" @@ -84,7 +85,7 @@ char *file; int fd; unsigned long *bitmap; - int bitmap_len; + int bitmap_offset; int data_offset; }; @@ -105,7 +106,7 @@ file: NULL, \ fd: -1, \ bitmap: NULL, \ - bitmap_len: 0, \ + bitmap_offset: 0, \ data_offset: 0, \ } @@ -473,23 +474,28 @@ static void ubd_close(struct ubd *dev) { close_fd(dev->fd); - if(dev->cow.file != NULL) close_fd(dev->cow.fd); + if(dev->cow.file != NULL) { + close_fd(dev->cow.fd); + vfree(dev->cow.bitmap); + dev->cow.bitmap = NULL; + } } static int ubd_open_dev(struct ubd *dev) { char *backing_file; - int err, len, order, flags, n; + int err, flags, n, bitmap_len; dev->fd = open_ubd_file(dev->file, &dev->openflags, &backing_file, - &dev->cow.bitmap_len, &dev->cow.data_offset); + &dev->cow.bitmap_offset, &bitmap_len, + &dev->cow.data_offset); if((dev->fd == -ENOENT) && (dev->cow.file != NULL)){ printk(KERN_INFO "Creating \"%s\" as COW file for \"%s\"\n", dev->file, dev->cow.file); n = dev - ubd_dev; dev->fd = create_cow_file(dev->file, dev->cow.file, 1 << 9, - &dev->cow.bitmap_len, + &dev->cow.bitmap_offset, &bitmap_len, &dev->cow.data_offset); if(dev->fd < 0){ printk(KERN_ERR "Creation of COW file \"%s\" failed, " @@ -509,22 +515,18 @@ } if(dev->cow.file != NULL){ - len = dev->cow.bitmap_len / PAGE_SIZE; - order = 0; - while(len){ - order++; - len >>= 1; - } err = -ENOMEM; - dev->cow.bitmap = (void *) __get_free_pages(GFP_KERNEL, order); + dev->cow.bitmap = (void *) vmalloc(bitmap_len); + flush_tlb_kernel_vm(); if(dev->cow.bitmap == NULL) goto error; - err = read_cow_bitmap(dev->fd, dev->cow.bitmap, - dev->cow.bitmap_len); + err = read_cow_bitmap(dev->fd, dev->cow.bitmap, + dev->cow.bitmap_offset, bitmap_len); if(err) goto error; flags = O_RDONLY; - err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL); + err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL, + NULL); if(err < 0) goto error; dev->cow.fd = err; } @@ -548,6 +550,9 @@ } if(ubd_dev[n].count == 0){ ubd_dev[n].openflags = ubd_dev[n].boot_openflags; + /* XXX This error is wrong when errno isn't stored in + * ubd_dev[n].fd + */ if(ubd_open_dev(&ubd_dev[n]) < 0){ printk(KERN_ERR "ubd%d: Can't open \"%s\": " "errno = %d\n", n, ubd_dev[n].file, @@ -613,6 +618,7 @@ req->bitmap_start = sector / (sizeof(long) * 8); req->bitmap_end = (sector + i) / (sizeof(long) * 8); req->bitmap_end++; + req->bitmap_offset = dev->cow.bitmap_offset; } } } @@ -654,6 +660,7 @@ req.sectorsize = 1 << 9; req.sector_mask = 0; req.bitmap = ubd_dev[dev].cow.bitmap; + req.bitmap_offset = -1; req.bitmap_start = -1; req.bitmap_end = -1; req.error = 0; diff -Naur -X exclude-files ac_cur/arch/um/drivers/ubd_user.c ac/arch/um/drivers/ubd_user.c --- ac_cur/arch/um/drivers/ubd_user.c Fri Oct 5 14:15:35 2001 +++ ac/arch/um/drivers/ubd_user.c Fri Oct 5 15:18:23 2001 @@ -4,50 +4,158 @@ * Licensed under the GPL */ +#include #include #include #include #include #include +#include #include #include #include #include #include +#include #include "user_util.h" +#include "kern_util.h" #include "user.h" #include "ubd_user.h" +#include +#include +#if __BYTE_ORDER == __BIG_ENDIAN +# define ntohll(x) (x) +# define htonll(x) (x) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +# define ntohll(x) bswap_64(x) +# define htonll(x) bswap_64(x) +#else +#error "__BYTE_ORDER not defined" +#endif + extern void panic(char *fmt, ...); -struct cow_header { +#define PATH_LEN_V1 256 + +struct cow_header_v1 { int magic; int version; - char backing_file[256]; + char backing_file[PATH_LEN_V1]; time_t mtime; __u64 size; int sectorsize; }; -#define COW_MAGIC 0x4f4f4f4d /* mooo */ -#define COW_VERSION 1 +#define PATH_LEN_V2 MAXPATHLEN -static void sizes(__u64 size, int sectorsize, int *bitmap_len_out, - int *data_offset_out) +struct cow_header_v2 { + unsigned long magic; + unsigned long version; + char backing_file[PATH_LEN_V2]; + time_t mtime; + __u64 size; + int sectorsize; +}; + +union cow_header { + struct cow_header_v1 v1; + struct cow_header_v2 v2; +}; + +#define COW_MAGIC 0x4f4f4f4d /* MOOO */ +#define COW_VERSION 2 + +static void sizes(__u64 size, int sectorsize, int bitmap_offset, + int *bitmap_len_out, int *data_offset_out) { *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize); - *data_offset_out = sizeof(struct cow_header) + *bitmap_len_out; + *data_offset_out = bitmap_offset + *bitmap_len_out; *data_offset_out = (*data_offset_out + sectorsize - 1) / sectorsize; *data_offset_out *= sectorsize; } +static int read_cow_header(int fd, int *magic_out, char **backing_file_out, + time_t *mtime_out, __u64 *size_out, + int *sectorsize_out, int *bitmap_offset_out) +{ + union cow_header *header; + char *file; + int err, n; + unsigned long version, magic; + + header = um_kmalloc(sizeof(*header)); + if(header == NULL){ + printk("read_cow_header - Failed to allocate header\n"); + return(-ENOMEM); + } + err = -EINVAL; + n = read(fd, header, sizeof(*header)); + if(n < offsetof(typeof(header->v1), backing_file)){ + printk("read_cow_header - short header\n"); + goto out; + } + + err = 0; + magic = header->v1.magic; + if(magic == COW_MAGIC) { + version = header->v1.version; + } + else if(magic == ntohl(COW_MAGIC)){ + version = ntohl(header->v1.version); + } + else goto out; + + *magic_out = COW_MAGIC; + + err = -EINVAL; + if(version == 1){ + if(n < sizeof(header->v1)){ + printk("read_cow_header - failed to read V1 header\n"); + goto out; + } + *mtime_out = header->v1.mtime; + *size_out = header->v1.size; + *sectorsize_out = header->v1.sectorsize; + *bitmap_offset_out = sizeof(header->v1); + file = header->v1.backing_file; + } + else if(version == 2){ + if(n < sizeof(header->v2)){ + printk("read_cow_header - failed to read V2 header\n"); + goto out; + } + *mtime_out = ntohl(header->v2.mtime); + *size_out = ntohll(header->v2.size); + *sectorsize_out = ntohl(header->v2.sectorsize); + *bitmap_offset_out = sizeof(header->v2); + file = header->v2.backing_file; + } + else { + printk("read_cow_header - invalid COW version\n"); + goto out; + } + err = -ENOMEM; + *backing_file_out = uml_strdup(file); + if(*backing_file_out == NULL){ + printk("read_cow_header - failed to allocate backing file\n"); + goto out; + } + err = 0; + out: + kfree(header); + return(err); +} + int open_ubd_file(char *file, int *openflags, char **backing_file_out, - int *bitmap_len_out, int *data_offset_out) + int *bitmap_offset_out, int *bitmap_len_out, + int *data_offset_out) { - struct cow_header header; struct stat64 buf; - int fd, err, mode = 0644; + time_t mtime; + __u64 size; + int fd, err, sectorsize, magic, mode = 0644; if(backing_file_out != NULL) *backing_file_out = NULL; if((fd = open64(file, *openflags, mode)) < 0){ @@ -58,40 +166,33 @@ if((fd = open64(file, *openflags, mode)) < 0) return(-errno); } if(backing_file_out == NULL) return(fd); - err = -EINVAL; - if(read(fd, &header, sizeof(header)) != sizeof(header)){ - printk("Failed to check COW header in \"%s\", errno = %d\n", - file, errno); - goto error; - } - if(header.magic != COW_MAGIC){ + + err = read_cow_header(fd, &magic, backing_file_out, &mtime, &size, + §orsize, bitmap_offset_out); + if(err) goto error; + + if(magic != COW_MAGIC){ *backing_file_out = NULL; return(fd); } - err = stat64(header.backing_file, &buf); + err = stat64(*backing_file_out, &buf); if(err) goto error; err = -EINVAL; - if(buf.st_size != header.size){ + if(buf.st_size != size){ printk("Size mismatch (%ld vs %ld) of COW header vs backing " - "file\n", buf.st_size, header.size); + "file\n", buf.st_size, size); goto error; } - if(buf.st_mtime != header.mtime){ + if(buf.st_mtime != mtime){ printk("mtime mismatch (%ld vs %ld) of COW header vs backing " - "file\n", buf.st_mtime, header.mtime); + "file\n", buf.st_mtime, mtime); goto error; } - *backing_file_out = um_kmalloc(strlen(header.backing_file) + 1); - if(*backing_file_out == NULL){ - close(fd); - return(-ENOMEM); - } - strcpy(*backing_file_out, header.backing_file); - - sizes(header.size, header.sectorsize, bitmap_len_out, data_offset_out); + sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out, + data_offset_out); return(fd); error: @@ -99,12 +200,12 @@ return(err); } -int read_cow_bitmap(int fd, void *buf, int len) +int read_cow_bitmap(int fd, void *buf, int offset, int len) { int err; - err = lseek64(fd, sizeof(struct cow_header), SEEK_SET); - if(err != sizeof(struct cow_header)) return(-errno); + err = lseek64(fd, offset, SEEK_SET); + if(err != offset) return(-errno); err = read(fd, buf, len); if(err < 0) return(-errno); return(0); @@ -157,56 +258,70 @@ } int create_cow_file(char *cow_file, char *backing_file, int sectorsize, - int *bitmap_len_out, int *data_offset_out) + int *bitmap_offset_out, int *bitmap_len_out, + int *data_offset_out) { - struct cow_header header; + struct cow_header_v2 *header; struct stat64 buf; __u64 blocks; long zero; int err, fd, i, flags; + __u64 size; flags = O_RDWR | O_CREAT; - fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL); + fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL); if(fd < 0) return(fd); - header.magic = COW_MAGIC; - header.version = COW_VERSION; + err = -ENOMEM; + header = um_kmalloc(sizeof(*header)); + if(header == NULL){ + printk("Failed to allocate COW V2 header\n"); + goto out_close; + } + header->magic = htonl(COW_MAGIC); + header->version = htonl(COW_VERSION); err = -EINVAL; - if(strlen(backing_file) > sizeof(header.backing_file) - 1){ + if(strlen(backing_file) > sizeof(header->backing_file) - 1){ printk("Backing file name \"%s\" is too long - names are " "limited to %d characters\n", backing_file, - sizeof(header.backing_file) - 1); - goto error; + sizeof(header->backing_file) - 1); + goto out_free; } - if(absolutize(header.backing_file, sizeof(header.backing_file), + if(absolutize(header->backing_file, sizeof(header->backing_file), backing_file)) - goto error; + goto out_free; - err = stat64(header.backing_file, &buf); - if(err < 0) goto error; + err = stat64(header->backing_file, &buf); + if(err < 0) goto out_free; - header.mtime = buf.st_mtime; - header.size = buf.st_size; - header.sectorsize = sectorsize; + header->mtime = htonl(buf.st_mtime); + header->size = htonll(buf.st_size); + header->sectorsize = htonl(sectorsize); + size = buf.st_size; - err = write(fd, &header, sizeof(header)); - if(err != sizeof(header)) goto error; + err = write(fd, header, sizeof(*header)); + if(err != sizeof(*header)) goto out_free; - blocks = (header.size + sectorsize - 1) / sectorsize; + blocks = (size + sectorsize - 1) / sectorsize; blocks = (blocks + sizeof(long) * 8 - 1) / (sizeof(long) * 8); zero = 0; for(i = 0; i < blocks; i++){ err = write(fd, &zero, sizeof(zero)); - if(err != sizeof(zero)) goto error; + if(err != sizeof(zero)) goto out_free; } - sizes(header.size, header.sectorsize, bitmap_len_out, data_offset_out); + sizes(size, sectorsize, sizeof(struct cow_header_v2), + bitmap_len_out, data_offset_out); + *bitmap_offset_out = sizeof(struct cow_header_v2); + kfree(header); return(fd); - error: + out_free: + kfree(header); + out_close: close(fd); return(err); } @@ -229,13 +344,14 @@ return(S_ISDIR(buf.st_mode)); } -unsigned long last_offset = -1; +__u64 last_offset = -1; int do_io(struct io_thread_req *req) { char *buf; unsigned long len; - int n, off, nsectors, start, end, bit; + int n, nsectors, start, end, bit; + __u64 off; nsectors = req->length / req->sectorsize; start = 0; @@ -283,7 +399,7 @@ if(req->bitmap_start != -1){ off = req->bitmap_start * sizeof(req->bitmap[0]); - off += sizeof(struct cow_header); + off += req->bitmap_offset; if(lseek64(req->fds[1], off, SEEK_SET) != off){ printk("do_io - bitmap lseek failed : errno = %d\n", errno); @@ -333,7 +449,7 @@ if((kernel_fds[0] = get_pty()) < 0) return(-1); raw(kernel_fds[0], 1); if((fds_out[0] = open(ptsname(kernel_fds[0]), O_RDWR)) < 0){ - printk("Couldn't open tty for slip line\n"); + printk("Couldn't open tty for IO\n"); return(-1); } fds_out[1] = fds_out[0]; diff -Naur -X exclude-files ac_cur/arch/um/include/ubd_user.h ac/arch/um/include/ubd_user.h --- ac_cur/arch/um/include/ubd_user.h Fri Oct 5 14:15:35 2001 +++ ac/arch/um/include/ubd_user.h Fri Oct 5 15:18:23 2001 @@ -18,16 +18,19 @@ int sectorsize; unsigned long sector_mask; unsigned long *bitmap; + unsigned long bitmap_offset; unsigned long bitmap_start; unsigned long bitmap_end; int error; }; extern int open_ubd_file(char *file, int *openflags, char **backing_file_out, - int *bitmap_len_out, int *data_offset_out); + int *bitmap_offset_out, int *bitmap_len_out, + int *data_offset_out); extern int create_cow_file(char *cow_file, char *backing_file, int sectorsize, - int *bitmap_len_out, int *data_offset_out); -extern int read_cow_bitmap(int fd, void *buf, int len); + int *bitmap_offset_out, int *bitmap_len_out, + int *data_offset_out); +extern int read_cow_bitmap(int fd, void *buf, int offset, int len); extern int read_ubd_fs(int fd, void *buffer, int len); extern int write_ubd_fs(int fd, char *buffer, int len); extern int start_io_thread(unsigned long sp, int *fds_out);