# Start fixing the problems with aligned access to COW files when O_DIRECT # is enabled. Index: linux-2.6.17/arch/um/drivers/ubd_kern.c =================================================================== --- linux-2.6.17.orig/arch/um/drivers/ubd_kern.c 2007-11-19 11:31:55.000000000 -0500 +++ linux-2.6.17/arch/um/drivers/ubd_kern.c 2007-11-19 11:31:59.000000000 -0500 @@ -121,10 +121,10 @@ static struct gendisk *fake_gendisk[MAX_ #ifdef CONFIG_BLK_DEV_UBD_SYNC #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 1, .c = 0, \ - .cl = 1 }) + .cl = 1, .d = 1 }) #else #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0, \ - .cl = 1 }) + .cl = 1, .d = 1 }) #endif static struct openflags global_openflags = OPEN_FLAGS; @@ -149,6 +149,7 @@ struct ubd { int count; int fd; __u64 size; + int io_unit; struct openflags boot_openflags; struct openflags openflags; unsigned shared:1; @@ -176,6 +177,7 @@ struct ubd { .count = 0, \ .fd = -1, \ .size = -1, \ + .io_unit = 1, \ .boot_openflags = OPEN_FLAGS, \ .openflags = OPEN_FLAGS, \ .no_cow = 0, \ @@ -930,6 +932,10 @@ static int ubd_add(int n, char **error_o ubd_dev->queue->queuedata = ubd_dev; blk_queue_max_hw_segments(ubd_dev->queue, MAX_SG); + if(doing_aio()){ + ubd_dev->io_unit = PAGE_SIZE; + blk_queue_hardsect_size(ubd_dev->queue, PAGE_SIZE); + } err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]); if(err){ *error_out = "Failed to register device"; @@ -1468,6 +1474,13 @@ int open_ubd_file(char *file, struct ope if(backing_file_out == NULL) return fd; + err = os_set_fd_odirect(fd, 0); + if(err){ + printk("Failed to disable O_DIRECT on COW file, err = %d\n", + err); + goto out_close; + } + err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, &size, §orsize, &align, bitmap_offset_out); if(err && (*backing_file_out != NULL)){ @@ -1475,9 +1488,21 @@ int open_ubd_file(char *file, struct ope "errno = %d\n", file, -err); goto out_close; } + + + /* XXX Don't know what case this is covering - it short-circuits + * re-enabling O_DIRECT below. + */ if(err) return fd; + err = os_set_fd_odirect(fd, openflags->d); + if(err){ + printk("Failed to maybe enable O_DIRECT on COW file, " + "err = %d\n", err); + goto out_close; + } + asked_switch = path_requires_switch(*backing_file_out, backing_file, file); /* Allow switching only if no mismatch. */ @@ -1569,7 +1594,7 @@ static int do_io(struct io_thread_req *r struct bitmap_io *bitmap_io = NULL; char *buf, *bits; unsigned long len, sector, start, *bitmap = dev->cow.bitmap; - int nsectors, end, bit, err; + int nsectors, end, bit, err, io_bits; __u64 off; if(req->bitmap_start != -1){ @@ -1577,8 +1602,13 @@ static int do_io(struct io_thread_req *r if(IS_ERR(bitmap_io)) return PTR_ERR(bitmap_io); - off = req->bitmap_start / 8; - len = (req->bitmap_end - 8 * off + 8 - 1) / 8; + io_bits = 8 * dev->io_unit; + off = req->bitmap_start / io_bits; + off *= dev->io_unit; + + len = (req->bitmap_end - 8 * off + io_bits - 1) / io_bits; + len *= dev->io_unit; + bits = &((char *) bitmap)[off]; *bitmap_io = ((struct bitmap_io) Index: linux-2.6.17/arch/um/include/os.h =================================================================== --- linux-2.6.17.orig/arch/um/include/os.h 2007-11-19 10:53:25.000000000 -0500 +++ linux-2.6.17/arch/um/include/os.h 2007-11-19 11:31:59.000000000 -0500 @@ -150,6 +150,7 @@ extern int os_ioctl_generic(int fd, unsi extern int os_get_ifname(int fd, char *namebuf); extern int os_set_slip(int fd); extern int os_set_owner(int fd, int pid); +extern int os_set_fd_odirect(int fd, int odirect); extern int os_mode_fd(int fd, int mode); extern int os_seek_file(int fd, unsigned long long offset); Index: linux-2.6.17/arch/um/os-Linux/file.c =================================================================== --- linux-2.6.17.orig/arch/um/os-Linux/file.c 2007-11-19 11:31:53.000000000 -0500 +++ linux-2.6.17/arch/um/os-Linux/file.c 2007-11-19 11:31:59.000000000 -0500 @@ -187,6 +187,27 @@ int os_set_owner(int fd, int pid) return 0; } +extern int os_set_fd_odirect(int fd, int odirect) +{ + int err, flags; + + flags = fcntl(fd, F_GETFL); + if(flags < 0) + return -errno; + + if(((flags & O_DIRECT) != 0) == odirect) + return 0; + + if(odirect) + flags |= O_DIRECT; + else flags &= ~O_DIRECT; + + err = fcntl(fd, F_SETFL, flags); + if(err) + return err; + return 0; +} + int os_mode_fd(int fd, int mode) { int err; @@ -259,6 +280,7 @@ int os_open_file(char *file, struct open if(flags.c) f |= O_CREAT; if(flags.t) f |= O_TRUNC; if(flags.e) f |= O_EXCL; + if(flags.d) f |= O_DIRECT; fd = open64(file, f, mode); if(fd < 0) Index: linux-2.6.17/arch/um/include/aio.h =================================================================== --- linux-2.6.17.orig/arch/um/include/aio.h 2007-11-19 11:25:47.000000000 -0500 +++ linux-2.6.17/arch/um/include/aio.h 2007-11-19 11:31:59.000000000 -0500 @@ -27,6 +27,7 @@ struct aio_context { .driver = aio_driver, \ .next = NULL } +extern int doing_aio(void); extern int submit_aio(struct aio_context *aio); extern int finish_aio(void); Index: linux-2.6.17/arch/um/os-Linux/aio.c =================================================================== --- linux-2.6.17.orig/arch/um/os-Linux/aio.c 2007-11-19 11:30:14.000000000 -0500 +++ linux-2.6.17/arch/um/os-Linux/aio.c 2007-11-19 11:32:27.000000000 -0500 @@ -430,6 +430,11 @@ static int init_aio(void) return 0; } +int doing_aio(void) +{ + return(!aio_24); +} + /* * The reason for the __initcall/__uml_exitcall asymmetry is that init_aio * needs to be called when the kernel is running because it calls run_helper,