diff options
-rw-r--r-- | arch/um/drivers/ubd_kern.c | 385 |
1 files changed, 190 insertions, 195 deletions
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index be3a2797dac4..5e45e39a8a8d 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -72,18 +72,6 @@ struct io_thread_req { | |||
72 | int error; | 72 | int error; |
73 | }; | 73 | }; |
74 | 74 | ||
75 | extern int open_ubd_file(char *file, struct openflags *openflags, int shared, | ||
76 | char **backing_file_out, int *bitmap_offset_out, | ||
77 | unsigned long *bitmap_len_out, int *data_offset_out, | ||
78 | int *create_cow_out); | ||
79 | extern int create_cow_file(char *cow_file, char *backing_file, | ||
80 | struct openflags flags, int sectorsize, | ||
81 | int alignment, int *bitmap_offset_out, | ||
82 | unsigned long *bitmap_len_out, | ||
83 | int *data_offset_out); | ||
84 | extern int read_cow_bitmap(int fd, void *buf, int offset, int len); | ||
85 | extern void do_io(struct io_thread_req *req); | ||
86 | |||
87 | static inline int ubd_test_bit(__u64 bit, unsigned char *data) | 75 | static inline int ubd_test_bit(__u64 bit, unsigned char *data) |
88 | { | 76 | { |
89 | __u64 n; | 77 | __u64 n; |
@@ -200,7 +188,7 @@ struct ubd { | |||
200 | } | 188 | } |
201 | 189 | ||
202 | /* Protected by ubd_lock */ | 190 | /* Protected by ubd_lock */ |
203 | struct ubd ubd_devs[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; | 191 | static struct ubd ubd_devs[MAX_DEV] = { [0 ... MAX_DEV - 1] = DEFAULT_UBD }; |
204 | 192 | ||
205 | /* Only changed by fake_ide_setup which is a setup */ | 193 | /* Only changed by fake_ide_setup which is a setup */ |
206 | static int fake_ide = 0; | 194 | static int fake_ide = 0; |
@@ -463,7 +451,7 @@ __uml_help(udb_setup, | |||
463 | static void do_ubd_request(struct request_queue * q); | 451 | static void do_ubd_request(struct request_queue * q); |
464 | 452 | ||
465 | /* Only changed by ubd_init, which is an initcall. */ | 453 | /* Only changed by ubd_init, which is an initcall. */ |
466 | int thread_fd = -1; | 454 | static int thread_fd = -1; |
467 | 455 | ||
468 | static void ubd_end_request(struct request *req, int bytes, int error) | 456 | static void ubd_end_request(struct request *req, int bytes, int error) |
469 | { | 457 | { |
@@ -531,7 +519,7 @@ static irqreturn_t ubd_intr(int irq, void *dev) | |||
531 | /* Only changed by ubd_init, which is an initcall. */ | 519 | /* Only changed by ubd_init, which is an initcall. */ |
532 | static int io_pid = -1; | 520 | static int io_pid = -1; |
533 | 521 | ||
534 | void kill_io_thread(void) | 522 | static void kill_io_thread(void) |
535 | { | 523 | { |
536 | if(io_pid != -1) | 524 | if(io_pid != -1) |
537 | os_kill_process(io_pid, 1); | 525 | os_kill_process(io_pid, 1); |
@@ -547,6 +535,192 @@ static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out) | |||
547 | return os_file_size(file, size_out); | 535 | return os_file_size(file, size_out); |
548 | } | 536 | } |
549 | 537 | ||
538 | static int read_cow_bitmap(int fd, void *buf, int offset, int len) | ||
539 | { | ||
540 | int err; | ||
541 | |||
542 | err = os_seek_file(fd, offset); | ||
543 | if (err < 0) | ||
544 | return err; | ||
545 | |||
546 | err = os_read_file(fd, buf, len); | ||
547 | if (err < 0) | ||
548 | return err; | ||
549 | |||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | static int backing_file_mismatch(char *file, __u64 size, time_t mtime) | ||
554 | { | ||
555 | unsigned long modtime; | ||
556 | unsigned long long actual; | ||
557 | int err; | ||
558 | |||
559 | err = os_file_modtime(file, &modtime); | ||
560 | if (err < 0) { | ||
561 | printk(KERN_ERR "Failed to get modification time of backing " | ||
562 | "file \"%s\", err = %d\n", file, -err); | ||
563 | return err; | ||
564 | } | ||
565 | |||
566 | err = os_file_size(file, &actual); | ||
567 | if (err < 0) { | ||
568 | printk(KERN_ERR "Failed to get size of backing file \"%s\", " | ||
569 | "err = %d\n", file, -err); | ||
570 | return err; | ||
571 | } | ||
572 | |||
573 | if (actual != size) { | ||
574 | /*__u64 can be a long on AMD64 and with %lu GCC complains; so | ||
575 | * the typecast.*/ | ||
576 | printk(KERN_ERR "Size mismatch (%llu vs %llu) of COW header " | ||
577 | "vs backing file\n", (unsigned long long) size, actual); | ||
578 | return -EINVAL; | ||
579 | } | ||
580 | if (modtime != mtime) { | ||
581 | printk(KERN_ERR "mtime mismatch (%ld vs %ld) of COW header vs " | ||
582 | "backing file\n", mtime, modtime); | ||
583 | return -EINVAL; | ||
584 | } | ||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow) | ||
589 | { | ||
590 | struct uml_stat buf1, buf2; | ||
591 | int err; | ||
592 | |||
593 | if (from_cmdline == NULL) | ||
594 | return 0; | ||
595 | if (!strcmp(from_cmdline, from_cow)) | ||
596 | return 0; | ||
597 | |||
598 | err = os_stat_file(from_cmdline, &buf1); | ||
599 | if (err < 0) { | ||
600 | printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cmdline, | ||
601 | -err); | ||
602 | return 0; | ||
603 | } | ||
604 | err = os_stat_file(from_cow, &buf2); | ||
605 | if (err < 0) { | ||
606 | printk(KERN_ERR "Couldn't stat '%s', err = %d\n", from_cow, | ||
607 | -err); | ||
608 | return 1; | ||
609 | } | ||
610 | if ((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) | ||
611 | return 0; | ||
612 | |||
613 | printk(KERN_ERR "Backing file mismatch - \"%s\" requested, " | ||
614 | "\"%s\" specified in COW header of \"%s\"\n", | ||
615 | from_cmdline, from_cow, cow); | ||
616 | return 1; | ||
617 | } | ||
618 | |||
619 | static int open_ubd_file(char *file, struct openflags *openflags, int shared, | ||
620 | char **backing_file_out, int *bitmap_offset_out, | ||
621 | unsigned long *bitmap_len_out, int *data_offset_out, | ||
622 | int *create_cow_out) | ||
623 | { | ||
624 | time_t mtime; | ||
625 | unsigned long long size; | ||
626 | __u32 version, align; | ||
627 | char *backing_file; | ||
628 | int fd, err, sectorsize, asked_switch, mode = 0644; | ||
629 | |||
630 | fd = os_open_file(file, *openflags, mode); | ||
631 | if (fd < 0) { | ||
632 | if ((fd == -ENOENT) && (create_cow_out != NULL)) | ||
633 | *create_cow_out = 1; | ||
634 | if (!openflags->w || | ||
635 | ((fd != -EROFS) && (fd != -EACCES))) | ||
636 | return fd; | ||
637 | openflags->w = 0; | ||
638 | fd = os_open_file(file, *openflags, mode); | ||
639 | if (fd < 0) | ||
640 | return fd; | ||
641 | } | ||
642 | |||
643 | if (shared) | ||
644 | printk(KERN_INFO "Not locking \"%s\" on the host\n", file); | ||
645 | else { | ||
646 | err = os_lock_file(fd, openflags->w); | ||
647 | if (err < 0) { | ||
648 | printk(KERN_ERR "Failed to lock '%s', err = %d\n", | ||
649 | file, -err); | ||
650 | goto out_close; | ||
651 | } | ||
652 | } | ||
653 | |||
654 | /* Successful return case! */ | ||
655 | if (backing_file_out == NULL) | ||
656 | return fd; | ||
657 | |||
658 | err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, | ||
659 | &size, §orsize, &align, bitmap_offset_out); | ||
660 | if (err && (*backing_file_out != NULL)) { | ||
661 | printk(KERN_ERR "Failed to read COW header from COW file " | ||
662 | "\"%s\", errno = %d\n", file, -err); | ||
663 | goto out_close; | ||
664 | } | ||
665 | if (err) | ||
666 | return fd; | ||
667 | |||
668 | asked_switch = path_requires_switch(*backing_file_out, backing_file, | ||
669 | file); | ||
670 | |||
671 | /* Allow switching only if no mismatch. */ | ||
672 | if (asked_switch && !backing_file_mismatch(*backing_file_out, size, | ||
673 | mtime)) { | ||
674 | printk(KERN_ERR "Switching backing file to '%s'\n", | ||
675 | *backing_file_out); | ||
676 | err = write_cow_header(file, fd, *backing_file_out, | ||
677 | sectorsize, align, &size); | ||
678 | if (err) { | ||
679 | printk(KERN_ERR "Switch failed, errno = %d\n", -err); | ||
680 | goto out_close; | ||
681 | } | ||
682 | } else { | ||
683 | *backing_file_out = backing_file; | ||
684 | err = backing_file_mismatch(*backing_file_out, size, mtime); | ||
685 | if (err) | ||
686 | goto out_close; | ||
687 | } | ||
688 | |||
689 | cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, | ||
690 | bitmap_len_out, data_offset_out); | ||
691 | |||
692 | return fd; | ||
693 | out_close: | ||
694 | os_close_file(fd); | ||
695 | return err; | ||
696 | } | ||
697 | |||
698 | static int create_cow_file(char *cow_file, char *backing_file, | ||
699 | struct openflags flags, | ||
700 | int sectorsize, int alignment, int *bitmap_offset_out, | ||
701 | unsigned long *bitmap_len_out, int *data_offset_out) | ||
702 | { | ||
703 | int err, fd; | ||
704 | |||
705 | flags.c = 1; | ||
706 | fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL); | ||
707 | if (fd < 0) { | ||
708 | err = fd; | ||
709 | printk(KERN_ERR "Open of COW file '%s' failed, errno = %d\n", | ||
710 | cow_file, -err); | ||
711 | goto out; | ||
712 | } | ||
713 | |||
714 | err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment, | ||
715 | bitmap_offset_out, bitmap_len_out, | ||
716 | data_offset_out); | ||
717 | if (!err) | ||
718 | return fd; | ||
719 | os_close_file(fd); | ||
720 | out: | ||
721 | return err; | ||
722 | } | ||
723 | |||
550 | static void ubd_close_dev(struct ubd *ubd_dev) | 724 | static void ubd_close_dev(struct ubd *ubd_dev) |
551 | { | 725 | { |
552 | os_close_file(ubd_dev->fd); | 726 | os_close_file(ubd_dev->fd); |
@@ -1166,185 +1340,6 @@ static int ubd_ioctl(struct inode * inode, struct file * file, | |||
1166 | return -EINVAL; | 1340 | return -EINVAL; |
1167 | } | 1341 | } |
1168 | 1342 | ||
1169 | static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow) | ||
1170 | { | ||
1171 | struct uml_stat buf1, buf2; | ||
1172 | int err; | ||
1173 | |||
1174 | if(from_cmdline == NULL) | ||
1175 | return 0; | ||
1176 | if(!strcmp(from_cmdline, from_cow)) | ||
1177 | return 0; | ||
1178 | |||
1179 | err = os_stat_file(from_cmdline, &buf1); | ||
1180 | if(err < 0){ | ||
1181 | printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err); | ||
1182 | return 0; | ||
1183 | } | ||
1184 | err = os_stat_file(from_cow, &buf2); | ||
1185 | if(err < 0){ | ||
1186 | printk("Couldn't stat '%s', err = %d\n", from_cow, -err); | ||
1187 | return 1; | ||
1188 | } | ||
1189 | if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) | ||
1190 | return 0; | ||
1191 | |||
1192 | printk("Backing file mismatch - \"%s\" requested,\n" | ||
1193 | "\"%s\" specified in COW header of \"%s\"\n", | ||
1194 | from_cmdline, from_cow, cow); | ||
1195 | return 1; | ||
1196 | } | ||
1197 | |||
1198 | static int backing_file_mismatch(char *file, __u64 size, time_t mtime) | ||
1199 | { | ||
1200 | unsigned long modtime; | ||
1201 | unsigned long long actual; | ||
1202 | int err; | ||
1203 | |||
1204 | err = os_file_modtime(file, &modtime); | ||
1205 | if(err < 0){ | ||
1206 | printk("Failed to get modification time of backing file " | ||
1207 | "\"%s\", err = %d\n", file, -err); | ||
1208 | return err; | ||
1209 | } | ||
1210 | |||
1211 | err = os_file_size(file, &actual); | ||
1212 | if(err < 0){ | ||
1213 | printk("Failed to get size of backing file \"%s\", " | ||
1214 | "err = %d\n", file, -err); | ||
1215 | return err; | ||
1216 | } | ||
1217 | |||
1218 | if(actual != size){ | ||
1219 | /*__u64 can be a long on AMD64 and with %lu GCC complains; so | ||
1220 | * the typecast.*/ | ||
1221 | printk("Size mismatch (%llu vs %llu) of COW header vs backing " | ||
1222 | "file\n", (unsigned long long) size, actual); | ||
1223 | return -EINVAL; | ||
1224 | } | ||
1225 | if(modtime != mtime){ | ||
1226 | printk("mtime mismatch (%ld vs %ld) of COW header vs backing " | ||
1227 | "file\n", mtime, modtime); | ||
1228 | return -EINVAL; | ||
1229 | } | ||
1230 | return 0; | ||
1231 | } | ||
1232 | |||
1233 | int read_cow_bitmap(int fd, void *buf, int offset, int len) | ||
1234 | { | ||
1235 | int err; | ||
1236 | |||
1237 | err = os_seek_file(fd, offset); | ||
1238 | if(err < 0) | ||
1239 | return err; | ||
1240 | |||
1241 | err = os_read_file(fd, buf, len); | ||
1242 | if(err < 0) | ||
1243 | return err; | ||
1244 | |||
1245 | return 0; | ||
1246 | } | ||
1247 | |||
1248 | int open_ubd_file(char *file, struct openflags *openflags, int shared, | ||
1249 | char **backing_file_out, int *bitmap_offset_out, | ||
1250 | unsigned long *bitmap_len_out, int *data_offset_out, | ||
1251 | int *create_cow_out) | ||
1252 | { | ||
1253 | time_t mtime; | ||
1254 | unsigned long long size; | ||
1255 | __u32 version, align; | ||
1256 | char *backing_file; | ||
1257 | int fd, err, sectorsize, asked_switch, mode = 0644; | ||
1258 | |||
1259 | fd = os_open_file(file, *openflags, mode); | ||
1260 | if (fd < 0) { | ||
1261 | if ((fd == -ENOENT) && (create_cow_out != NULL)) | ||
1262 | *create_cow_out = 1; | ||
1263 | if (!openflags->w || | ||
1264 | ((fd != -EROFS) && (fd != -EACCES))) | ||
1265 | return fd; | ||
1266 | openflags->w = 0; | ||
1267 | fd = os_open_file(file, *openflags, mode); | ||
1268 | if (fd < 0) | ||
1269 | return fd; | ||
1270 | } | ||
1271 | |||
1272 | if(shared) | ||
1273 | printk("Not locking \"%s\" on the host\n", file); | ||
1274 | else { | ||
1275 | err = os_lock_file(fd, openflags->w); | ||
1276 | if(err < 0){ | ||
1277 | printk("Failed to lock '%s', err = %d\n", file, -err); | ||
1278 | goto out_close; | ||
1279 | } | ||
1280 | } | ||
1281 | |||
1282 | /* Successful return case! */ | ||
1283 | if(backing_file_out == NULL) | ||
1284 | return fd; | ||
1285 | |||
1286 | err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, | ||
1287 | &size, §orsize, &align, bitmap_offset_out); | ||
1288 | if(err && (*backing_file_out != NULL)){ | ||
1289 | printk("Failed to read COW header from COW file \"%s\", " | ||
1290 | "errno = %d\n", file, -err); | ||
1291 | goto out_close; | ||
1292 | } | ||
1293 | if(err) | ||
1294 | return fd; | ||
1295 | |||
1296 | asked_switch = path_requires_switch(*backing_file_out, backing_file, file); | ||
1297 | |||
1298 | /* Allow switching only if no mismatch. */ | ||
1299 | if (asked_switch && !backing_file_mismatch(*backing_file_out, size, mtime)) { | ||
1300 | printk("Switching backing file to '%s'\n", *backing_file_out); | ||
1301 | err = write_cow_header(file, fd, *backing_file_out, | ||
1302 | sectorsize, align, &size); | ||
1303 | if (err) { | ||
1304 | printk("Switch failed, errno = %d\n", -err); | ||
1305 | goto out_close; | ||
1306 | } | ||
1307 | } else { | ||
1308 | *backing_file_out = backing_file; | ||
1309 | err = backing_file_mismatch(*backing_file_out, size, mtime); | ||
1310 | if (err) | ||
1311 | goto out_close; | ||
1312 | } | ||
1313 | |||
1314 | cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, | ||
1315 | bitmap_len_out, data_offset_out); | ||
1316 | |||
1317 | return fd; | ||
1318 | out_close: | ||
1319 | os_close_file(fd); | ||
1320 | return err; | ||
1321 | } | ||
1322 | |||
1323 | int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, | ||
1324 | int sectorsize, int alignment, int *bitmap_offset_out, | ||
1325 | unsigned long *bitmap_len_out, int *data_offset_out) | ||
1326 | { | ||
1327 | int err, fd; | ||
1328 | |||
1329 | flags.c = 1; | ||
1330 | fd = open_ubd_file(cow_file, &flags, 0, NULL, NULL, NULL, NULL, NULL); | ||
1331 | if(fd < 0){ | ||
1332 | err = fd; | ||
1333 | printk("Open of COW file '%s' failed, errno = %d\n", cow_file, | ||
1334 | -err); | ||
1335 | goto out; | ||
1336 | } | ||
1337 | |||
1338 | err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment, | ||
1339 | bitmap_offset_out, bitmap_len_out, | ||
1340 | data_offset_out); | ||
1341 | if(!err) | ||
1342 | return fd; | ||
1343 | os_close_file(fd); | ||
1344 | out: | ||
1345 | return err; | ||
1346 | } | ||
1347 | |||
1348 | static int update_bitmap(struct io_thread_req *req) | 1343 | static int update_bitmap(struct io_thread_req *req) |
1349 | { | 1344 | { |
1350 | int n; | 1345 | int n; |
@@ -1369,7 +1364,7 @@ static int update_bitmap(struct io_thread_req *req) | |||
1369 | return 0; | 1364 | return 0; |
1370 | } | 1365 | } |
1371 | 1366 | ||
1372 | void do_io(struct io_thread_req *req) | 1367 | static void do_io(struct io_thread_req *req) |
1373 | { | 1368 | { |
1374 | char *buf; | 1369 | char *buf; |
1375 | unsigned long len; | 1370 | unsigned long len; |