diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-02 21:39:22 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-01-02 21:39:22 -0500 |
commit | 6aa293d8ff0939802a6c86cee6cd152c1b0a7a0d (patch) | |
tree | f07bcfb2e44bd8bc0a38c4b0fcc707b6ef1a7ab4 /arch/um | |
parent | 04a17edeca524b71dbb5be41a7002d247fbf34c0 (diff) | |
parent | 940b241d9050fc354f68c182e99fc3da1ff36bc0 (diff) |
Merge branch 'for-linus-4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml
Pull UML updates from Richard Weinberger:
- DISCARD support for our block device driver
- Many TLB flush optimizations
- Various smaller fixes
- And most important, Anton agreed to help me maintaining UML
* 'for-linus-4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml:
um: Remove obsolete reenable_XX calls
um: writev needs <sys/uio.h>
Add Anton Ivanov to UML maintainers
um: remove redundant generic-y
um: Optimize Flush TLB for force/fork case
um: Avoid marking pages with "changed protection"
um: Skip TLB flushing where not needed
um: Optimize TLB operations v2
um: Remove unnecessary faulted check in uaccess.c
um: Add support for DISCARD in the UBD Driver
um: Remove unsafe printks from the io thread
um: Clean-up command processing in UML UBD driver
um: Switch to block-mq constants in the UML UBD driver
um: Make GCOV depend on !KCOV
um: Include sys/uio.h to have writev()
um: Add HAVE_DEBUG_BUGVERBOSE
um: Update maintainers file entry
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/Kconfig | 1 | ||||
-rw-r--r-- | arch/um/Kconfig.debug | 1 | ||||
-rw-r--r-- | arch/um/drivers/chan_kern.c | 10 | ||||
-rw-r--r-- | arch/um/drivers/line.c | 10 | ||||
-rw-r--r-- | arch/um/drivers/mconsole_kern.c | 2 | ||||
-rw-r--r-- | arch/um/drivers/net_kern.c | 2 | ||||
-rw-r--r-- | arch/um/drivers/port_kern.c | 1 | ||||
-rw-r--r-- | arch/um/drivers/random.c | 1 | ||||
-rw-r--r-- | arch/um/drivers/ubd_kern.c | 231 | ||||
-rw-r--r-- | arch/um/drivers/vector_user.c | 2 | ||||
-rw-r--r-- | arch/um/include/asm/Kbuild | 2 | ||||
-rw-r--r-- | arch/um/include/asm/pgtable.h | 9 | ||||
-rw-r--r-- | arch/um/include/shared/irq_user.h | 1 | ||||
-rw-r--r-- | arch/um/include/shared/os.h | 1 | ||||
-rw-r--r-- | arch/um/kernel/irq.c | 6 | ||||
-rw-r--r-- | arch/um/kernel/sigio.c | 1 | ||||
-rw-r--r-- | arch/um/kernel/skas/uaccess.c | 23 | ||||
-rw-r--r-- | arch/um/kernel/tlb.c | 115 | ||||
-rw-r--r-- | arch/um/os-Linux/file.c | 10 |
19 files changed, 257 insertions, 172 deletions
diff --git a/arch/um/Kconfig b/arch/um/Kconfig index a238547671d6..ec9711d068b7 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig | |||
@@ -12,6 +12,7 @@ config UML | |||
12 | select HAVE_UID16 | 12 | select HAVE_UID16 |
13 | select HAVE_FUTEX_CMPXCHG if FUTEX | 13 | select HAVE_FUTEX_CMPXCHG if FUTEX |
14 | select HAVE_DEBUG_KMEMLEAK | 14 | select HAVE_DEBUG_KMEMLEAK |
15 | select HAVE_DEBUG_BUGVERBOSE | ||
15 | select GENERIC_IRQ_SHOW | 16 | select GENERIC_IRQ_SHOW |
16 | select GENERIC_CPU_DEVICES | 17 | select GENERIC_CPU_DEVICES |
17 | select GENERIC_CLOCKEVENTS | 18 | select GENERIC_CLOCKEVENTS |
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug index 2014597605ea..85726eeec345 100644 --- a/arch/um/Kconfig.debug +++ b/arch/um/Kconfig.debug | |||
@@ -16,6 +16,7 @@ config GPROF | |||
16 | config GCOV | 16 | config GCOV |
17 | bool "Enable gcov support" | 17 | bool "Enable gcov support" |
18 | depends on DEBUG_INFO | 18 | depends on DEBUG_INFO |
19 | depends on !KCOV | ||
19 | help | 20 | help |
20 | This option allows developers to retrieve coverage data from a UML | 21 | This option allows developers to retrieve coverage data from a UML |
21 | session. | 22 | session. |
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 05588f9466c7..a4e64edb8f38 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c | |||
@@ -211,12 +211,6 @@ void deactivate_chan(struct chan *chan, int irq) | |||
211 | deactivate_fd(chan->fd, irq); | 211 | deactivate_fd(chan->fd, irq); |
212 | } | 212 | } |
213 | 213 | ||
214 | void reactivate_chan(struct chan *chan, int irq) | ||
215 | { | ||
216 | if (chan && chan->enabled) | ||
217 | reactivate_fd(chan->fd, irq); | ||
218 | } | ||
219 | |||
220 | int write_chan(struct chan *chan, const char *buf, int len, | 214 | int write_chan(struct chan *chan, const char *buf, int len, |
221 | int write_irq) | 215 | int write_irq) |
222 | { | 216 | { |
@@ -228,8 +222,6 @@ int write_chan(struct chan *chan, const char *buf, int len, | |||
228 | n = chan->ops->write(chan->fd, buf, len, chan->data); | 222 | n = chan->ops->write(chan->fd, buf, len, chan->data); |
229 | if (chan->primary) { | 223 | if (chan->primary) { |
230 | ret = n; | 224 | ret = n; |
231 | if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len))) | ||
232 | reactivate_fd(chan->fd, write_irq); | ||
233 | } | 225 | } |
234 | return ret; | 226 | return ret; |
235 | } | 227 | } |
@@ -527,8 +519,6 @@ void chan_interrupt(struct line *line, int irq) | |||
527 | tty_insert_flip_char(port, c, TTY_NORMAL); | 519 | tty_insert_flip_char(port, c, TTY_NORMAL); |
528 | } while (err > 0); | 520 | } while (err > 0); |
529 | 521 | ||
530 | if (err == 0) | ||
531 | reactivate_fd(chan->fd, irq); | ||
532 | if (err == -EIO) { | 522 | if (err == -EIO) { |
533 | if (chan->primary) { | 523 | if (chan->primary) { |
534 | tty_port_tty_hangup(&line->port, false); | 524 | tty_port_tty_hangup(&line->port, false); |
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 7e524efed584..e0e63931fb2b 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c | |||
@@ -235,14 +235,6 @@ void line_unthrottle(struct tty_struct *tty) | |||
235 | 235 | ||
236 | line->throttled = 0; | 236 | line->throttled = 0; |
237 | chan_interrupt(line, line->driver->read_irq); | 237 | chan_interrupt(line, line->driver->read_irq); |
238 | |||
239 | /* | ||
240 | * Maybe there is enough stuff pending that calling the interrupt | ||
241 | * throttles us again. In this case, line->throttled will be 1 | ||
242 | * again and we shouldn't turn the interrupt back on. | ||
243 | */ | ||
244 | if (!line->throttled) | ||
245 | reactivate_chan(line->chan_in, line->driver->read_irq); | ||
246 | } | 238 | } |
247 | 239 | ||
248 | static irqreturn_t line_write_interrupt(int irq, void *data) | 240 | static irqreturn_t line_write_interrupt(int irq, void *data) |
@@ -667,8 +659,6 @@ static irqreturn_t winch_interrupt(int irq, void *data) | |||
667 | tty_kref_put(tty); | 659 | tty_kref_put(tty); |
668 | } | 660 | } |
669 | out: | 661 | out: |
670 | if (winch->fd != -1) | ||
671 | reactivate_fd(winch->fd, WINCH_IRQ); | ||
672 | return IRQ_HANDLED; | 662 | return IRQ_HANDLED; |
673 | } | 663 | } |
674 | 664 | ||
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index d5f9a2d1da1b..ff3ab72fd90f 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c | |||
@@ -96,7 +96,6 @@ static irqreturn_t mconsole_interrupt(int irq, void *dev_id) | |||
96 | } | 96 | } |
97 | if (!list_empty(&mc_requests)) | 97 | if (!list_empty(&mc_requests)) |
98 | schedule_work(&mconsole_work); | 98 | schedule_work(&mconsole_work); |
99 | reactivate_fd(fd, MCONSOLE_IRQ); | ||
100 | return IRQ_HANDLED; | 99 | return IRQ_HANDLED; |
101 | } | 100 | } |
102 | 101 | ||
@@ -240,7 +239,6 @@ void mconsole_stop(struct mc_request *req) | |||
240 | (*req->cmd->handler)(req); | 239 | (*req->cmd->handler)(req); |
241 | } | 240 | } |
242 | os_set_fd_block(req->originating_fd, 0); | 241 | os_set_fd_block(req->originating_fd, 0); |
243 | reactivate_fd(req->originating_fd, MCONSOLE_IRQ); | ||
244 | mconsole_reply(req, "", 0, 0); | 242 | mconsole_reply(req, "", 0, 0); |
245 | } | 243 | } |
246 | 244 | ||
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 624cb47cc9cd..d80cfb1d9430 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c | |||
@@ -137,8 +137,6 @@ static irqreturn_t uml_net_interrupt(int irq, void *dev_id) | |||
137 | schedule_work(&lp->work); | 137 | schedule_work(&lp->work); |
138 | goto out; | 138 | goto out; |
139 | } | 139 | } |
140 | reactivate_fd(lp->fd, UM_ETH_IRQ); | ||
141 | |||
142 | out: | 140 | out: |
143 | spin_unlock(&lp->lock); | 141 | spin_unlock(&lp->lock); |
144 | return IRQ_HANDLED; | 142 | return IRQ_HANDLED; |
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c index 40ca5cc275e9..b0e9ff35daee 100644 --- a/arch/um/drivers/port_kern.c +++ b/arch/um/drivers/port_kern.c | |||
@@ -137,7 +137,6 @@ static void port_work_proc(struct work_struct *unused) | |||
137 | if (!port->has_connection) | 137 | if (!port->has_connection) |
138 | continue; | 138 | continue; |
139 | 139 | ||
140 | reactivate_fd(port->fd, ACCEPT_IRQ); | ||
141 | while (port_accept(port)) | 140 | while (port_accept(port)) |
142 | ; | 141 | ; |
143 | port->has_connection = 0; | 142 | port->has_connection = 0; |
diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c index 778a0e52d5a5..1d5d3057e6f1 100644 --- a/arch/um/drivers/random.c +++ b/arch/um/drivers/random.c | |||
@@ -73,7 +73,6 @@ static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size, | |||
73 | return ret ? : -EAGAIN; | 73 | return ret ? : -EAGAIN; |
74 | 74 | ||
75 | atomic_inc(&host_sleep_count); | 75 | atomic_inc(&host_sleep_count); |
76 | reactivate_fd(random_fd, RANDOM_IRQ); | ||
77 | add_sigio_fd(random_fd); | 76 | add_sigio_fd(random_fd); |
78 | 77 | ||
79 | add_wait_queue(&host_read_wait, &wait); | 78 | add_wait_queue(&host_read_wait, &wait); |
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 28c40624bcb6..a4a41421c5e2 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2018 Cambridge Greys Ltd | ||
2 | * Copyright (C) 2015-2016 Anton Ivanov (aivanov@brocade.com) | 3 | * Copyright (C) 2015-2016 Anton Ivanov (aivanov@brocade.com) |
3 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) | 4 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) |
4 | * Licensed under the GPL | 5 | * Licensed under the GPL |
@@ -43,11 +44,11 @@ | |||
43 | #include <os.h> | 44 | #include <os.h> |
44 | #include "cow.h" | 45 | #include "cow.h" |
45 | 46 | ||
46 | enum ubd_req { UBD_READ, UBD_WRITE, UBD_FLUSH }; | 47 | /* Max request size is determined by sector mask - 32K */ |
48 | #define UBD_MAX_REQUEST (8 * sizeof(long)) | ||
47 | 49 | ||
48 | struct io_thread_req { | 50 | struct io_thread_req { |
49 | struct request *req; | 51 | struct request *req; |
50 | enum ubd_req op; | ||
51 | int fds[2]; | 52 | int fds[2]; |
52 | unsigned long offsets[2]; | 53 | unsigned long offsets[2]; |
53 | unsigned long long offset; | 54 | unsigned long long offset; |
@@ -153,6 +154,7 @@ struct ubd { | |||
153 | struct openflags openflags; | 154 | struct openflags openflags; |
154 | unsigned shared:1; | 155 | unsigned shared:1; |
155 | unsigned no_cow:1; | 156 | unsigned no_cow:1; |
157 | unsigned no_trim:1; | ||
156 | struct cow cow; | 158 | struct cow cow; |
157 | struct platform_device pdev; | 159 | struct platform_device pdev; |
158 | struct request_queue *queue; | 160 | struct request_queue *queue; |
@@ -176,6 +178,7 @@ struct ubd { | |||
176 | .boot_openflags = OPEN_FLAGS, \ | 178 | .boot_openflags = OPEN_FLAGS, \ |
177 | .openflags = OPEN_FLAGS, \ | 179 | .openflags = OPEN_FLAGS, \ |
178 | .no_cow = 0, \ | 180 | .no_cow = 0, \ |
181 | .no_trim = 0, \ | ||
179 | .shared = 0, \ | 182 | .shared = 0, \ |
180 | .cow = DEFAULT_COW, \ | 183 | .cow = DEFAULT_COW, \ |
181 | .lock = __SPIN_LOCK_UNLOCKED(ubd_devs.lock), \ | 184 | .lock = __SPIN_LOCK_UNLOCKED(ubd_devs.lock), \ |
@@ -322,7 +325,7 @@ static int ubd_setup_common(char *str, int *index_out, char **error_out) | |||
322 | *index_out = n; | 325 | *index_out = n; |
323 | 326 | ||
324 | err = -EINVAL; | 327 | err = -EINVAL; |
325 | for (i = 0; i < sizeof("rscd="); i++) { | 328 | for (i = 0; i < sizeof("rscdt="); i++) { |
326 | switch (*str) { | 329 | switch (*str) { |
327 | case 'r': | 330 | case 'r': |
328 | flags.w = 0; | 331 | flags.w = 0; |
@@ -336,12 +339,15 @@ static int ubd_setup_common(char *str, int *index_out, char **error_out) | |||
336 | case 'c': | 339 | case 'c': |
337 | ubd_dev->shared = 1; | 340 | ubd_dev->shared = 1; |
338 | break; | 341 | break; |
342 | case 't': | ||
343 | ubd_dev->no_trim = 1; | ||
344 | break; | ||
339 | case '=': | 345 | case '=': |
340 | str++; | 346 | str++; |
341 | goto break_loop; | 347 | goto break_loop; |
342 | default: | 348 | default: |
343 | *error_out = "Expected '=' or flag letter " | 349 | *error_out = "Expected '=' or flag letter " |
344 | "(r, s, c, or d)"; | 350 | "(r, s, c, t or d)"; |
345 | goto out; | 351 | goto out; |
346 | } | 352 | } |
347 | str++; | 353 | str++; |
@@ -414,6 +420,7 @@ __uml_help(ubd_setup, | |||
414 | " 'c' will cause the device to be treated as being shared between multiple\n" | 420 | " 'c' will cause the device to be treated as being shared between multiple\n" |
415 | " UMLs and file locking will be turned off - this is appropriate for a\n" | 421 | " UMLs and file locking will be turned off - this is appropriate for a\n" |
416 | " cluster filesystem and inappropriate at almost all other times.\n\n" | 422 | " cluster filesystem and inappropriate at almost all other times.\n\n" |
423 | " 't' will disable trim/discard support on the device (enabled by default).\n\n" | ||
417 | ); | 424 | ); |
418 | 425 | ||
419 | static int udb_setup(char *str) | 426 | static int udb_setup(char *str) |
@@ -511,16 +518,21 @@ static void ubd_handler(void) | |||
511 | } | 518 | } |
512 | for (count = 0; count < n/sizeof(struct io_thread_req *); count++) { | 519 | for (count = 0; count < n/sizeof(struct io_thread_req *); count++) { |
513 | struct io_thread_req *io_req = (*irq_req_buffer)[count]; | 520 | struct io_thread_req *io_req = (*irq_req_buffer)[count]; |
514 | int err = io_req->error ? BLK_STS_IOERR : BLK_STS_OK; | ||
515 | |||
516 | if (!blk_update_request(io_req->req, err, io_req->length)) | ||
517 | __blk_mq_end_request(io_req->req, err); | ||
518 | 521 | ||
522 | if ((io_req->error == BLK_STS_NOTSUPP) && (req_op(io_req->req) == REQ_OP_DISCARD)) { | ||
523 | blk_queue_max_discard_sectors(io_req->req->q, 0); | ||
524 | blk_queue_max_write_zeroes_sectors(io_req->req->q, 0); | ||
525 | blk_queue_flag_clear(QUEUE_FLAG_DISCARD, io_req->req->q); | ||
526 | } | ||
527 | if ((io_req->error) || (io_req->buffer == NULL)) | ||
528 | blk_mq_end_request(io_req->req, io_req->error); | ||
529 | else { | ||
530 | if (!blk_update_request(io_req->req, io_req->error, io_req->length)) | ||
531 | __blk_mq_end_request(io_req->req, io_req->error); | ||
532 | } | ||
519 | kfree(io_req); | 533 | kfree(io_req); |
520 | } | 534 | } |
521 | } | 535 | } |
522 | |||
523 | reactivate_fd(thread_fd, UBD_IRQ); | ||
524 | } | 536 | } |
525 | 537 | ||
526 | static irqreturn_t ubd_intr(int irq, void *dev) | 538 | static irqreturn_t ubd_intr(int irq, void *dev) |
@@ -789,7 +801,7 @@ static int ubd_open_dev(struct ubd *ubd_dev) | |||
789 | 801 | ||
790 | if((fd == -ENOENT) && create_cow){ | 802 | if((fd == -ENOENT) && create_cow){ |
791 | fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file, | 803 | fd = create_cow_file(ubd_dev->file, ubd_dev->cow.file, |
792 | ubd_dev->openflags, 1 << 9, PAGE_SIZE, | 804 | ubd_dev->openflags, SECTOR_SIZE, PAGE_SIZE, |
793 | &ubd_dev->cow.bitmap_offset, | 805 | &ubd_dev->cow.bitmap_offset, |
794 | &ubd_dev->cow.bitmap_len, | 806 | &ubd_dev->cow.bitmap_len, |
795 | &ubd_dev->cow.data_offset); | 807 | &ubd_dev->cow.data_offset); |
@@ -830,6 +842,14 @@ static int ubd_open_dev(struct ubd *ubd_dev) | |||
830 | if(err < 0) goto error; | 842 | if(err < 0) goto error; |
831 | ubd_dev->cow.fd = err; | 843 | ubd_dev->cow.fd = err; |
832 | } | 844 | } |
845 | if (ubd_dev->no_trim == 0) { | ||
846 | ubd_dev->queue->limits.discard_granularity = SECTOR_SIZE; | ||
847 | ubd_dev->queue->limits.discard_alignment = SECTOR_SIZE; | ||
848 | blk_queue_max_discard_sectors(ubd_dev->queue, UBD_MAX_REQUEST); | ||
849 | blk_queue_max_write_zeroes_sectors(ubd_dev->queue, UBD_MAX_REQUEST); | ||
850 | blk_queue_flag_set(QUEUE_FLAG_DISCARD, ubd_dev->queue); | ||
851 | } | ||
852 | blk_queue_flag_set(QUEUE_FLAG_NONROT, ubd_dev->queue); | ||
833 | return 0; | 853 | return 0; |
834 | error: | 854 | error: |
835 | os_close_file(ubd_dev->fd); | 855 | os_close_file(ubd_dev->fd); |
@@ -882,7 +902,7 @@ static int ubd_disk_register(int major, u64 size, int unit, | |||
882 | return 0; | 902 | return 0; |
883 | } | 903 | } |
884 | 904 | ||
885 | #define ROUND_BLOCK(n) ((n + ((1 << 9) - 1)) & (-1 << 9)) | 905 | #define ROUND_BLOCK(n) ((n + (SECTOR_SIZE - 1)) & (-SECTOR_SIZE)) |
886 | 906 | ||
887 | static const struct blk_mq_ops ubd_mq_ops = { | 907 | static const struct blk_mq_ops ubd_mq_ops = { |
888 | .queue_rq = ubd_queue_rq, | 908 | .queue_rq = ubd_queue_rq, |
@@ -1234,10 +1254,10 @@ static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, | |||
1234 | __u64 bitmap_offset, unsigned long *bitmap_words, | 1254 | __u64 bitmap_offset, unsigned long *bitmap_words, |
1235 | __u64 bitmap_len) | 1255 | __u64 bitmap_len) |
1236 | { | 1256 | { |
1237 | __u64 sector = io_offset >> 9; | 1257 | __u64 sector = io_offset >> SECTOR_SHIFT; |
1238 | int i, update_bitmap = 0; | 1258 | int i, update_bitmap = 0; |
1239 | 1259 | ||
1240 | for(i = 0; i < length >> 9; i++){ | 1260 | for (i = 0; i < length >> SECTOR_SHIFT; i++) { |
1241 | if(cow_mask != NULL) | 1261 | if(cow_mask != NULL) |
1242 | ubd_set_bit(i, (unsigned char *) cow_mask); | 1262 | ubd_set_bit(i, (unsigned char *) cow_mask); |
1243 | if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) | 1263 | if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) |
@@ -1271,14 +1291,14 @@ static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, | |||
1271 | static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, | 1291 | static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, |
1272 | __u64 bitmap_offset, __u64 bitmap_len) | 1292 | __u64 bitmap_offset, __u64 bitmap_len) |
1273 | { | 1293 | { |
1274 | __u64 sector = req->offset >> 9; | 1294 | __u64 sector = req->offset >> SECTOR_SHIFT; |
1275 | int i; | 1295 | int i; |
1276 | 1296 | ||
1277 | if(req->length > (sizeof(req->sector_mask) * 8) << 9) | 1297 | if (req->length > (sizeof(req->sector_mask) * 8) << SECTOR_SHIFT) |
1278 | panic("Operation too long"); | 1298 | panic("Operation too long"); |
1279 | 1299 | ||
1280 | if(req->op == UBD_READ) { | 1300 | if (req_op(req->req) == REQ_OP_READ) { |
1281 | for(i = 0; i < req->length >> 9; i++){ | 1301 | for (i = 0; i < req->length >> SECTOR_SHIFT; i++) { |
1282 | if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) | 1302 | if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) |
1283 | ubd_set_bit(i, (unsigned char *) | 1303 | ubd_set_bit(i, (unsigned char *) |
1284 | &req->sector_mask); | 1304 | &req->sector_mask); |
@@ -1307,68 +1327,86 @@ static int ubd_queue_one_vec(struct blk_mq_hw_ctx *hctx, struct request *req, | |||
1307 | io_req->fds[0] = dev->fd; | 1327 | io_req->fds[0] = dev->fd; |
1308 | io_req->error = 0; | 1328 | io_req->error = 0; |
1309 | 1329 | ||
1310 | if (req_op(req) == REQ_OP_FLUSH) { | 1330 | if (bvec != NULL) { |
1311 | io_req->op = UBD_FLUSH; | ||
1312 | } else { | ||
1313 | io_req->fds[1] = dev->fd; | ||
1314 | io_req->cow_offset = -1; | ||
1315 | io_req->offset = off; | ||
1316 | io_req->length = bvec->bv_len; | ||
1317 | io_req->sector_mask = 0; | ||
1318 | io_req->op = rq_data_dir(req) == READ ? UBD_READ : UBD_WRITE; | ||
1319 | io_req->offsets[0] = 0; | ||
1320 | io_req->offsets[1] = dev->cow.data_offset; | ||
1321 | io_req->buffer = page_address(bvec->bv_page) + bvec->bv_offset; | 1331 | io_req->buffer = page_address(bvec->bv_page) + bvec->bv_offset; |
1322 | io_req->sectorsize = 1 << 9; | 1332 | io_req->length = bvec->bv_len; |
1323 | 1333 | } else { | |
1324 | if (dev->cow.file) { | 1334 | io_req->buffer = NULL; |
1325 | cowify_req(io_req, dev->cow.bitmap, | 1335 | io_req->length = blk_rq_bytes(req); |
1326 | dev->cow.bitmap_offset, dev->cow.bitmap_len); | ||
1327 | } | ||
1328 | } | 1336 | } |
1329 | 1337 | ||
1338 | io_req->sectorsize = SECTOR_SIZE; | ||
1339 | io_req->fds[1] = dev->fd; | ||
1340 | io_req->cow_offset = -1; | ||
1341 | io_req->offset = off; | ||
1342 | io_req->sector_mask = 0; | ||
1343 | io_req->offsets[0] = 0; | ||
1344 | io_req->offsets[1] = dev->cow.data_offset; | ||
1345 | |||
1346 | if (dev->cow.file) | ||
1347 | cowify_req(io_req, dev->cow.bitmap, | ||
1348 | dev->cow.bitmap_offset, dev->cow.bitmap_len); | ||
1349 | |||
1330 | ret = os_write_file(thread_fd, &io_req, sizeof(io_req)); | 1350 | ret = os_write_file(thread_fd, &io_req, sizeof(io_req)); |
1331 | if (ret != sizeof(io_req)) { | 1351 | if (ret != sizeof(io_req)) { |
1332 | if (ret != -EAGAIN) | 1352 | if (ret != -EAGAIN) |
1333 | pr_err("write to io thread failed: %d\n", -ret); | 1353 | pr_err("write to io thread failed: %d\n", -ret); |
1334 | kfree(io_req); | 1354 | kfree(io_req); |
1335 | } | 1355 | } |
1336 | |||
1337 | return ret; | 1356 | return ret; |
1338 | } | 1357 | } |
1339 | 1358 | ||
1359 | static int queue_rw_req(struct blk_mq_hw_ctx *hctx, struct request *req) | ||
1360 | { | ||
1361 | struct req_iterator iter; | ||
1362 | struct bio_vec bvec; | ||
1363 | int ret; | ||
1364 | u64 off = (u64)blk_rq_pos(req) << SECTOR_SHIFT; | ||
1365 | |||
1366 | rq_for_each_segment(bvec, req, iter) { | ||
1367 | ret = ubd_queue_one_vec(hctx, req, off, &bvec); | ||
1368 | if (ret < 0) | ||
1369 | return ret; | ||
1370 | off += bvec.bv_len; | ||
1371 | } | ||
1372 | return 0; | ||
1373 | } | ||
1374 | |||
1340 | static blk_status_t ubd_queue_rq(struct blk_mq_hw_ctx *hctx, | 1375 | static blk_status_t ubd_queue_rq(struct blk_mq_hw_ctx *hctx, |
1341 | const struct blk_mq_queue_data *bd) | 1376 | const struct blk_mq_queue_data *bd) |
1342 | { | 1377 | { |
1343 | struct ubd *ubd_dev = hctx->queue->queuedata; | 1378 | struct ubd *ubd_dev = hctx->queue->queuedata; |
1344 | struct request *req = bd->rq; | 1379 | struct request *req = bd->rq; |
1345 | int ret = 0; | 1380 | int ret = 0, res = BLK_STS_OK; |
1346 | 1381 | ||
1347 | blk_mq_start_request(req); | 1382 | blk_mq_start_request(req); |
1348 | 1383 | ||
1349 | spin_lock_irq(&ubd_dev->lock); | 1384 | spin_lock_irq(&ubd_dev->lock); |
1350 | 1385 | ||
1351 | if (req_op(req) == REQ_OP_FLUSH) { | 1386 | switch (req_op(req)) { |
1387 | /* operations with no lentgth/offset arguments */ | ||
1388 | case REQ_OP_FLUSH: | ||
1352 | ret = ubd_queue_one_vec(hctx, req, 0, NULL); | 1389 | ret = ubd_queue_one_vec(hctx, req, 0, NULL); |
1353 | } else { | 1390 | break; |
1354 | struct req_iterator iter; | 1391 | case REQ_OP_READ: |
1355 | struct bio_vec bvec; | 1392 | case REQ_OP_WRITE: |
1356 | u64 off = (u64)blk_rq_pos(req) << 9; | 1393 | ret = queue_rw_req(hctx, req); |
1357 | 1394 | break; | |
1358 | rq_for_each_segment(bvec, req, iter) { | 1395 | case REQ_OP_DISCARD: |
1359 | ret = ubd_queue_one_vec(hctx, req, off, &bvec); | 1396 | case REQ_OP_WRITE_ZEROES: |
1360 | if (ret < 0) | 1397 | ret = ubd_queue_one_vec(hctx, req, (u64)blk_rq_pos(req) << 9, NULL); |
1361 | goto out; | 1398 | break; |
1362 | off += bvec.bv_len; | 1399 | default: |
1363 | } | 1400 | WARN_ON_ONCE(1); |
1401 | res = BLK_STS_NOTSUPP; | ||
1364 | } | 1402 | } |
1365 | out: | 1403 | |
1366 | spin_unlock_irq(&ubd_dev->lock); | 1404 | spin_unlock_irq(&ubd_dev->lock); |
1367 | 1405 | ||
1368 | if (ret < 0) | 1406 | if (ret < 0) |
1369 | blk_mq_requeue_request(req, true); | 1407 | blk_mq_requeue_request(req, true); |
1370 | 1408 | ||
1371 | return BLK_STS_OK; | 1409 | return res; |
1372 | } | 1410 | } |
1373 | 1411 | ||
1374 | static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo) | 1412 | static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo) |
@@ -1413,39 +1451,60 @@ static int ubd_ioctl(struct block_device *bdev, fmode_t mode, | |||
1413 | return -EINVAL; | 1451 | return -EINVAL; |
1414 | } | 1452 | } |
1415 | 1453 | ||
1454 | static int map_error(int error_code) | ||
1455 | { | ||
1456 | switch (error_code) { | ||
1457 | case 0: | ||
1458 | return BLK_STS_OK; | ||
1459 | case ENOSYS: | ||
1460 | case EOPNOTSUPP: | ||
1461 | return BLK_STS_NOTSUPP; | ||
1462 | case ENOSPC: | ||
1463 | return BLK_STS_NOSPC; | ||
1464 | } | ||
1465 | return BLK_STS_IOERR; | ||
1466 | } | ||
1467 | |||
1468 | /* | ||
1469 | * Everything from here onwards *IS NOT PART OF THE KERNEL* | ||
1470 | * | ||
1471 | * The following functions are part of UML hypervisor code. | ||
1472 | * All functions from here onwards are executed as a helper | ||
1473 | * thread and are not allowed to execute any kernel functions. | ||
1474 | * | ||
1475 | * Any communication must occur strictly via shared memory and IPC. | ||
1476 | * | ||
1477 | * Do not add printks, locks, kernel memory operations, etc - it | ||
1478 | * will result in unpredictable behaviour and/or crashes. | ||
1479 | */ | ||
1480 | |||
1416 | static int update_bitmap(struct io_thread_req *req) | 1481 | static int update_bitmap(struct io_thread_req *req) |
1417 | { | 1482 | { |
1418 | int n; | 1483 | int n; |
1419 | 1484 | ||
1420 | if(req->cow_offset == -1) | 1485 | if(req->cow_offset == -1) |
1421 | return 0; | 1486 | return map_error(0); |
1422 | 1487 | ||
1423 | n = os_pwrite_file(req->fds[1], &req->bitmap_words, | 1488 | n = os_pwrite_file(req->fds[1], &req->bitmap_words, |
1424 | sizeof(req->bitmap_words), req->cow_offset); | 1489 | sizeof(req->bitmap_words), req->cow_offset); |
1425 | if(n != sizeof(req->bitmap_words)){ | 1490 | if (n != sizeof(req->bitmap_words)) |
1426 | printk("do_io - bitmap update failed, err = %d fd = %d\n", -n, | 1491 | return map_error(-n); |
1427 | req->fds[1]); | ||
1428 | return 1; | ||
1429 | } | ||
1430 | 1492 | ||
1431 | return 0; | 1493 | return map_error(0); |
1432 | } | 1494 | } |
1433 | 1495 | ||
1434 | static void do_io(struct io_thread_req *req) | 1496 | static void do_io(struct io_thread_req *req) |
1435 | { | 1497 | { |
1436 | char *buf; | 1498 | char *buf = NULL; |
1437 | unsigned long len; | 1499 | unsigned long len; |
1438 | int n, nsectors, start, end, bit; | 1500 | int n, nsectors, start, end, bit; |
1439 | __u64 off; | 1501 | __u64 off; |
1440 | 1502 | ||
1441 | if (req->op == UBD_FLUSH) { | 1503 | /* FLUSH is really a special case, we cannot "case" it with others */ |
1504 | |||
1505 | if (req_op(req->req) == REQ_OP_FLUSH) { | ||
1442 | /* fds[0] is always either the rw image or our cow file */ | 1506 | /* fds[0] is always either the rw image or our cow file */ |
1443 | n = os_sync_file(req->fds[0]); | 1507 | req->error = map_error(-os_sync_file(req->fds[0])); |
1444 | if (n != 0) { | ||
1445 | printk("do_io - sync failed err = %d " | ||
1446 | "fd = %d\n", -n, req->fds[0]); | ||
1447 | req->error = 1; | ||
1448 | } | ||
1449 | return; | 1508 | return; |
1450 | } | 1509 | } |
1451 | 1510 | ||
@@ -1462,30 +1521,42 @@ static void do_io(struct io_thread_req *req) | |||
1462 | off = req->offset + req->offsets[bit] + | 1521 | off = req->offset + req->offsets[bit] + |
1463 | start * req->sectorsize; | 1522 | start * req->sectorsize; |
1464 | len = (end - start) * req->sectorsize; | 1523 | len = (end - start) * req->sectorsize; |
1465 | buf = &req->buffer[start * req->sectorsize]; | 1524 | if (req->buffer != NULL) |
1525 | buf = &req->buffer[start * req->sectorsize]; | ||
1466 | 1526 | ||
1467 | if(req->op == UBD_READ){ | 1527 | switch (req_op(req->req)) { |
1528 | case REQ_OP_READ: | ||
1468 | n = 0; | 1529 | n = 0; |
1469 | do { | 1530 | do { |
1470 | buf = &buf[n]; | 1531 | buf = &buf[n]; |
1471 | len -= n; | 1532 | len -= n; |
1472 | n = os_pread_file(req->fds[bit], buf, len, off); | 1533 | n = os_pread_file(req->fds[bit], buf, len, off); |
1473 | if (n < 0) { | 1534 | if (n < 0) { |
1474 | printk("do_io - read failed, err = %d " | 1535 | req->error = map_error(-n); |
1475 | "fd = %d\n", -n, req->fds[bit]); | ||
1476 | req->error = 1; | ||
1477 | return; | 1536 | return; |
1478 | } | 1537 | } |
1479 | } while((n < len) && (n != 0)); | 1538 | } while((n < len) && (n != 0)); |
1480 | if (n < len) memset(&buf[n], 0, len - n); | 1539 | if (n < len) memset(&buf[n], 0, len - n); |
1481 | } else { | 1540 | break; |
1541 | case REQ_OP_WRITE: | ||
1482 | n = os_pwrite_file(req->fds[bit], buf, len, off); | 1542 | n = os_pwrite_file(req->fds[bit], buf, len, off); |
1483 | if(n != len){ | 1543 | if(n != len){ |
1484 | printk("do_io - write failed err = %d " | 1544 | req->error = map_error(-n); |
1485 | "fd = %d\n", -n, req->fds[bit]); | 1545 | return; |
1486 | req->error = 1; | 1546 | } |
1547 | break; | ||
1548 | case REQ_OP_DISCARD: | ||
1549 | case REQ_OP_WRITE_ZEROES: | ||
1550 | n = os_falloc_punch(req->fds[bit], off, len); | ||
1551 | if (n) { | ||
1552 | req->error = map_error(-n); | ||
1487 | return; | 1553 | return; |
1488 | } | 1554 | } |
1555 | break; | ||
1556 | default: | ||
1557 | WARN_ON_ONCE(1); | ||
1558 | req->error = BLK_STS_NOTSUPP; | ||
1559 | return; | ||
1489 | } | 1560 | } |
1490 | 1561 | ||
1491 | start = end; | 1562 | start = end; |
@@ -1520,11 +1591,6 @@ int io_thread(void *arg) | |||
1520 | if (n == -EAGAIN) { | 1591 | if (n == -EAGAIN) { |
1521 | ubd_read_poll(-1); | 1592 | ubd_read_poll(-1); |
1522 | continue; | 1593 | continue; |
1523 | } else { | ||
1524 | printk("io_thread - read failed, fd = %d, " | ||
1525 | "err = %d," | ||
1526 | "reminder = %d\n", | ||
1527 | kernel_fd, -n, io_remainder_size); | ||
1528 | } | 1594 | } |
1529 | } | 1595 | } |
1530 | 1596 | ||
@@ -1539,11 +1605,6 @@ int io_thread(void *arg) | |||
1539 | res = os_write_file(kernel_fd, ((char *) io_req_buffer) + written, n); | 1605 | res = os_write_file(kernel_fd, ((char *) io_req_buffer) + written, n); |
1540 | if (res >= 0) { | 1606 | if (res >= 0) { |
1541 | written += res; | 1607 | written += res; |
1542 | } else { | ||
1543 | if (res != -EAGAIN) { | ||
1544 | printk("io_thread - write failed, fd = %d, " | ||
1545 | "err = %d\n", kernel_fd, -n); | ||
1546 | } | ||
1547 | } | 1608 | } |
1548 | if (written < n) { | 1609 | if (written < n) { |
1549 | ubd_write_poll(-1); | 1610 | ubd_write_poll(-1); |
diff --git a/arch/um/drivers/vector_user.c b/arch/um/drivers/vector_user.c index 3d8cdbdb4e66..d2c17dd74620 100644 --- a/arch/um/drivers/vector_user.c +++ b/arch/um/drivers/vector_user.c | |||
@@ -25,11 +25,13 @@ | |||
25 | #include <linux/if_packet.h> | 25 | #include <linux/if_packet.h> |
26 | #include <sys/socket.h> | 26 | #include <sys/socket.h> |
27 | #include <sys/wait.h> | 27 | #include <sys/wait.h> |
28 | #include <sys/uio.h> | ||
28 | #include <linux/virtio_net.h> | 29 | #include <linux/virtio_net.h> |
29 | #include <netdb.h> | 30 | #include <netdb.h> |
30 | #include <stdlib.h> | 31 | #include <stdlib.h> |
31 | #include <os.h> | 32 | #include <os.h> |
32 | #include <um_malloc.h> | 33 | #include <um_malloc.h> |
34 | #include <sys/uio.h> | ||
33 | #include "vector_user.h" | 35 | #include "vector_user.h" |
34 | 36 | ||
35 | #define ID_GRE 0 | 37 | #define ID_GRE 0 |
diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild index b10dde6cb793..00bcbe2326d9 100644 --- a/arch/um/include/asm/Kbuild +++ b/arch/um/include/asm/Kbuild | |||
@@ -10,9 +10,7 @@ generic-y += exec.h | |||
10 | generic-y += extable.h | 10 | generic-y += extable.h |
11 | generic-y += ftrace.h | 11 | generic-y += ftrace.h |
12 | generic-y += futex.h | 12 | generic-y += futex.h |
13 | generic-y += hardirq.h | ||
14 | generic-y += hw_irq.h | 13 | generic-y += hw_irq.h |
15 | generic-y += io.h | ||
16 | generic-y += irq_regs.h | 14 | generic-y += irq_regs.h |
17 | generic-y += irq_work.h | 15 | generic-y += irq_work.h |
18 | generic-y += kdebug.h | 16 | generic-y += kdebug.h |
diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h index 7485398d0737..9c04562310b3 100644 --- a/arch/um/include/asm/pgtable.h +++ b/arch/um/include/asm/pgtable.h | |||
@@ -197,12 +197,17 @@ static inline pte_t pte_mkold(pte_t pte) | |||
197 | 197 | ||
198 | static inline pte_t pte_wrprotect(pte_t pte) | 198 | static inline pte_t pte_wrprotect(pte_t pte) |
199 | { | 199 | { |
200 | pte_clear_bits(pte, _PAGE_RW); | 200 | if (likely(pte_get_bits(pte, _PAGE_RW))) |
201 | pte_clear_bits(pte, _PAGE_RW); | ||
202 | else | ||
203 | return pte; | ||
201 | return(pte_mknewprot(pte)); | 204 | return(pte_mknewprot(pte)); |
202 | } | 205 | } |
203 | 206 | ||
204 | static inline pte_t pte_mkread(pte_t pte) | 207 | static inline pte_t pte_mkread(pte_t pte) |
205 | { | 208 | { |
209 | if (unlikely(pte_get_bits(pte, _PAGE_USER))) | ||
210 | return pte; | ||
206 | pte_set_bits(pte, _PAGE_USER); | 211 | pte_set_bits(pte, _PAGE_USER); |
207 | return(pte_mknewprot(pte)); | 212 | return(pte_mknewprot(pte)); |
208 | } | 213 | } |
@@ -221,6 +226,8 @@ static inline pte_t pte_mkyoung(pte_t pte) | |||
221 | 226 | ||
222 | static inline pte_t pte_mkwrite(pte_t pte) | 227 | static inline pte_t pte_mkwrite(pte_t pte) |
223 | { | 228 | { |
229 | if (unlikely(pte_get_bits(pte, _PAGE_RW))) | ||
230 | return pte; | ||
224 | pte_set_bits(pte, _PAGE_RW); | 231 | pte_set_bits(pte, _PAGE_RW); |
225 | return(pte_mknewprot(pte)); | 232 | return(pte_mknewprot(pte)); |
226 | } | 233 | } |
diff --git a/arch/um/include/shared/irq_user.h b/arch/um/include/shared/irq_user.h index a7a6120f19d5..e7242a0ae489 100644 --- a/arch/um/include/shared/irq_user.h +++ b/arch/um/include/shared/irq_user.h | |||
@@ -31,7 +31,6 @@ struct irq_fd { | |||
31 | struct siginfo; | 31 | struct siginfo; |
32 | extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); | 32 | extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); |
33 | extern void free_irq_by_fd(int fd); | 33 | extern void free_irq_by_fd(int fd); |
34 | extern void reactivate_fd(int fd, int irqnum); | ||
35 | extern void deactivate_fd(int fd, int irqnum); | 34 | extern void deactivate_fd(int fd, int irqnum); |
36 | extern int deactivate_all_fds(void); | 35 | extern int deactivate_all_fds(void); |
37 | extern int activate_ipi(int fd, int pid); | 36 | extern int activate_ipi(int fd, int pid); |
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index 048ae37eb5aa..ebf23012a59b 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h | |||
@@ -175,6 +175,7 @@ extern int os_fchange_dir(int fd); | |||
175 | extern unsigned os_major(unsigned long long dev); | 175 | extern unsigned os_major(unsigned long long dev); |
176 | extern unsigned os_minor(unsigned long long dev); | 176 | extern unsigned os_minor(unsigned long long dev); |
177 | extern unsigned long long os_makedev(unsigned major, unsigned minor); | 177 | extern unsigned long long os_makedev(unsigned major, unsigned minor); |
178 | extern int os_falloc_punch(int fd, unsigned long long offset, int count); | ||
178 | 179 | ||
179 | /* start_up.c */ | 180 | /* start_up.c */ |
180 | extern void os_early_checks(void); | 181 | extern void os_early_checks(void); |
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 8360fa3f676d..f4874b7ec503 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c | |||
@@ -350,11 +350,6 @@ static void free_irq_by_irq_and_dev(unsigned int irq, void *dev) | |||
350 | } | 350 | } |
351 | 351 | ||
352 | 352 | ||
353 | void reactivate_fd(int fd, int irqnum) | ||
354 | { | ||
355 | /** NOP - we do auto-EOI now **/ | ||
356 | } | ||
357 | |||
358 | void deactivate_fd(int fd, int irqnum) | 353 | void deactivate_fd(int fd, int irqnum) |
359 | { | 354 | { |
360 | struct irq_entry *to_free; | 355 | struct irq_entry *to_free; |
@@ -449,7 +444,6 @@ int um_request_irq(unsigned int irq, int fd, int type, | |||
449 | } | 444 | } |
450 | 445 | ||
451 | EXPORT_SYMBOL(um_request_irq); | 446 | EXPORT_SYMBOL(um_request_irq); |
452 | EXPORT_SYMBOL(reactivate_fd); | ||
453 | 447 | ||
454 | /* | 448 | /* |
455 | * irq_chip must define at least enable/disable and ack when | 449 | * irq_chip must define at least enable/disable and ack when |
diff --git a/arch/um/kernel/sigio.c b/arch/um/kernel/sigio.c index b5e0cbb34382..3fb6a4041ed6 100644 --- a/arch/um/kernel/sigio.c +++ b/arch/um/kernel/sigio.c | |||
@@ -16,7 +16,6 @@ static irqreturn_t sigio_interrupt(int irq, void *data) | |||
16 | char c; | 16 | char c; |
17 | 17 | ||
18 | os_read_file(sigio_irq_fd, &c, sizeof(c)); | 18 | os_read_file(sigio_irq_fd, &c, sizeof(c)); |
19 | reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ); | ||
20 | return IRQ_HANDLED; | 19 | return IRQ_HANDLED; |
21 | } | 20 | } |
22 | 21 | ||
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index d450797a3a7c..7f06fdbc7ee1 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c | |||
@@ -62,27 +62,28 @@ static int do_op_one_page(unsigned long addr, int len, int is_write, | |||
62 | jmp_buf buf; | 62 | jmp_buf buf; |
63 | struct page *page; | 63 | struct page *page; |
64 | pte_t *pte; | 64 | pte_t *pte; |
65 | int n, faulted; | 65 | int n; |
66 | 66 | ||
67 | pte = maybe_map(addr, is_write); | 67 | pte = maybe_map(addr, is_write); |
68 | if (pte == NULL) | 68 | if (pte == NULL) |
69 | return -1; | 69 | return -1; |
70 | 70 | ||
71 | page = pte_page(*pte); | 71 | page = pte_page(*pte); |
72 | #ifdef CONFIG_64BIT | ||
73 | pagefault_disable(); | ||
74 | addr = (unsigned long) page_address(page) + | ||
75 | (addr & ~PAGE_MASK); | ||
76 | #else | ||
72 | addr = (unsigned long) kmap_atomic(page) + | 77 | addr = (unsigned long) kmap_atomic(page) + |
73 | (addr & ~PAGE_MASK); | 78 | (addr & ~PAGE_MASK); |
79 | #endif | ||
80 | n = (*op)(addr, len, arg); | ||
74 | 81 | ||
75 | current->thread.fault_catcher = &buf; | 82 | #ifdef CONFIG_64BIT |
76 | 83 | pagefault_enable(); | |
77 | faulted = UML_SETJMP(&buf); | 84 | #else |
78 | if (faulted == 0) | ||
79 | n = (*op)(addr, len, arg); | ||
80 | else | ||
81 | n = -1; | ||
82 | |||
83 | current->thread.fault_catcher = NULL; | ||
84 | |||
85 | kunmap_atomic((void *)addr); | 85 | kunmap_atomic((void *)addr); |
86 | #endif | ||
86 | 87 | ||
87 | return n; | 88 | return n; |
88 | } | 89 | } |
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index 37508b190106..8347161c2ae0 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c | |||
@@ -37,17 +37,19 @@ struct host_vm_change { | |||
37 | } mprotect; | 37 | } mprotect; |
38 | } u; | 38 | } u; |
39 | } ops[1]; | 39 | } ops[1]; |
40 | int userspace; | ||
40 | int index; | 41 | int index; |
41 | struct mm_id *id; | 42 | struct mm_struct *mm; |
42 | void *data; | 43 | void *data; |
43 | int force; | 44 | int force; |
44 | }; | 45 | }; |
45 | 46 | ||
46 | #define INIT_HVC(mm, force) \ | 47 | #define INIT_HVC(mm, force, userspace) \ |
47 | ((struct host_vm_change) \ | 48 | ((struct host_vm_change) \ |
48 | { .ops = { { .type = NONE } }, \ | 49 | { .ops = { { .type = NONE } }, \ |
49 | .id = &mm->context.id, \ | 50 | .mm = mm, \ |
50 | .data = NULL, \ | 51 | .data = NULL, \ |
52 | .userspace = userspace, \ | ||
51 | .index = 0, \ | 53 | .index = 0, \ |
52 | .force = force }) | 54 | .force = force }) |
53 | 55 | ||
@@ -68,18 +70,40 @@ static int do_ops(struct host_vm_change *hvc, int end, | |||
68 | op = &hvc->ops[i]; | 70 | op = &hvc->ops[i]; |
69 | switch (op->type) { | 71 | switch (op->type) { |
70 | case MMAP: | 72 | case MMAP: |
71 | ret = map(hvc->id, op->u.mmap.addr, op->u.mmap.len, | 73 | if (hvc->userspace) |
72 | op->u.mmap.prot, op->u.mmap.fd, | 74 | ret = map(&hvc->mm->context.id, op->u.mmap.addr, |
73 | op->u.mmap.offset, finished, &hvc->data); | 75 | op->u.mmap.len, op->u.mmap.prot, |
76 | op->u.mmap.fd, | ||
77 | op->u.mmap.offset, finished, | ||
78 | &hvc->data); | ||
79 | else | ||
80 | map_memory(op->u.mmap.addr, op->u.mmap.offset, | ||
81 | op->u.mmap.len, 1, 1, 1); | ||
74 | break; | 82 | break; |
75 | case MUNMAP: | 83 | case MUNMAP: |
76 | ret = unmap(hvc->id, op->u.munmap.addr, | 84 | if (hvc->userspace) |
77 | op->u.munmap.len, finished, &hvc->data); | 85 | ret = unmap(&hvc->mm->context.id, |
86 | op->u.munmap.addr, | ||
87 | op->u.munmap.len, finished, | ||
88 | &hvc->data); | ||
89 | else | ||
90 | ret = os_unmap_memory( | ||
91 | (void *) op->u.munmap.addr, | ||
92 | op->u.munmap.len); | ||
93 | |||
78 | break; | 94 | break; |
79 | case MPROTECT: | 95 | case MPROTECT: |
80 | ret = protect(hvc->id, op->u.mprotect.addr, | 96 | if (hvc->userspace) |
81 | op->u.mprotect.len, op->u.mprotect.prot, | 97 | ret = protect(&hvc->mm->context.id, |
82 | finished, &hvc->data); | 98 | op->u.mprotect.addr, |
99 | op->u.mprotect.len, | ||
100 | op->u.mprotect.prot, | ||
101 | finished, &hvc->data); | ||
102 | else | ||
103 | ret = os_protect_memory( | ||
104 | (void *) op->u.mprotect.addr, | ||
105 | op->u.mprotect.len, | ||
106 | 1, 1, 1); | ||
83 | break; | 107 | break; |
84 | default: | 108 | default: |
85 | printk(KERN_ERR "Unknown op type %d in do_ops\n", | 109 | printk(KERN_ERR "Unknown op type %d in do_ops\n", |
@@ -100,9 +124,12 @@ static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, | |||
100 | { | 124 | { |
101 | __u64 offset; | 125 | __u64 offset; |
102 | struct host_vm_op *last; | 126 | struct host_vm_op *last; |
103 | int fd, ret = 0; | 127 | int fd = -1, ret = 0; |
104 | 128 | ||
105 | fd = phys_mapping(phys, &offset); | 129 | if (hvc->userspace) |
130 | fd = phys_mapping(phys, &offset); | ||
131 | else | ||
132 | offset = phys; | ||
106 | if (hvc->index != 0) { | 133 | if (hvc->index != 0) { |
107 | last = &hvc->ops[hvc->index - 1]; | 134 | last = &hvc->ops[hvc->index - 1]; |
108 | if ((last->type == MMAP) && | 135 | if ((last->type == MMAP) && |
@@ -215,10 +242,11 @@ static inline int update_pte_range(pmd_t *pmd, unsigned long addr, | |||
215 | prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) | | 242 | prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) | |
216 | (x ? UM_PROT_EXEC : 0)); | 243 | (x ? UM_PROT_EXEC : 0)); |
217 | if (hvc->force || pte_newpage(*pte)) { | 244 | if (hvc->force || pte_newpage(*pte)) { |
218 | if (pte_present(*pte)) | 245 | if (pte_present(*pte)) { |
219 | ret = add_mmap(addr, pte_val(*pte) & PAGE_MASK, | 246 | if (pte_newpage(*pte)) |
220 | PAGE_SIZE, prot, hvc); | 247 | ret = add_mmap(addr, pte_val(*pte) & PAGE_MASK, |
221 | else | 248 | PAGE_SIZE, prot, hvc); |
249 | } else | ||
222 | ret = add_munmap(addr, PAGE_SIZE, hvc); | 250 | ret = add_munmap(addr, PAGE_SIZE, hvc); |
223 | } else if (pte_newprot(*pte)) | 251 | } else if (pte_newprot(*pte)) |
224 | ret = add_mprotect(addr, PAGE_SIZE, prot, hvc); | 252 | ret = add_mprotect(addr, PAGE_SIZE, prot, hvc); |
@@ -277,9 +305,9 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, | |||
277 | pgd_t *pgd; | 305 | pgd_t *pgd; |
278 | struct host_vm_change hvc; | 306 | struct host_vm_change hvc; |
279 | unsigned long addr = start_addr, next; | 307 | unsigned long addr = start_addr, next; |
280 | int ret = 0; | 308 | int ret = 0, userspace = 1; |
281 | 309 | ||
282 | hvc = INIT_HVC(mm, force); | 310 | hvc = INIT_HVC(mm, force, userspace); |
283 | pgd = pgd_offset(mm, addr); | 311 | pgd = pgd_offset(mm, addr); |
284 | do { | 312 | do { |
285 | next = pgd_addr_end(addr, end_addr); | 313 | next = pgd_addr_end(addr, end_addr); |
@@ -314,9 +342,11 @@ static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) | |||
314 | pmd_t *pmd; | 342 | pmd_t *pmd; |
315 | pte_t *pte; | 343 | pte_t *pte; |
316 | unsigned long addr, last; | 344 | unsigned long addr, last; |
317 | int updated = 0, err; | 345 | int updated = 0, err = 0, force = 0, userspace = 0; |
346 | struct host_vm_change hvc; | ||
318 | 347 | ||
319 | mm = &init_mm; | 348 | mm = &init_mm; |
349 | hvc = INIT_HVC(mm, force, userspace); | ||
320 | for (addr = start; addr < end;) { | 350 | for (addr = start; addr < end;) { |
321 | pgd = pgd_offset(mm, addr); | 351 | pgd = pgd_offset(mm, addr); |
322 | if (!pgd_present(*pgd)) { | 352 | if (!pgd_present(*pgd)) { |
@@ -325,8 +355,7 @@ static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) | |||
325 | last = end; | 355 | last = end; |
326 | if (pgd_newpage(*pgd)) { | 356 | if (pgd_newpage(*pgd)) { |
327 | updated = 1; | 357 | updated = 1; |
328 | err = os_unmap_memory((void *) addr, | 358 | err = add_munmap(addr, last - addr, &hvc); |
329 | last - addr); | ||
330 | if (err < 0) | 359 | if (err < 0) |
331 | panic("munmap failed, errno = %d\n", | 360 | panic("munmap failed, errno = %d\n", |
332 | -err); | 361 | -err); |
@@ -342,8 +371,7 @@ static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) | |||
342 | last = end; | 371 | last = end; |
343 | if (pud_newpage(*pud)) { | 372 | if (pud_newpage(*pud)) { |
344 | updated = 1; | 373 | updated = 1; |
345 | err = os_unmap_memory((void *) addr, | 374 | err = add_munmap(addr, last - addr, &hvc); |
346 | last - addr); | ||
347 | if (err < 0) | 375 | if (err < 0) |
348 | panic("munmap failed, errno = %d\n", | 376 | panic("munmap failed, errno = %d\n", |
349 | -err); | 377 | -err); |
@@ -359,8 +387,7 @@ static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) | |||
359 | last = end; | 387 | last = end; |
360 | if (pmd_newpage(*pmd)) { | 388 | if (pmd_newpage(*pmd)) { |
361 | updated = 1; | 389 | updated = 1; |
362 | err = os_unmap_memory((void *) addr, | 390 | err = add_munmap(addr, last - addr, &hvc); |
363 | last - addr); | ||
364 | if (err < 0) | 391 | if (err < 0) |
365 | panic("munmap failed, errno = %d\n", | 392 | panic("munmap failed, errno = %d\n", |
366 | -err); | 393 | -err); |
@@ -372,22 +399,25 @@ static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) | |||
372 | pte = pte_offset_kernel(pmd, addr); | 399 | pte = pte_offset_kernel(pmd, addr); |
373 | if (!pte_present(*pte) || pte_newpage(*pte)) { | 400 | if (!pte_present(*pte) || pte_newpage(*pte)) { |
374 | updated = 1; | 401 | updated = 1; |
375 | err = os_unmap_memory((void *) addr, | 402 | err = add_munmap(addr, PAGE_SIZE, &hvc); |
376 | PAGE_SIZE); | ||
377 | if (err < 0) | 403 | if (err < 0) |
378 | panic("munmap failed, errno = %d\n", | 404 | panic("munmap failed, errno = %d\n", |
379 | -err); | 405 | -err); |
380 | if (pte_present(*pte)) | 406 | if (pte_present(*pte)) |
381 | map_memory(addr, | 407 | err = add_mmap(addr, pte_val(*pte) & PAGE_MASK, |
382 | pte_val(*pte) & PAGE_MASK, | 408 | PAGE_SIZE, 0, &hvc); |
383 | PAGE_SIZE, 1, 1, 1); | ||
384 | } | 409 | } |
385 | else if (pte_newprot(*pte)) { | 410 | else if (pte_newprot(*pte)) { |
386 | updated = 1; | 411 | updated = 1; |
387 | os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1); | 412 | err = add_mprotect(addr, PAGE_SIZE, 0, &hvc); |
388 | } | 413 | } |
389 | addr += PAGE_SIZE; | 414 | addr += PAGE_SIZE; |
390 | } | 415 | } |
416 | if (!err) | ||
417 | err = do_ops(&hvc, hvc.index, 1); | ||
418 | |||
419 | if (err < 0) | ||
420 | panic("flush_tlb_kernel failed, errno = %d\n", err); | ||
391 | return updated; | 421 | return updated; |
392 | } | 422 | } |
393 | 423 | ||
@@ -491,6 +521,13 @@ pte_t *addr_pte(struct task_struct *task, unsigned long addr) | |||
491 | 521 | ||
492 | void flush_tlb_all(void) | 522 | void flush_tlb_all(void) |
493 | { | 523 | { |
524 | /* | ||
525 | * Don't bother flushing if this address space is about to be | ||
526 | * destroyed. | ||
527 | */ | ||
528 | if (atomic_read(¤t->mm->mm_users) == 0) | ||
529 | return; | ||
530 | |||
494 | flush_tlb_mm(current->mm); | 531 | flush_tlb_mm(current->mm); |
495 | } | 532 | } |
496 | 533 | ||
@@ -512,6 +549,13 @@ void __flush_tlb_one(unsigned long addr) | |||
512 | static void fix_range(struct mm_struct *mm, unsigned long start_addr, | 549 | static void fix_range(struct mm_struct *mm, unsigned long start_addr, |
513 | unsigned long end_addr, int force) | 550 | unsigned long end_addr, int force) |
514 | { | 551 | { |
552 | /* | ||
553 | * Don't bother flushing if this address space is about to be | ||
554 | * destroyed. | ||
555 | */ | ||
556 | if (atomic_read(&mm->mm_users) == 0) | ||
557 | return; | ||
558 | |||
515 | fix_range_common(mm, start_addr, end_addr, force); | 559 | fix_range_common(mm, start_addr, end_addr, force); |
516 | } | 560 | } |
517 | 561 | ||
@@ -527,13 +571,6 @@ EXPORT_SYMBOL(flush_tlb_range); | |||
527 | void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, | 571 | void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, |
528 | unsigned long end) | 572 | unsigned long end) |
529 | { | 573 | { |
530 | /* | ||
531 | * Don't bother flushing if this address space is about to be | ||
532 | * destroyed. | ||
533 | */ | ||
534 | if (atomic_read(&mm->mm_users) == 0) | ||
535 | return; | ||
536 | |||
537 | fix_range(mm, start, end, 0); | 574 | fix_range(mm, start, end, 0); |
538 | } | 575 | } |
539 | 576 | ||
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index c0197097c86e..f25b110d4e70 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c | |||
@@ -610,3 +610,13 @@ unsigned long long os_makedev(unsigned major, unsigned minor) | |||
610 | { | 610 | { |
611 | return makedev(major, minor); | 611 | return makedev(major, minor); |
612 | } | 612 | } |
613 | |||
614 | int os_falloc_punch(int fd, unsigned long long offset, int len) | ||
615 | { | ||
616 | int n = fallocate(fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, offset, len); | ||
617 | |||
618 | if (n < 0) | ||
619 | return -errno; | ||
620 | return n; | ||
621 | } | ||
622 | |||