Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

um: ubd: Add REQ_FLUSH suppport

UML's block device driver does not support write barriers,
to support this this patch adds REQ_FLUSH suppport.
Every time the block layer sends a REQ_FLUSH we fsync() now
our backing file to guarantee data consistency.

Reported-and-tested-by: Richard W.M. Jones <rjones@redhat.com>
Signed-off-by: Richard Weinberger <richard@nod.at>

+50 -1
+40 -1
arch/um/drivers/ubd_kern.c
··· 41 41 #include <os.h> 42 42 #include "cow.h" 43 43 44 - enum ubd_req { UBD_READ, UBD_WRITE }; 44 + enum ubd_req { UBD_READ, UBD_WRITE, UBD_FLUSH }; 45 45 46 46 struct io_thread_req { 47 47 struct request *req; ··· 866 866 goto out; 867 867 } 868 868 ubd_dev->queue->queuedata = ubd_dev; 869 + blk_queue_flush(ubd_dev->queue, REQ_FLUSH); 869 870 870 871 blk_queue_max_segments(ubd_dev->queue, MAX_SG); 871 872 err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]); ··· 1240 1239 } 1241 1240 1242 1241 /* Called with dev->lock held */ 1242 + static void prepare_flush_request(struct request *req, 1243 + struct io_thread_req *io_req) 1244 + { 1245 + struct gendisk *disk = req->rq_disk; 1246 + struct ubd *ubd_dev = disk->private_data; 1247 + 1248 + io_req->req = req; 1249 + io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : 1250 + ubd_dev->fd; 1251 + io_req->op = UBD_FLUSH; 1252 + } 1253 + 1254 + /* Called with dev->lock held */ 1243 1255 static void do_ubd_request(struct request_queue *q) 1244 1256 { 1245 1257 struct io_thread_req *io_req; ··· 1273 1259 } 1274 1260 1275 1261 req = dev->request; 1262 + 1263 + if (req->cmd_flags & REQ_FLUSH) { 1264 + io_req = kmalloc(sizeof(struct io_thread_req), 1265 + GFP_ATOMIC); 1266 + if (io_req == NULL) { 1267 + if (list_empty(&dev->restart)) 1268 + list_add(&dev->restart, &restart); 1269 + return; 1270 + } 1271 + prepare_flush_request(req, io_req); 1272 + os_write_file(thread_fd, &io_req, 1273 + sizeof(struct io_thread_req *)); 1274 + } 1275 + 1276 1276 while(dev->start_sg < dev->end_sg){ 1277 1277 struct scatterlist *sg = &dev->sg[dev->start_sg]; 1278 1278 ··· 1394 1366 int n, nsectors, start, end, bit; 1395 1367 int err; 1396 1368 __u64 off; 1369 + 1370 + if (req->op == UBD_FLUSH) { 1371 + /* fds[0] is always either the rw image or our cow file */ 1372 + n = os_sync_file(req->fds[0]); 1373 + if (n != 0) { 1374 + printk("do_io - sync failed err = %d " 1375 + "fd = %d\n", -n, req->fds[0]); 1376 + req->error = 1; 1377 + } 1378 + return; 1379 + } 1397 1380 1398 1381 nsectors = req->length / req->sectorsize; 1399 1382 start = 0;
+1
arch/um/include/shared/os.h
··· 141 141 extern int os_open_file(const char *file, struct openflags flags, int mode); 142 142 extern int os_read_file(int fd, void *buf, int len); 143 143 extern int os_write_file(int fd, const void *buf, int count); 144 + extern int os_sync_file(int fd); 144 145 extern int os_file_size(const char *file, unsigned long long *size_out); 145 146 extern int os_file_modtime(const char *file, unsigned long *modtime); 146 147 extern int os_pipe(int *fd, int stream, int close_on_exec);
+9
arch/um/os-Linux/file.c
··· 266 266 return n; 267 267 } 268 268 269 + int os_sync_file(int fd) 270 + { 271 + int n = fsync(fd); 272 + 273 + if (n < 0) 274 + return -errno; 275 + return n; 276 + } 277 + 269 278 int os_file_size(const char *file, unsigned long long *size_out) 270 279 { 271 280 struct uml_stat buf;