diff options
author | jdike <jdike> | 2003-08-29 16:42:58 +0000 |
---|---|---|
committer | jdike <jdike> | 2003-08-29 16:42:58 +0000 |
commit | 77d2107deb3dcf29d96424a90ff2be6549b2ef37 (patch) | |
tree | cab446208bd197681e17991f974678c74352801d | |
parent | 4600eab05c288be0bd83d11a4b7bc871f903302c (diff) | |
download | uml-history-77d2107deb3dcf29d96424a90ff2be6549b2ef37.tar.gz |
Added V3 COW format support.
-rw-r--r-- | arch/um/drivers/cow.h | 13 | ||||
-rw-r--r-- | arch/um/drivers/cow_kern.c | 12 | ||||
-rw-r--r-- | arch/um/drivers/cow_user.c | 120 | ||||
-rw-r--r-- | arch/um/drivers/ubd_user.c | 99 |
4 files changed, 157 insertions, 87 deletions
diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h index 662ac5c..d875d04 100644 --- a/arch/um/drivers/cow.h +++ b/arch/um/drivers/cow.h @@ -14,21 +14,22 @@ #endif extern int init_cow_file(int fd, char *cow_file, char *backing_file, - int sectorsize, int *bitmap_offset_out, + int sectorsize, int alignment, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out); extern int file_reader(__u64 offset, char *buf, int len, void *arg); extern int read_cow_header(int (*reader)(__u64, char *, int, void *), - void *arg, __u32 *magic_out, + void *arg, __u32 *version_out, char **backing_file_out, time_t *mtime_out, __u64 *size_out, int *sectorsize_out, - int *bitmap_offset_out); + __u32 *align_out, int *bitmap_offset_out); extern int write_cow_header(char *cow_file, int fd, char *backing_file, - int sectorsize, long long *size); + int sectorsize, int alignment, long long *size); -extern void cow_sizes(__u64 size, int sectorsize, int bitmap_offset, - unsigned long *bitmap_len_out, int *data_offset_out); +extern void cow_sizes(int version, __u64 size, int sectorsize, int align, + int bitmap_offset, unsigned long *bitmap_len_out, + int *data_offset_out); #endif diff --git a/arch/um/drivers/cow_kern.c b/arch/um/drivers/cow_kern.c index 4c4d7f8..413fdaf 100644 --- a/arch/um/drivers/cow_kern.c +++ b/arch/um/drivers/cow_kern.c @@ -389,7 +389,7 @@ static int cow_open(struct inode *inode, struct file *filp) mm_segment_t fs; struct cow *dev; __u64 size; - __u32 magic; + __u32 version, align; time_t mtime; char *backing_file; int n, offset, err = 0; @@ -451,17 +451,19 @@ static int cow_open(struct inode *inode, struct file *filp) goto out; } - err = read_cow_header(reader, &dev->cow_dev, &magic, + err = read_cow_header(reader, &dev->cow_dev, &version, &backing_file, &mtime, &size, - &dev->sectorsize, &dev->bitmap_offset); + &dev->sectorsize, &align, + &dev->bitmap_offset); if(err){ printk(KERN_ERR "cow_open - read_cow_header failed, " "err = %d\n", err); goto out; } - cow_sizes(size, dev->sectorsize, dev->bitmap_offset, - &dev->bitmap_len, &dev->data_offset); + cow_sizes(version, size, dev->sectorsize, align, + dev->bitmap_offset, &dev->bitmap_len, + &dev->data_offset); dev->bitmap = (void *) vmalloc(dev->bitmap_len); if(dev->bitmap == NULL){ err = -ENOMEM; diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c index 675a716..3951642 100644 --- a/arch/um/drivers/cow_user.c +++ b/arch/um/drivers/cow_user.c @@ -6,6 +6,7 @@ #include <sys/stat.h> #include <sys/time.h> #include <sys/param.h> +#include <sys/user.h> #include <netinet/in.h> #include "cow.h" @@ -33,22 +34,80 @@ struct cow_header_v2 { int sectorsize; }; +/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in + * case other systems have different values for MAXPATHLEN + */ +#define PATH_LEN_V3 4096 + +/* Changes from V2 - + * PATH_LEN_V3 as described above + * Explicitly specify field bit lengths for systems with different + * lengths for the usual C types. Not sure whether char or + * time_t should be changed, this can be changed later without + * breaking compatibility + * Add alignment field so that different alignments can be used for the + * bitmap and data + * Add cow_format field to allow for the possibility of different ways + * of specifying the COW blocks. For now, the only value is 0, + * for the traditional COW bitmap. + * Move the backing_file field to the end of the header. This allows + * for the possibility of expanding it into the padding required + * by the bitmap alignment. + * The bitmap and data portions of the file will be aligned as specified + * by the alignment field. This is to allow COW files to be + * put on devices with restrictions on access alignments, such as + * /dev/raw, with a 512 byte alignment restriction. This also + * allows the data to be more aligned more strictly than on + * sector boundaries. This is needed for ubd-mmap, which needs + * the data to be page aligned. + * Fixed (finally!) the rounding bug + */ + +struct cow_header_v3 { + __u32 magic; + __u32 version; + time_t mtime; + __u64 size; + __u32 sectorsize; + __u32 alignment; + __u32 cow_format; + char backing_file[PATH_LEN_V3]; +}; + +/* COW format definitions - for now, we have only the usual COW bitmap */ +#define COW_BITMAP 0 + union cow_header { struct cow_header_v1 v1; struct cow_header_v2 v2; + struct cow_header_v3 v3; }; #define COW_MAGIC 0x4f4f4f4d /* MOOO */ -#define COW_VERSION 2 +#define COW_VERSION 3 + +#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len)) +#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align) -void cow_sizes(__u64 size, int sectorsize, int bitmap_offset, - unsigned long *bitmap_len_out, int *data_offset_out) +void cow_sizes(int version, __u64 size, int sectorsize, int align, + int bitmap_offset, unsigned long *bitmap_len_out, + int *data_offset_out) { - *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize); + if(version < 3){ + *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize); + + *data_offset_out = bitmap_offset + *bitmap_len_out; + *data_offset_out = (*data_offset_out + sectorsize - 1) / + sectorsize; + *data_offset_out *= sectorsize; + } + else { + *bitmap_len_out = DIV_ROUND(size, sectorsize); + *bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8); - *data_offset_out = bitmap_offset + *bitmap_len_out; - *data_offset_out = (*data_offset_out + sectorsize - 1) / sectorsize; - *data_offset_out *= sectorsize; + *data_offset_out = bitmap_offset + *bitmap_len_out; + *data_offset_out = ROUND_UP(*data_offset_out, align); + } } static int absolutize(char *to, int size, char *from) @@ -99,9 +158,9 @@ static int absolutize(char *to, int size, char *from) } int write_cow_header(char *cow_file, int fd, char *backing_file, - int sectorsize, long long *size) + int sectorsize, int alignment, long long *size) { - struct cow_header_v2 *header; + struct cow_header_v3 *header; struct stat64 buf; int err; @@ -115,7 +174,7 @@ int write_cow_header(char *cow_file, int fd, char *backing_file, err = -ENOMEM; header = cow_malloc(sizeof(*header)); if(header == NULL){ - cow_printf("Failed to allocate COW V2 header\n"); + cow_printf("Failed to allocate COW V3 header\n"); goto out; } header->magic = htonl(COW_MAGIC); @@ -151,6 +210,8 @@ int write_cow_header(char *cow_file, int fd, char *backing_file, header->mtime = htonl(buf.st_mtime); header->size = htonll(*size); header->sectorsize = htonl(sectorsize); + header->alignment = htonl(alignment); + header->cow_format = COW_BITMAP; err = write(fd, header, sizeof(*header)); if(err != sizeof(*header)){ @@ -172,10 +233,13 @@ int file_reader(__u64 offset, char *buf, int len, void *arg) return(pread(fd, buf, len, offset)); } +/* XXX Need to sanity-check the values read from the header */ + int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, - __u32 *magic_out, char **backing_file_out, + __u32 *version_out, char **backing_file_out, time_t *mtime_out, __u64 *size_out, - int *sectorsize_out, int *bitmap_offset_out) + int *sectorsize_out, __u32 *align_out, + int *bitmap_offset_out) { union cow_header *header; char *file; @@ -204,7 +268,7 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, /* No error printed because the non-COW case comes through here */ else goto out; - *magic_out = COW_MAGIC; + *version_out = version; if(version == 1){ if(n < sizeof(header->v1)){ @@ -216,6 +280,7 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, *size_out = header->v1.size; *sectorsize_out = header->v1.sectorsize; *bitmap_offset_out = sizeof(header->v1); + *align_out = *sectorsize_out; file = header->v1.backing_file; } else if(version == 2){ @@ -228,11 +293,25 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, *size_out = ntohll(header->v2.size); *sectorsize_out = ntohl(header->v2.sectorsize); *bitmap_offset_out = sizeof(header->v2); + *align_out = *sectorsize_out; file = header->v2.backing_file; } + else if(version == 3){ + if(n < sizeof(header->v3)){ + cow_printf("read_cow_header - failed to read V2 " + "header\n"); + goto out; + } + *mtime_out = ntohl(header->v3.mtime); + *size_out = ntohll(header->v3.size); + *sectorsize_out = ntohl(header->v3.sectorsize); + *align_out = ntohl(header->v3.alignment); + *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out); + file = header->v3.backing_file; + } else { cow_printf("read_cow_header - invalid COW version\n"); - goto out; + goto out; } err = -ENOMEM; *backing_file_out = cow_strdup(file); @@ -248,24 +327,25 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, } int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, - int *bitmap_offset_out, unsigned long *bitmap_len_out, - int *data_offset_out) + int alignment, int *bitmap_offset_out, + unsigned long *bitmap_len_out, int *data_offset_out) { __u64 size, offset; char zero = 0; int err; - err = write_cow_header(cow_file, fd, backing_file, sectorsize, &size); + err = write_cow_header(cow_file, fd, backing_file, sectorsize, + alignment, &size); if(err) goto out; - cow_sizes(size, sectorsize, sizeof(struct cow_header_v2), + *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment); + cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out, bitmap_len_out, data_offset_out); - *bitmap_offset_out = sizeof(struct cow_header_v2); offset = *data_offset_out + size - sizeof(zero); err = cow_seek_file(fd, offset); - if(err != 0){ + if(err){ cow_printf("cow bitmap lseek failed : errno = %d\n", errno); goto out; } diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c index ba7d5b5..670f0bd 100644 --- a/arch/um/drivers/ubd_user.c +++ b/arch/um/drivers/ubd_user.c @@ -60,7 +60,6 @@ static int backing_file_mismatch(char *file, __u64 size, time_t mtime) long long actual; int err; - printk("%ld", htonll(size)); if(stat64(file, &buf) < 0){ printk("Failed to stat backing file \"%s\", errno = %d\n", file, errno); @@ -105,8 +104,9 @@ int open_ubd_file(char *file, struct openflags *openflags, { time_t mtime; __u64 size; + __u32 version, align; char *backing_file; - int fd, err, sectorsize, magic, same, mode = 0644; + int fd, err, sectorsize, same, mode = 0644; if((fd = os_open_file(file, *openflags, mode)) < 0){ if((fd == -ENOENT) && (create_cow_out != NULL)) @@ -121,17 +121,17 @@ int open_ubd_file(char *file, struct openflags *openflags, err = os_lock_file(fd, openflags->w); if(err){ printk("Failed to lock '%s', errno = %d\n", file, -err); - goto error; + goto out_close; } if(backing_file_out == NULL) return(fd); - err = read_cow_header(file_reader, &fd, &magic, &backing_file, &mtime, - &size, §orsize, bitmap_offset_out); + 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 error; + goto out_close; } if(err) return(fd); @@ -141,8 +141,8 @@ int open_ubd_file(char *file, struct openflags *openflags, 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, &size); + err = write_cow_header(file, fd, *backing_file_out, + sectorsize, align, &size); if(err){ printk("Switch failed, errno = %d\n", err); return(err); @@ -151,20 +151,20 @@ int open_ubd_file(char *file, struct openflags *openflags, else { *backing_file_out = backing_file; err = backing_file_mismatch(*backing_file_out, size, mtime); - if(err) goto error; + if(err) goto out_close; } - cow_sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out, - data_offset_out); + cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, + bitmap_len_out, data_offset_out); return(fd); - error: + out_close: os_close_file(fd); return(err); } int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, - int sectorsize, int *bitmap_offset_out, + int sectorsize, int alignment, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out) { int err, fd; @@ -178,7 +178,7 @@ int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, goto out; } - err = init_cow_file(fd, cow_file, backing_file, sectorsize, + err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment, bitmap_offset_out, bitmap_len_out, data_offset_out); if(!err) @@ -207,6 +207,28 @@ int write_ubd_fs(int fd, char *buffer, int len) else return(n); } +static int update_bitmap(struct io_thread_req *req) +{ + int n; + + if(req->cow_offset == -1) + return(0); + + if(os_seek_file(req->fds[1], req->cow_offset) != 0){ + printk("do_io - bitmap lseek failed : errno = %d\n", errno); + return(1); + } + + n = write(req->fds[1], &req->bitmap_words, sizeof(req->bitmap_words)); + if(n != sizeof(req->bitmap_words)){ + printk("do_io - bitmap update returned %d : errno = %d " + "fd = %d\n", n, errno, req->fds[1]); + return(1); + } + + return(0); +} + void do_io(struct io_thread_req *req) { char *buf; @@ -214,6 +236,12 @@ void do_io(struct io_thread_req *req) int n, nsectors, start, end, bit; __u64 off; + if(req->op == UBD_MMAP){ + n = *((int *) req->buffer); + req->error = update_bitmap(req); + return; + } + nsectors = req->length / req->sectorsize; start = 0; do { @@ -224,8 +252,6 @@ void do_io(struct io_thread_req *req) &req->sector_mask) == bit)) end++; - if(end != nsectors) - printk("end != nsectors\n"); off = req->offset + req->offsets[bit] + start * req->sectorsize; len = (end - start) * req->sectorsize; @@ -266,24 +292,7 @@ void do_io(struct io_thread_req *req) start = end; } while(start < nsectors); - if(req->cow_offset != -1){ - if(os_seek_file(req->fds[1], req->cow_offset) != 0){ - printk("do_io - bitmap lseek failed : errno = %d\n", - errno); - req->error = 1; - return; - } - n = write(req->fds[1], &req->bitmap_words, - sizeof(req->bitmap_words)); - if(n != sizeof(req->bitmap_words)){ - printk("do_io - bitmap update returned %d : " - "errno = %d fd = %d\n", n, errno, req->fds[1]); - req->error = 1; - return; - } - } - req->error = 0; - return; + req->error = update_bitmap(req); } /* Changed in start_io_thread, which is serialized by being called only @@ -338,28 +347,6 @@ int start_io_thread(unsigned long sp, int *fd_out) return(pid); } -#ifdef notdef -int start_io_thread(unsigned long sp, int *fd_out) -{ - int pid; - - if((kernel_fd = get_pty()) < 0) return(-1); - raw(kernel_fd, 0); - if((*fd_out = open(ptsname(kernel_fd), O_RDWR)) < 0){ - printk("Couldn't open tty for IO\n"); - return(-1); - } - - pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD, - NULL); - if(pid < 0){ - printk("start_io_thread - clone failed : errno = %d\n", errno); - return(-errno); - } - return(pid); -} -#endif - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically |