summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjdike <jdike>2003-08-29 16:42:58 +0000
committerjdike <jdike>2003-08-29 16:42:58 +0000
commit77d2107deb3dcf29d96424a90ff2be6549b2ef37 (patch)
treecab446208bd197681e17991f974678c74352801d
parent4600eab05c288be0bd83d11a4b7bc871f903302c (diff)
downloaduml-history-77d2107deb3dcf29d96424a90ff2be6549b2ef37.tar.gz
Added V3 COW format support.
-rw-r--r--arch/um/drivers/cow.h13
-rw-r--r--arch/um/drivers/cow_kern.c12
-rw-r--r--arch/um/drivers/cow_user.c120
-rw-r--r--arch/um/drivers/ubd_user.c99
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, &sectorsize, bitmap_offset_out);
+ 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 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