summaryrefslogtreecommitdiff
path: root/os_dep.c
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2021-08-26 08:51:58 +0300
committerIvan Maidanski <ivmai@mail.ru>2021-08-26 17:57:05 +0300
commit5b75faefeec9c1fb67fd1067d78c2bdff3aa7a45 (patch)
tree388f93765da88304b2d80ecf6cf282e4111d344a /os_dep.c
parent2bae6c818e4e61dd9f62fdffc0cc1621a5ba40a9 (diff)
downloadbdwgc-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.c90
1 files changed, 52 insertions, 38 deletions
diff --git a/os_dep.c b/os_dep.c
index feac94ee..ad484c97 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -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);
}
}