diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2021-08-26 08:51:58 +0300 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2021-08-26 17:57:05 +0300 |
commit | 5b75faefeec9c1fb67fd1067d78c2bdff3aa7a45 (patch) | |
tree | 388f93765da88304b2d80ecf6cf282e4111d344a /os_dep.c | |
parent | 2bae6c818e4e61dd9f62fdffc0cc1621a5ba40a9 (diff) | |
download | bdwgc-5b75faefeec9c1fb67fd1067d78c2bdff3aa7a45.tar.gz |
Fix incomplete read in GC_soft_read_dirty
(fix of commit de8e2e986)
Issue #265 (bdwgc).
* os_dep.c [SOFT_VDB] (soft_set_grungy_pages): New static function
(move code from outer for statement in GC_soft_read_dirty); add loop
to call READ() while region address limit is not reached (do no modify
limit variable value, update pm_ofs variable value on each iteration);
abort if read size is not multiple of entry size.
Diffstat (limited to 'os_dep.c')
-rw-r--r-- | os_dep.c | 90 |
1 files changed, 52 insertions, 38 deletions
@@ -3761,6 +3761,56 @@ GC_INLINE void GC_proc_read_dirty(GC_bool output_unneeded) # define PM_SOFTDIRTY_OFS (55/8) # define PM_SOFTDIRTY_MASK (1<<(55%8)) + static void soft_set_grungy_pages(ptr_t vaddr, ptr_t limit) + { + ssize_t res; + word limit_buf; + word pm_ofs = (word)vaddr / GC_page_size * PAGEMAP_ENTRY_SZ; + unsigned char *bufp; + + /* TODO: page-aligned lseek, read less bytes if possible. */ + /* TODO: don't read if data already in buf */ + if (lseek(pagemap_fd, (off_t)pm_ofs, SEEK_SET) == (off_t)(-1)) + ABORT_ARG2("Failed to lseek /proc/self/pagemap", + ": offset = %lu, errno = %d", + (unsigned long)pm_ofs, errno); + + while ((word)vaddr < (word)limit) { + res = PROC_READ(pagemap_fd, soft_vdb_buf, VDB_BUF_SZ); + if (res < PAGEMAP_ENTRY_SZ) + ABORT_ARG1("Failed to read /proc/self/pagemap", + ": errno = %d", res < 0 ? errno : 0); + if ((res % PAGEMAP_ENTRY_SZ) != 0) + ABORT("Unsupported: incomplete read of pagemap not multiple" + " of entry size"); + + pm_ofs += (size_t)res; + limit_buf = pm_ofs / PAGEMAP_ENTRY_SZ * GC_page_size; + if (limit_buf > (word)limit) + limit_buf = (word)limit; + + for (bufp = soft_vdb_buf; (word)vaddr < limit_buf; + vaddr += GC_page_size, bufp += PAGEMAP_ENTRY_SZ) { + if ((bufp[PM_SOFTDIRTY_OFS] & PM_SOFTDIRTY_MASK) != 0) { + struct hblk * h; + ptr_t next_vaddr = vaddr + GC_page_size; + + /* If the bit is set, the respective PTE was written to */ + /* since clearing the soft-dirty bits. */ +# ifdef DEBUG_DIRTY_BITS + GC_log_printf("dirty page at: %p\n", (void *)vaddr); +# endif + for (h = (struct hblk *)vaddr; + (word)h < (word)next_vaddr; h++) { + word index = PHT_HASH(h); + set_pht_entry_from_index(GC_grungy_pages, index); + } + } + } + /* Read the next portion of pagemap file if incomplete. */ + } + } + GC_INLINE void GC_soft_read_dirty(GC_bool output_unneeded) { ssize_t res; @@ -3773,44 +3823,8 @@ GC_INLINE void GC_proc_read_dirty(GC_bool output_unneeded) for (i = 0; i != GC_n_heap_sects; ++i) { ptr_t vaddr = GC_heap_sects[i].hs_start; - ptr_t limit = vaddr + GC_heap_sects[i].hs_bytes; - word limit_buf; - word pm_ofs = (word)vaddr / GC_page_size * PAGEMAP_ENTRY_SZ; - unsigned char *bufp; - - /* TODO: page-aligned lseek, read less bytes if possible. */ - /* TODO: don't read if data already in buf */ - if (lseek(pagemap_fd, (off_t)pm_ofs, SEEK_SET) == (off_t)(-1)) - ABORT_ARG2("Failed to lseek /proc/self/pagemap", - ": offset = %lu, errno = %d", - (unsigned long)pm_ofs, errno); - res = PROC_READ(pagemap_fd, soft_vdb_buf, VDB_BUF_SZ); - if (res < PAGEMAP_ENTRY_SZ) - ABORT_ARG1("Failed to read /proc/self/pagemap", - ": errno = %d", res < 0 ? errno : 0); - - limit_buf = (pm_ofs + (size_t)res) / PAGEMAP_ENTRY_SZ * GC_page_size; - if ((word)limit > limit_buf) - limit = (ptr_t)limit_buf; - - for (bufp = soft_vdb_buf; (word)vaddr < (word)limit; - vaddr += GC_page_size, bufp += PAGEMAP_ENTRY_SZ) { - if ((bufp[PM_SOFTDIRTY_OFS] & PM_SOFTDIRTY_MASK) != 0) { - struct hblk * h; - ptr_t next_vaddr = vaddr + GC_page_size; - - /* If the bit is set, the respective PTE was written to */ - /* since clearing the soft-dirty bits. */ -# ifdef DEBUG_DIRTY_BITS - GC_log_printf("dirty page at: %p\n", (void *)vaddr); -# endif - for (h = (struct hblk *)vaddr; - (word)h < (word)next_vaddr; h++) { - word index = PHT_HASH(h); - set_pht_entry_from_index(GC_grungy_pages, index); - } - } - } + + soft_set_grungy_pages(vaddr, vaddr + GC_heap_sects[i].hs_bytes); } } |