Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F154727877
D22654.id65415.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D22654.id65415.diff
View Options
Index: sys/dev/md/md.c
===================================================================
--- sys/dev/md/md.c
+++ sys/dev/md/md.c
@@ -1121,10 +1121,7 @@
}
vm_page_valid(m);
- if (m->dirty != VM_PAGE_BITS_ALL) {
- vm_page_dirty(m);
- vm_pager_page_unswapped(m);
- }
+ vm_page_set_dirty(m, true);
} else if (bp->bio_cmd == BIO_DELETE) {
if (len == PAGE_SIZE || vm_page_all_valid(m))
rv = VM_PAGER_OK;
@@ -1142,10 +1139,7 @@
/* Page is valid. */
if (len != PAGE_SIZE) {
pmap_zero_page_area(m, offs, len);
- if (m->dirty != VM_PAGE_BITS_ALL) {
- vm_page_dirty(m);
- vm_pager_page_unswapped(m);
- }
+ vm_page_set_dirty(m, true);
} else {
vm_pager_page_unswapped(m);
vm_page_free(m);
Index: sys/fs/tmpfs/tmpfs_subr.c
===================================================================
--- sys/fs/tmpfs/tmpfs_subr.c
+++ sys/fs/tmpfs/tmpfs_subr.c
@@ -1507,9 +1507,8 @@
}
if (m != NULL) {
pmap_zero_page_area(m, base, PAGE_SIZE - base);
- vm_page_dirty(m);
+ vm_page_set_dirty(m, true);
vm_page_xunbusy(m);
- vm_pager_page_unswapped(m);
}
}
Index: sys/kern/uipc_shm.c
===================================================================
--- sys/kern/uipc_shm.c
+++ sys/kern/uipc_shm.c
@@ -198,7 +198,7 @@
* type object.
*/
rv = vm_page_grab_valid(&m, obj, idx,
- VM_ALLOC_NORMAL | VM_ALLOC_WIRED | VM_ALLOC_NOBUSY);
+ VM_ALLOC_NORMAL | VM_ALLOC_SBUSY | VM_ALLOC_IGN_SBUSY);
if (rv != VM_PAGER_OK) {
VM_OBJECT_WUNLOCK(obj);
printf("uiomove_object: vm_obj %p idx %jd pager error %d\n",
@@ -207,13 +207,10 @@
}
VM_OBJECT_WUNLOCK(obj);
error = uiomove_fromphys(&m, offset, tlen, uio);
- if (uio->uio_rw == UIO_WRITE && error == 0) {
- VM_OBJECT_WLOCK(obj);
- vm_page_dirty(m);
- vm_pager_page_unswapped(m);
- VM_OBJECT_WUNLOCK(obj);
- }
- vm_page_unwire(m, PQ_ACTIVE);
+ if (uio->uio_rw == UIO_WRITE && error == 0)
+ vm_page_set_dirty(m, false);
+ vm_page_aflag_set(m, PGA_REFERENCED);
+ vm_page_sunbusy(m);
return (error);
}
@@ -529,9 +526,8 @@
pmap_zero_page_area(m, base, PAGE_SIZE - base);
KASSERT(vm_page_all_valid(m),
("shm_dotruncate: page %p is invalid", m));
- vm_page_dirty(m);
+ vm_page_set_dirty(m, true);
vm_page_xunbusy(m);
- vm_pager_page_unswapped(m);
}
}
delta = IDX_TO_OFF(object->size - nobjsize);
Index: sys/vm/vm_fault.c
===================================================================
--- sys/vm/vm_fault.c
+++ sys/vm/vm_fault.c
@@ -251,49 +251,29 @@
vm_object_set_writeable_dirty(m->object);
- if (!excl)
- /*
- * If two callers of vm_fault_dirty() with excl ==
- * FALSE, one for the map entry with MAP_ENTRY_NOSYNC
- * flag set, other with flag clear, race, it is
- * possible for the no-NOSYNC thread to see m->dirty
- * != 0 and not clear PGA_NOSYNC. Take vm_page lock
- * around manipulation of PGA_NOSYNC and
- * vm_page_dirty() call to avoid the race.
- */
- vm_page_lock(m);
-
- /*
- * If this is a NOSYNC mmap we do not want to set PGA_NOSYNC
- * if the page is already dirty to prevent data written with
- * the expectation of being synced from not being synced.
- * Likewise if this entry does not request NOSYNC then make
- * sure the page isn't marked NOSYNC. Applications sharing
- * data should use the same flags to avoid ping ponging.
- */
- if ((entry->eflags & MAP_ENTRY_NOSYNC) != 0) {
- if (m->dirty == 0) {
- vm_page_aflag_set(m, PGA_NOSYNC);
- }
- } else {
- vm_page_aflag_clear(m, PGA_NOSYNC);
- }
-
/*
* If the fault is a write, we know that this page is being
* written NOW so dirty it explicitly to save on
* pmap_is_modified() calls later.
*
* Also, since the page is now dirty, we can possibly tell
- * the pager to release any swap backing the page. Calling
- * the pager requires a write lock on the object.
+ * the pager to release any swap backing the page.
*/
- if (need_dirty)
- vm_page_dirty(m);
- if (!excl)
- vm_page_unlock(m);
- else if (need_dirty)
- vm_pager_page_unswapped(m);
+ if (need_dirty && vm_page_set_dirty(m, excl) == 0) {
+ /*
+ * If this is a NOSYNC mmap we do not want to set PGA_NOSYNC
+ * if the page is already dirty to prevent data written with
+ * the expectation of being synced from not being synced.
+ * Likewise if this entry does not request NOSYNC then make
+ * sure the page isn't marked NOSYNC. Applications sharing
+ * data should use the same flags to avoid ping ponging.
+ */
+ if ((entry->eflags & MAP_ENTRY_NOSYNC) != 0)
+ vm_page_aflag_set(m, PGA_NOSYNC);
+ else
+ vm_page_aflag_clear(m, PGA_NOSYNC);
+ }
+
}
/*
Index: sys/vm/vm_page.h
===================================================================
--- sys/vm/vm_page.h
+++ sys/vm/vm_page.h
@@ -422,6 +422,10 @@
* PGA_REQUEUE_HEAD is a special flag for enqueuing pages near the head of
* the inactive queue, thus bypassing LRU. The page lock must be held to
* set this flag, and the queue lock for the page must be held to clear it.
+ *
+ * PGA_UNSWAPPED is used to defer freeing swap space to the pageout daemon
+ * when the context that dirties the page does not have the object write lock
+ * held.
*/
#define PGA_WRITEABLE 0x0001 /* page may be mapped writeable */
#define PGA_REFERENCED 0x0002 /* page has been referenced */
@@ -431,6 +435,7 @@
#define PGA_REQUEUE 0x0020 /* page is due to be requeued */
#define PGA_REQUEUE_HEAD 0x0040 /* page requeue should bypass LRU */
#define PGA_NOSYNC 0x0080 /* do not collect for syncer */
+#define PGA_UNSWAPPED 0x0100 /* page with swap space was dirtied */
#define PGA_QUEUE_STATE_MASK (PGA_ENQUEUED | PGA_DEQUEUE | PGA_REQUEUE | \
PGA_REQUEUE_HEAD)
@@ -640,6 +645,7 @@
int vm_page_sbusied(vm_page_t m);
vm_page_t vm_page_scan_contig(u_long npages, vm_page_t m_start,
vm_page_t m_end, u_long alignment, vm_paddr_t boundary, int options);
+vm_page_bits_t vm_page_set_dirty(vm_page_t m, bool locked);
void vm_page_set_valid_range(vm_page_t m, int base, int size);
int vm_page_sleep_if_busy(vm_page_t m, const char *msg);
int vm_page_sleep_if_xbusy(vm_page_t m, const char *msg);
Index: sys/vm/vm_page.c
===================================================================
--- sys/vm/vm_page.c
+++ sys/vm/vm_page.c
@@ -144,12 +144,24 @@
CTLFLAG_RD, &queue_nops,
"Number of batched queue operations with no effects");
+static counter_u64_t swap_free_deferred = EARLY_COUNTER;
+SYSCTL_COUNTER_U64(_vm_stats_page, OID_AUTO, swap_free_deferred,
+ CTLFLAG_RD, &swap_free_deferred,
+ "Number of pages that deferred swap reclamation");
+
+counter_u64_t swap_free_reclaimed = EARLY_COUNTER;
+SYSCTL_COUNTER_U64(_vm_stats_page, OID_AUTO, swap_free_reclaimed,
+ CTLFLAG_RD, &swap_free_reclaimed,
+ "Number of deferred frees completed");
+
static void
counter_startup(void)
{
queue_ops = counter_u64_alloc(M_WAITOK);
queue_nops = counter_u64_alloc(M_WAITOK);
+ swap_free_deferred = counter_u64_alloc(M_WAITOK);
+ swap_free_reclaimed = counter_u64_alloc(M_WAITOK);
}
SYSINIT(page_counters, SI_SUB_CPU, SI_ORDER_ANY, counter_startup, NULL);
@@ -1584,6 +1596,13 @@
KASSERT((m->ref_count & VPRC_OBJREF) != 0,
("page %p is missing its object ref", m));
+ /* Deferred free of swap space. */
+ if ((m->aflags & PGA_UNSWAPPED) != 0) {
+ vm_pager_page_unswapped(m);
+ counter_u64_add(swap_free_reclaimed, 1);
+ vm_page_aflag_clear(m, PGA_UNSWAPPED);
+ }
+
mrem = vm_radix_remove(&object->rtree, m->pindex);
KASSERT(mrem == m, ("removed page %p, expected page %p", mrem, m));
@@ -4605,6 +4624,62 @@
#endif /* PAGE_SIZE */
}
+static inline vm_page_bits_t
+vm_page_bits_swap(vm_page_t m, vm_page_bits_t *bits, vm_page_bits_t newbits)
+{
+#if PAGE_SIZE == 32768
+ uint64_t old;
+
+ old = *bits;
+ while (atomic_fcmpset_64(bits, &old, newbits) == 0);
+ return (old);
+#elif PAGE_SIZE == 16384
+ uint32_t old;
+
+ old = *bits;
+ while (atomic_fcmpset_32(bits, &old, newbits) == 0);
+ return (old);
+#elif (PAGE_SIZE == 8192) && defined(atomic_fcmpset_16)
+ uint16_t old;
+
+ old = *bits;
+ while (atomic_fcmpset_16(bits, &old, newbits) == 0);
+ return (old);
+#elif (PAGE_SIZE == 4096) && defined(atomic_fcmpset_8)
+ uint8_t old;
+
+ old = *bits;
+ while (atomic_fcmpset_8(bits, &old, newbits) == 0);
+ return (old);
+#else /* PAGE_SIZE <= 4096*/
+ uintptr_t addr;
+ uint32_t old, new, mask;
+ int shift;
+
+ addr = (uintptr_t)bits;
+ /*
+ * Use a trick to perform a 32-bit atomic on the
+ * containing aligned word, to not depend on the existence
+ * of atomic_{set, swap, clear}_{8, 16}.
+ */
+ shift = addr & (sizeof(uint32_t) - 1);
+#if BYTE_ORDER == BIG_ENDIAN
+ shift = (sizeof(uint32_t) - sizeof(vm_page_bits_t) - shift) * NBBY;
+#else
+ shift *= NBBY;
+#endif
+ addr &= ~(sizeof(uint32_t) - 1);
+ mask = VM_PAGE_BITS_ALL << shift;
+
+ old = *bits;
+ do {
+ new = old & ~mask;
+ new |= newbits << shift;
+ } while (atomic_fcmpset_32((uint32_t *)addr, &old, new) == 0);
+ return (old >> shift);
+#endif /* PAGE_SIZE */
+}
+
/*
* vm_page_set_valid_range:
*
@@ -4662,6 +4737,39 @@
vm_page_bits_set(m, &m->valid, pagebits);
}
+/*
+ * Set the page dirty bits and free the invalid swap space or schedule it to
+ * be cleared later. If the locked parameter is true the object lock is
+ * expected to be write locked.
+ */
+vm_page_bits_t
+vm_page_set_dirty(vm_page_t m, bool locked)
+{
+ vm_page_bits_t old;
+ vm_object_t obj;
+
+ VM_PAGE_OBJECT_BUSY_ASSERT(m);
+ obj = m->object;
+ if (locked)
+ VM_OBJECT_ASSERT_WLOCKED(obj);
+
+ if (vm_page_xbusied(m) && !pmap_page_is_write_mapped(m)) {
+ old = m->dirty;
+ m->dirty = VM_PAGE_BITS_ALL;
+ } else
+ old = vm_page_bits_swap(m, &m->dirty, VM_PAGE_BITS_ALL);
+ if (old == 0 && obj != NULL && obj->type == OBJT_SWAP) {
+ if (locked) {
+ vm_pager_page_unswapped(m);
+ } else {
+ counter_u64_add(swap_free_deferred, 1);
+ vm_page_aflag_set(m, PGA_UNSWAPPED);
+ }
+ }
+
+ return (old);
+}
+
/*
* Clear the given bits from the specified page's dirty field.
*/
Index: sys/vm/vm_pageout.h
===================================================================
--- sys/vm/vm_pageout.h
+++ sys/vm/vm_pageout.h
@@ -77,6 +77,7 @@
extern u_long vm_page_max_user_wired;
extern int vm_pageout_page_count;
+extern uint64_t *swap_free_reclaimed;
#define VM_OOM_MEM 1
#define VM_OOM_MEM_PF 2
Index: sys/vm/vm_pageout.c
===================================================================
--- sys/vm/vm_pageout.c
+++ sys/vm/vm_pageout.c
@@ -1307,6 +1307,17 @@
act_delta++;
}
+ /* Deferred free of swap space. */
+ if ((m->aflags & PGA_UNSWAPPED) != 0 &&
+ VM_OBJECT_TRYWLOCK(object)) {
+ if (m->object == object) {
+ vm_pager_page_unswapped(m);
+ vm_page_aflag_clear(m, PGA_UNSWAPPED);
+ counter_u64_add(swap_free_reclaimed, 1);
+ }
+ VM_OBJECT_WUNLOCK(object);
+ }
+
/*
* Advance or decay the act_count based on recent usage.
*/
@@ -1542,6 +1553,13 @@
goto reinsert;
}
+ /* Deferred free of swap space. */
+ if ((m->aflags & PGA_UNSWAPPED) != 0) {
+ vm_pager_page_unswapped(m);
+ vm_page_aflag_clear(m, PGA_UNSWAPPED);
+ counter_u64_add(swap_free_reclaimed, 1);
+ }
+
/*
* Re-check for wirings now that we hold the object lock and
* have verified that the page is unbusied. If the page is
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Apr 30, 8:06 AM (21 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32474900
Default Alt Text
D22654.id65415.diff (11 KB)
Attached To
Mode
D22654: Add a deferred mechanism for deleting swap space without the object lock held.
Attached
Detach File
Event Timeline
Log In to Comment