summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authoralc <alc@FreeBSD.org>2009-06-02 08:02:27 +0000
committeralc <alc@FreeBSD.org>2009-06-02 08:02:27 +0000
commit4a004094863695f228584bd2dd78759f39280f3d (patch)
tree093f5d6b6fd20e3168e8b72f1bec881789e2f8e2 /sys/kern
parentb741ad3e96345042455577273b4346af99e4296a (diff)
downloadFreeBSD-src-4a004094863695f228584bd2dd78759f39280f3d.zip
FreeBSD-src-4a004094863695f228584bd2dd78759f39280f3d.tar.gz
Correct a boundary case error in the management of a page's dirty bits by
shm_dotruncate() and vnode_pager_setsize(). Specifically, if the length of a shared memory object or a file is truncated such that the length modulo the page size is between 1 and 511, then all of the page's dirty bits were cleared. Now, a dirty bit is cleared only if the corresponding block is truncated in its entirety.
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/uipc_shm.c21
1 files changed, 17 insertions, 4 deletions
diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c
index a12c731..00fb438 100644
--- a/sys/kern/uipc_shm.c
+++ b/sys/kern/uipc_shm.c
@@ -274,7 +274,7 @@ shm_dotruncate(struct shmfd *shmfd, off_t length)
/*
* If the last page is partially mapped, then zero out
* the garbage at the end of the page. See comments
- * in vnode_page_setsize() for more details.
+ * in vnode_pager_setsize() for more details.
*
* XXXJHB: This handles in memory pages, but what about
* a page swapped out to disk?
@@ -286,10 +286,23 @@ shm_dotruncate(struct shmfd *shmfd, off_t length)
int size = PAGE_SIZE - base;
pmap_zero_page_area(m, base, size);
+
+ /*
+ * Update the valid bits to reflect the blocks that
+ * have been zeroed. Some of these valid bits may
+ * have already been set.
+ */
+ vm_page_set_valid(m, base, size);
+
+ /*
+ * Round "base" to the next block boundary so that the
+ * dirty bit for a partially zeroed block is not
+ * cleared.
+ */
+ base = roundup2(base, DEV_BSIZE);
+
vm_page_lock_queues();
- vm_page_set_validclean(m, base, size);
- if (m->dirty != 0)
- m->dirty = VM_PAGE_BITS_ALL;
+ vm_page_clear_dirty(m, base, PAGE_SIZE - base);
vm_page_unlock_queues();
} else if ((length & PAGE_MASK) &&
__predict_false(object->cache != NULL)) {
OpenPOWER on IntegriCloud