diff options
-rw-r--r-- | arch/um/drivers/ubd_kern.c | 296 | ||||
-rw-r--r-- | arch/um/kernel/trap_kern.c | 29 |
2 files changed, 3 insertions, 322 deletions
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 9a56ff94308d..88f956c34fed 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -55,7 +55,7 @@ | |||
55 | #include "mem_kern.h" | 55 | #include "mem_kern.h" |
56 | #include "cow.h" | 56 | #include "cow.h" |
57 | 57 | ||
58 | enum ubd_req { UBD_READ, UBD_WRITE, UBD_MMAP }; | 58 | enum ubd_req { UBD_READ, UBD_WRITE }; |
59 | 59 | ||
60 | struct io_thread_req { | 60 | struct io_thread_req { |
61 | enum ubd_req op; | 61 | enum ubd_req op; |
@@ -68,8 +68,6 @@ struct io_thread_req { | |||
68 | unsigned long sector_mask; | 68 | unsigned long sector_mask; |
69 | unsigned long long cow_offset; | 69 | unsigned long long cow_offset; |
70 | unsigned long bitmap_words[2]; | 70 | unsigned long bitmap_words[2]; |
71 | int map_fd; | ||
72 | unsigned long long map_offset; | ||
73 | int error; | 71 | int error; |
74 | }; | 72 | }; |
75 | 73 | ||
@@ -122,10 +120,6 @@ static int ubd_ioctl(struct inode * inode, struct file * file, | |||
122 | 120 | ||
123 | #define MAX_DEV (8) | 121 | #define MAX_DEV (8) |
124 | 122 | ||
125 | /* Changed in early boot */ | ||
126 | static int ubd_do_mmap = 0; | ||
127 | #define UBD_MMAP_BLOCK_SIZE PAGE_SIZE | ||
128 | |||
129 | static struct block_device_operations ubd_blops = { | 123 | static struct block_device_operations ubd_blops = { |
130 | .owner = THIS_MODULE, | 124 | .owner = THIS_MODULE, |
131 | .open = ubd_open, | 125 | .open = ubd_open, |
@@ -175,12 +169,6 @@ struct ubd { | |||
175 | int no_cow; | 169 | int no_cow; |
176 | struct cow cow; | 170 | struct cow cow; |
177 | struct platform_device pdev; | 171 | struct platform_device pdev; |
178 | |||
179 | int map_writes; | ||
180 | int map_reads; | ||
181 | int nomap_writes; | ||
182 | int nomap_reads; | ||
183 | int write_maps; | ||
184 | }; | 172 | }; |
185 | 173 | ||
186 | #define DEFAULT_COW { \ | 174 | #define DEFAULT_COW { \ |
@@ -200,11 +188,6 @@ struct ubd { | |||
200 | .openflags = OPEN_FLAGS, \ | 188 | .openflags = OPEN_FLAGS, \ |
201 | .no_cow = 0, \ | 189 | .no_cow = 0, \ |
202 | .cow = DEFAULT_COW, \ | 190 | .cow = DEFAULT_COW, \ |
203 | .map_writes = 0, \ | ||
204 | .map_reads = 0, \ | ||
205 | .nomap_writes = 0, \ | ||
206 | .nomap_reads = 0, \ | ||
207 | .write_maps = 0, \ | ||
208 | } | 191 | } |
209 | 192 | ||
210 | struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; | 193 | struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD }; |
@@ -314,13 +297,6 @@ static int ubd_setup_common(char *str, int *index_out) | |||
314 | int major; | 297 | int major; |
315 | 298 | ||
316 | str++; | 299 | str++; |
317 | if(!strcmp(str, "mmap")){ | ||
318 | CHOOSE_MODE(printk("mmap not supported by the ubd " | ||
319 | "driver in tt mode\n"), | ||
320 | ubd_do_mmap = 1); | ||
321 | return(0); | ||
322 | } | ||
323 | |||
324 | if(!strcmp(str, "sync")){ | 300 | if(!strcmp(str, "sync")){ |
325 | global_openflags = of_sync(global_openflags); | 301 | global_openflags = of_sync(global_openflags); |
326 | return(0); | 302 | return(0); |
@@ -524,7 +500,7 @@ static void ubd_handler(void) | |||
524 | { | 500 | { |
525 | struct io_thread_req req; | 501 | struct io_thread_req req; |
526 | struct request *rq = elv_next_request(ubd_queue); | 502 | struct request *rq = elv_next_request(ubd_queue); |
527 | int n, err; | 503 | int n; |
528 | 504 | ||
529 | do_ubd = NULL; | 505 | do_ubd = NULL; |
530 | intr_count++; | 506 | intr_count++; |
@@ -538,19 +514,6 @@ static void ubd_handler(void) | |||
538 | return; | 514 | return; |
539 | } | 515 | } |
540 | 516 | ||
541 | if((req.op != UBD_MMAP) && | ||
542 | ((req.offset != ((__u64) (rq->sector)) << 9) || | ||
543 | (req.length != (rq->current_nr_sectors) << 9))) | ||
544 | panic("I/O op mismatch"); | ||
545 | |||
546 | if(req.map_fd != -1){ | ||
547 | err = physmem_subst_mapping(req.buffer, req.map_fd, | ||
548 | req.map_offset, 1); | ||
549 | if(err) | ||
550 | printk("ubd_handler - physmem_subst_mapping failed, " | ||
551 | "err = %d\n", -err); | ||
552 | } | ||
553 | |||
554 | ubd_finish(rq, req.error); | 517 | ubd_finish(rq, req.error); |
555 | reactivate_fd(thread_fd, UBD_IRQ); | 518 | reactivate_fd(thread_fd, UBD_IRQ); |
556 | do_ubd_request(ubd_queue); | 519 | do_ubd_request(ubd_queue); |
@@ -583,14 +546,10 @@ static int ubd_file_size(struct ubd *dev, __u64 *size_out) | |||
583 | 546 | ||
584 | static void ubd_close(struct ubd *dev) | 547 | static void ubd_close(struct ubd *dev) |
585 | { | 548 | { |
586 | if(ubd_do_mmap) | ||
587 | physmem_forget_descriptor(dev->fd); | ||
588 | os_close_file(dev->fd); | 549 | os_close_file(dev->fd); |
589 | if(dev->cow.file == NULL) | 550 | if(dev->cow.file == NULL) |
590 | return; | 551 | return; |
591 | 552 | ||
592 | if(ubd_do_mmap) | ||
593 | physmem_forget_descriptor(dev->cow.fd); | ||
594 | os_close_file(dev->cow.fd); | 553 | os_close_file(dev->cow.fd); |
595 | vfree(dev->cow.bitmap); | 554 | vfree(dev->cow.bitmap); |
596 | dev->cow.bitmap = NULL; | 555 | dev->cow.bitmap = NULL; |
@@ -1010,94 +969,13 @@ static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, | |||
1010 | req->bitmap_words, bitmap_len); | 969 | req->bitmap_words, bitmap_len); |
1011 | } | 970 | } |
1012 | 971 | ||
1013 | static int mmap_fd(struct request *req, struct ubd *dev, __u64 offset) | ||
1014 | { | ||
1015 | __u64 sector; | ||
1016 | unsigned char *bitmap; | ||
1017 | int bit, i; | ||
1018 | |||
1019 | /* mmap must have been requested on the command line */ | ||
1020 | if(!ubd_do_mmap) | ||
1021 | return(-1); | ||
1022 | |||
1023 | /* The buffer must be page aligned */ | ||
1024 | if(((unsigned long) req->buffer % UBD_MMAP_BLOCK_SIZE) != 0) | ||
1025 | return(-1); | ||
1026 | |||
1027 | /* The request must be a page long */ | ||
1028 | if((req->current_nr_sectors << 9) != PAGE_SIZE) | ||
1029 | return(-1); | ||
1030 | |||
1031 | if(dev->cow.file == NULL) | ||
1032 | return(dev->fd); | ||
1033 | |||
1034 | sector = offset >> 9; | ||
1035 | bitmap = (unsigned char *) dev->cow.bitmap; | ||
1036 | bit = ubd_test_bit(sector, bitmap); | ||
1037 | |||
1038 | for(i = 1; i < req->current_nr_sectors; i++){ | ||
1039 | if(ubd_test_bit(sector + i, bitmap) != bit) | ||
1040 | return(-1); | ||
1041 | } | ||
1042 | |||
1043 | if(bit || (rq_data_dir(req) == WRITE)) | ||
1044 | offset += dev->cow.data_offset; | ||
1045 | |||
1046 | /* The data on disk must be page aligned */ | ||
1047 | if((offset % UBD_MMAP_BLOCK_SIZE) != 0) | ||
1048 | return(-1); | ||
1049 | |||
1050 | return(bit ? dev->fd : dev->cow.fd); | ||
1051 | } | ||
1052 | |||
1053 | static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset, | ||
1054 | struct request *req, | ||
1055 | struct io_thread_req *io_req) | ||
1056 | { | ||
1057 | int err; | ||
1058 | |||
1059 | if(rq_data_dir(req) == WRITE){ | ||
1060 | /* Writes are almost no-ops since the new data is already in the | ||
1061 | * host page cache | ||
1062 | */ | ||
1063 | dev->map_writes++; | ||
1064 | if(dev->cow.file != NULL) | ||
1065 | cowify_bitmap(io_req->offset, io_req->length, | ||
1066 | &io_req->sector_mask, &io_req->cow_offset, | ||
1067 | dev->cow.bitmap, dev->cow.bitmap_offset, | ||
1068 | io_req->bitmap_words, | ||
1069 | dev->cow.bitmap_len); | ||
1070 | } | ||
1071 | else { | ||
1072 | int w; | ||
1073 | |||
1074 | if((dev->cow.file != NULL) && (fd == dev->cow.fd)) | ||
1075 | w = 0; | ||
1076 | else w = dev->openflags.w; | ||
1077 | |||
1078 | if((dev->cow.file != NULL) && (fd == dev->fd)) | ||
1079 | offset += dev->cow.data_offset; | ||
1080 | |||
1081 | err = physmem_subst_mapping(req->buffer, fd, offset, w); | ||
1082 | if(err){ | ||
1083 | printk("physmem_subst_mapping failed, err = %d\n", | ||
1084 | -err); | ||
1085 | return(1); | ||
1086 | } | ||
1087 | dev->map_reads++; | ||
1088 | } | ||
1089 | io_req->op = UBD_MMAP; | ||
1090 | io_req->buffer = req->buffer; | ||
1091 | return(0); | ||
1092 | } | ||
1093 | |||
1094 | /* Called with ubd_io_lock held */ | 972 | /* Called with ubd_io_lock held */ |
1095 | static int prepare_request(struct request *req, struct io_thread_req *io_req) | 973 | static int prepare_request(struct request *req, struct io_thread_req *io_req) |
1096 | { | 974 | { |
1097 | struct gendisk *disk = req->rq_disk; | 975 | struct gendisk *disk = req->rq_disk; |
1098 | struct ubd *dev = disk->private_data; | 976 | struct ubd *dev = disk->private_data; |
1099 | __u64 offset; | 977 | __u64 offset; |
1100 | int len, fd; | 978 | int len; |
1101 | 979 | ||
1102 | if(req->rq_status == RQ_INACTIVE) return(1); | 980 | if(req->rq_status == RQ_INACTIVE) return(1); |
1103 | 981 | ||
@@ -1114,34 +992,12 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) | |||
1114 | 992 | ||
1115 | io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; | 993 | io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; |
1116 | io_req->fds[1] = dev->fd; | 994 | io_req->fds[1] = dev->fd; |
1117 | io_req->map_fd = -1; | ||
1118 | io_req->cow_offset = -1; | 995 | io_req->cow_offset = -1; |
1119 | io_req->offset = offset; | 996 | io_req->offset = offset; |
1120 | io_req->length = len; | 997 | io_req->length = len; |
1121 | io_req->error = 0; | 998 | io_req->error = 0; |
1122 | io_req->sector_mask = 0; | 999 | io_req->sector_mask = 0; |
1123 | 1000 | ||
1124 | fd = mmap_fd(req, dev, io_req->offset); | ||
1125 | if(fd > 0){ | ||
1126 | /* If mmapping is otherwise OK, but the first access to the | ||
1127 | * page is a write, then it's not mapped in yet. So we have | ||
1128 | * to write the data to disk first, then we can map the disk | ||
1129 | * page in and continue normally from there. | ||
1130 | */ | ||
1131 | if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer)){ | ||
1132 | io_req->map_fd = dev->fd; | ||
1133 | io_req->map_offset = io_req->offset + | ||
1134 | dev->cow.data_offset; | ||
1135 | dev->write_maps++; | ||
1136 | } | ||
1137 | else return(prepare_mmap_request(dev, fd, io_req->offset, req, | ||
1138 | io_req)); | ||
1139 | } | ||
1140 | |||
1141 | if(rq_data_dir(req) == READ) | ||
1142 | dev->nomap_reads++; | ||
1143 | else dev->nomap_writes++; | ||
1144 | |||
1145 | io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE; | 1001 | io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE; |
1146 | io_req->offsets[0] = 0; | 1002 | io_req->offsets[0] = 0; |
1147 | io_req->offsets[1] = dev->cow.data_offset; | 1003 | io_req->offsets[1] = dev->cow.data_offset; |
@@ -1229,143 +1085,6 @@ static int ubd_ioctl(struct inode * inode, struct file * file, | |||
1229 | return(-EINVAL); | 1085 | return(-EINVAL); |
1230 | } | 1086 | } |
1231 | 1087 | ||
1232 | static int ubd_check_remapped(int fd, unsigned long address, int is_write, | ||
1233 | __u64 offset) | ||
1234 | { | ||
1235 | __u64 bitmap_offset; | ||
1236 | unsigned long new_bitmap[2]; | ||
1237 | int i, err, n; | ||
1238 | |||
1239 | /* If it's not a write access, we can't do anything about it */ | ||
1240 | if(!is_write) | ||
1241 | return(0); | ||
1242 | |||
1243 | /* We have a write */ | ||
1244 | for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){ | ||
1245 | struct ubd *dev = &ubd_dev[i]; | ||
1246 | |||
1247 | if((dev->fd != fd) && (dev->cow.fd != fd)) | ||
1248 | continue; | ||
1249 | |||
1250 | /* It's a write to a ubd device */ | ||
1251 | |||
1252 | /* This should be impossible now */ | ||
1253 | if(!dev->openflags.w){ | ||
1254 | /* It's a write access on a read-only device - probably | ||
1255 | * shouldn't happen. If the kernel is trying to change | ||
1256 | * something with no intention of writing it back out, | ||
1257 | * then this message will clue us in that this needs | ||
1258 | * fixing | ||
1259 | */ | ||
1260 | printk("Write access to mapped page from readonly ubd " | ||
1261 | "device %d\n", i); | ||
1262 | return(0); | ||
1263 | } | ||
1264 | |||
1265 | /* It's a write to a writeable ubd device - it must be COWed | ||
1266 | * because, otherwise, the page would have been mapped in | ||
1267 | * writeable | ||
1268 | */ | ||
1269 | |||
1270 | if(!dev->cow.file) | ||
1271 | panic("Write fault on writeable non-COW ubd device %d", | ||
1272 | i); | ||
1273 | |||
1274 | /* It should also be an access to the backing file since the | ||
1275 | * COW pages should be mapped in read-write | ||
1276 | */ | ||
1277 | |||
1278 | if(fd == dev->fd) | ||
1279 | panic("Write fault on a backing page of ubd " | ||
1280 | "device %d\n", i); | ||
1281 | |||
1282 | /* So, we do the write, copying the backing data to the COW | ||
1283 | * file... | ||
1284 | */ | ||
1285 | |||
1286 | err = os_seek_file(dev->fd, offset + dev->cow.data_offset); | ||
1287 | if(err < 0) | ||
1288 | panic("Couldn't seek to %lld in COW file of ubd " | ||
1289 | "device %d, err = %d", | ||
1290 | offset + dev->cow.data_offset, i, -err); | ||
1291 | |||
1292 | n = os_write_file(dev->fd, (void *) address, PAGE_SIZE); | ||
1293 | if(n != PAGE_SIZE) | ||
1294 | panic("Couldn't copy data to COW file of ubd " | ||
1295 | "device %d, err = %d", i, -n); | ||
1296 | |||
1297 | /* ... updating the COW bitmap... */ | ||
1298 | |||
1299 | cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset, | ||
1300 | dev->cow.bitmap, dev->cow.bitmap_offset, | ||
1301 | new_bitmap, dev->cow.bitmap_len); | ||
1302 | |||
1303 | err = os_seek_file(dev->fd, bitmap_offset); | ||
1304 | if(err < 0) | ||
1305 | panic("Couldn't seek to %lld in COW file of ubd " | ||
1306 | "device %d, err = %d", bitmap_offset, i, -err); | ||
1307 | |||
1308 | n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap)); | ||
1309 | if(n != sizeof(new_bitmap)) | ||
1310 | panic("Couldn't update bitmap of ubd device %d, " | ||
1311 | "err = %d", i, -n); | ||
1312 | |||
1313 | /* Maybe we can map the COW page in, and maybe we can't. If | ||
1314 | * it is a pre-V3 COW file, we can't, since the alignment will | ||
1315 | * be wrong. If it is a V3 or later COW file which has been | ||
1316 | * moved to a system with a larger page size, then maybe we | ||
1317 | * can't, depending on the exact location of the page. | ||
1318 | */ | ||
1319 | |||
1320 | offset += dev->cow.data_offset; | ||
1321 | |||
1322 | /* Remove the remapping, putting the original anonymous page | ||
1323 | * back. If the COW file can be mapped in, that is done. | ||
1324 | * Otherwise, the COW page is read in. | ||
1325 | */ | ||
1326 | |||
1327 | if(!physmem_remove_mapping((void *) address)) | ||
1328 | panic("Address 0x%lx not remapped by ubd device %d", | ||
1329 | address, i); | ||
1330 | if((offset % UBD_MMAP_BLOCK_SIZE) == 0) | ||
1331 | physmem_subst_mapping((void *) address, dev->fd, | ||
1332 | offset, 1); | ||
1333 | else { | ||
1334 | err = os_seek_file(dev->fd, offset); | ||
1335 | if(err < 0) | ||
1336 | panic("Couldn't seek to %lld in COW file of " | ||
1337 | "ubd device %d, err = %d", offset, i, | ||
1338 | -err); | ||
1339 | |||
1340 | n = os_read_file(dev->fd, (void *) address, PAGE_SIZE); | ||
1341 | if(n != PAGE_SIZE) | ||
1342 | panic("Failed to read page from offset %llx of " | ||
1343 | "COW file of ubd device %d, err = %d", | ||
1344 | offset, i, -n); | ||
1345 | } | ||
1346 | |||
1347 | return(1); | ||
1348 | } | ||
1349 | |||
1350 | /* It's not a write on a ubd device */ | ||
1351 | return(0); | ||
1352 | } | ||
1353 | |||
1354 | static struct remapper ubd_remapper = { | ||
1355 | .list = LIST_HEAD_INIT(ubd_remapper.list), | ||
1356 | .proc = ubd_check_remapped, | ||
1357 | }; | ||
1358 | |||
1359 | static int ubd_remapper_setup(void) | ||
1360 | { | ||
1361 | if(ubd_do_mmap) | ||
1362 | register_remapper(&ubd_remapper); | ||
1363 | |||
1364 | return(0); | ||
1365 | } | ||
1366 | |||
1367 | __initcall(ubd_remapper_setup); | ||
1368 | |||
1369 | static int same_backing_files(char *from_cmdline, char *from_cow, char *cow) | 1088 | static int same_backing_files(char *from_cmdline, char *from_cow, char *cow) |
1370 | { | 1089 | { |
1371 | struct uml_stat buf1, buf2; | 1090 | struct uml_stat buf1, buf2; |
@@ -1568,15 +1287,6 @@ void do_io(struct io_thread_req *req) | |||
1568 | int err; | 1287 | int err; |
1569 | __u64 off; | 1288 | __u64 off; |
1570 | 1289 | ||
1571 | if(req->op == UBD_MMAP){ | ||
1572 | /* Touch the page to force the host to do any necessary IO to | ||
1573 | * get it into memory | ||
1574 | */ | ||
1575 | n = *((volatile int *) req->buffer); | ||
1576 | req->error = update_bitmap(req); | ||
1577 | return; | ||
1578 | } | ||
1579 | |||
1580 | nsectors = req->length / req->sectorsize; | 1290 | nsectors = req->length / req->sectorsize; |
1581 | start = 0; | 1291 | start = 0; |
1582 | do { | 1292 | do { |
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 9ae2eff0d8f3..1de22d8a313a 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c | |||
@@ -107,33 +107,6 @@ out_of_memory: | |||
107 | goto out; | 107 | goto out; |
108 | } | 108 | } |
109 | 109 | ||
110 | LIST_HEAD(physmem_remappers); | ||
111 | |||
112 | void register_remapper(struct remapper *info) | ||
113 | { | ||
114 | list_add(&info->list, &physmem_remappers); | ||
115 | } | ||
116 | |||
117 | static int check_remapped_addr(unsigned long address, int is_write) | ||
118 | { | ||
119 | struct remapper *remapper; | ||
120 | struct list_head *ele; | ||
121 | __u64 offset; | ||
122 | int fd; | ||
123 | |||
124 | fd = phys_mapping(__pa(address), &offset); | ||
125 | if(fd == -1) | ||
126 | return(0); | ||
127 | |||
128 | list_for_each(ele, &physmem_remappers){ | ||
129 | remapper = list_entry(ele, struct remapper, list); | ||
130 | if((*remapper->proc)(fd, address, is_write, offset)) | ||
131 | return(1); | ||
132 | } | ||
133 | |||
134 | return(0); | ||
135 | } | ||
136 | |||
137 | /* | 110 | /* |
138 | * We give a *copy* of the faultinfo in the regs to segv. | 111 | * We give a *copy* of the faultinfo in the regs to segv. |
139 | * This must be done, since nesting SEGVs could overwrite | 112 | * This must be done, since nesting SEGVs could overwrite |
@@ -152,8 +125,6 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) | |||
152 | flush_tlb_kernel_vm(); | 125 | flush_tlb_kernel_vm(); |
153 | return(0); | 126 | return(0); |
154 | } | 127 | } |
155 | else if(check_remapped_addr(address & PAGE_MASK, is_write)) | ||
156 | return(0); | ||
157 | else if(current->mm == NULL) | 128 | else if(current->mm == NULL) |
158 | panic("Segfault with no mm"); | 129 | panic("Segfault with no mm"); |
159 | err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); | 130 | err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); |