diff options
-rw-r--r-- | devio/devpager.c | 38 |
1 files changed, 26 insertions, 12 deletions
diff --git a/devio/devpager.c b/devio/devpager.c index 9ed5bd3e..ab3da34a 100644 --- a/devio/devpager.c +++ b/devio/devpager.c @@ -41,26 +41,36 @@ error_t pager_read_page(struct user_pager_info *upi, vm_offset_t page, vm_address_t *buf, int *writelock) { + error_t err; int read; /* bytes actually read */ + int want = vm_page_size; /* bytes we want to read */ struct dev *dev = (struct dev *)upi; - error_t err = - device_read(dev->port, - 0, page / dev->dev_block_size, vm_page_size, - (io_buf_ptr_t *)buf, &read); + + if (page + want > dev->size) + /* Read a partial page if necessary to avoid reading off the end. */ + want = dev->size - page; + + err = device_read(dev->port, 0, page / dev->dev_block_size, want, + (io_buf_ptr_t *)buf, &read); #ifdef MSG if (debug) { mutex_lock(&debug_lock); fprintf(debug, "device_read(%d, %d) [pager] => %s, %s, %d\n", - page / dev->dev_block_size, vm_page_size, + page / dev->dev_block_size, want, strerror(err), err ? "-" : brep(*buf, read), read); mutex_unlock(&debug_lock); } #endif + if (!err && want < vm_page_size) + /* Zero anything we didn't read. Allocation only happens in page-size + multiples, so we know we can write there. */ + bzero((char *)*buf + want, vm_page_size - want); + *writelock = (dev->flags & DEV_READONLY); - if (err || read < vm_page_size) + if (err || read < want) return EIO; else return 0; @@ -79,12 +89,16 @@ pager_write_page(struct user_pager_info *upi, return EROFS; else { + error_t err; int written; - error_t err = - device_write(dev->port, - 0, page / dev->dev_block_size, - (io_buf_ptr_t)buf, vm_page_size, - &written); + int want = vm_page_size; + + if (page + want > dev->size) + /* Write a partial page if necessary to avoid reading off the end. */ + want = dev->size - page; + + err = device_write(dev->port, 0, page / dev->dev_block_size, + (io_buf_ptr_t)buf, want, &written); #ifdef MSG if (debug) { @@ -99,7 +113,7 @@ pager_write_page(struct user_pager_info *upi, vm_deallocate(mach_task_self(), buf, vm_page_size); - if (err || written < vm_page_size) + if (err || written < want) return EIO; else return 0; |