# 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, &sectorsize, &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,