Page MenuHomeFreeBSD

D27194.diff
No OneTemporary

D27194.diff

diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -409,6 +409,7 @@
vnet.9 \
vnode.9 \
vnode_pager_setsize.9 \
+ vnode_pager_purge_range.9 \
VOP_ACCESS.9 \
VOP_ACLCHECK.9 \
VOP_ADVISE.9 \
diff --git a/share/man/man9/vnode_pager_purge_range.9 b/share/man/man9/vnode_pager_purge_range.9
new file mode 100644
--- /dev/null
+++ b/share/man/man9/vnode_pager_purge_range.9
@@ -0,0 +1,85 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+.\"
+.\" Copyright (c) 2021 The FreeBSD Foundation
+.\"
+.\" This manual page was written by Ka Ho Ng under sponsorship from
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd August 2, 2021
+.Dt VNODE_PAGER_PURGE_RANGE 9
+.Os
+.Sh NAME
+.Nm vnode_pager_purge_range
+.Nd "invalidate the cached contents within the given byte range"
+.Sh SYNOPSIS
+.In sys/param.h
+.In vm/vm.h
+.In vm/vm_extern.h
+.Ft void
+.Fo vnode_pager_purge_range
+.Fa "struct vnode *vp"
+.Fa "vm_ooffset_t start"
+.Fa "vm_ooffset_t end"
+.Fc
+.Sh DESCRIPTION
+.Nm
+invalidates the cached contents within the given byte range from the
+specified vnode
+.Fa vp .
+The range to be purged is
+.Eo [
+.Fa start , end
+.Ec ) .
+If the
+.Fa end
+parameter is the value zero, the affected range starts from
+.Fa start
+continues to the end of the object.
+Pages within the specified range will be removed from the object's queue.
+If
+.Fa start
+or
+.Fa end
+is not aligned to a page boundary, the invalidated part of the page is zeroed.
+This function only cleans the resident pages in the affected region, it is up to
+the callers to ensure reading the backing store gets back zeroes.
+.Pp
+In case the vnode
+.Fa vp
+does not have a VM object allocated, the effect of calling this function is a
+no-op.
+.Sh LOCKS
+The vnode must be locked on entry and will still be locked on exit.
+.Sh SEE ALSO
+.Xr vnode 9
+.Sh HISTORY
+The
+.Nm
+manual page first appeared in
+.Fx 14 .
+.Sh AUTHORS
+This
+manual page was written by
+.An Ka Ho Ng Aq Mt khng@FreeBSD.org .
diff --git a/sys/vm/vm_extern.h b/sys/vm/vm_extern.h
--- a/sys/vm/vm_extern.h
+++ b/sys/vm/vm_extern.h
@@ -120,6 +120,7 @@
void vmspace_exitfree(struct proc *);
void vmspace_switch_aio(struct vmspace *);
void vnode_pager_setsize(struct vnode *, vm_ooffset_t);
+void vnode_pager_purge_range(struct vnode *, vm_ooffset_t, vm_ooffset_t);
int vslock(void *, size_t);
void vsunlock(void *, size_t);
struct sf_buf *vm_imgact_map_page(vm_object_t object, vm_ooffset_t offset);
diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c
--- a/sys/vm/vnode_pager.c
+++ b/sys/vm/vnode_pager.c
@@ -427,6 +427,53 @@
return TRUE;
}
+/*
+ * Internal routine clearing partial-page content
+ */
+static void
+vnode_pager_subpage_purge(struct vm_page *m, int base, int end)
+{
+ int size;
+
+ KASSERT(end > base && end <= PAGE_SIZE,
+ ("%s: start %d end %d", __func__, base, end));
+ size = end - base;
+
+ /*
+ * Clear out partial-page garbage in case
+ * the page has been mapped.
+ */
+ 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_range(m, base, size);
+
+ /*
+ * Round up "base" to the next block boundary so
+ * that the dirty bit for a partially zeroed
+ * block is not cleared.
+ */
+ base = roundup2(base, DEV_BSIZE);
+ end = rounddown2(end, DEV_BSIZE);
+
+ if (end > base) {
+ /*
+ * Clear out partial-page dirty bits.
+ *
+ * note that we do not clear out the
+ * valid bits. This would prevent
+ * bogus_page replacement from working
+ * properly.
+ */
+ vm_page_clear_dirty(m, base, end - base);
+ }
+
+}
+
/*
* Lets the VM system know about a change in size for a file.
* We adjust our own internal size and flush any cached pages in
@@ -489,39 +536,9 @@
m = vm_page_grab(object, OFF_TO_IDX(nsize), VM_ALLOC_NOCREAT);
if (m == NULL)
goto out;
- if (!vm_page_none_valid(m)) {
- int base = (int)nsize & PAGE_MASK;
- int size = PAGE_SIZE - base;
-
- /*
- * Clear out partial-page garbage in case
- * the page has been mapped.
- */
- 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_range(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);
-
- /*
- * Clear out partial-page dirty bits.
- *
- * note that we do not clear out the valid
- * bits. This would prevent bogus_page
- * replacement from working properly.
- */
- vm_page_clear_dirty(m, base, PAGE_SIZE - base);
- }
+ if (!vm_page_none_valid(m))
+ vnode_pager_subpage_purge(m, (int)nsize & PAGE_MASK,
+ PAGE_SIZE);
vm_page_xunbusy(m);
}
out:
@@ -534,6 +551,63 @@
VM_OBJECT_WUNLOCK(object);
}
+/*
+ * Lets the VM system know about the purged range for a file. We toss away any
+ * cached pages in the associated object that are affected by the purge
+ * operation. Partial-page area not aligned to page boundaries will be zeroed
+ * and the dirty blocks in DEV_BSIZE unit within a page will not be flushed.
+ */
+void
+vnode_pager_purge_range(struct vnode *vp, vm_ooffset_t start, vm_ooffset_t end)
+{
+ struct vm_page *m;
+ struct vm_object *object;
+ vm_pindex_t pi, pistart, piend;
+ bool same_page;
+ int base, pend;
+
+ ASSERT_VOP_LOCKED(vp, "vnode_pager_purge_range");
+
+ object = vp->v_object;
+ pi = start + PAGE_MASK < start ? OBJ_MAX_SIZE :
+ OFF_TO_IDX(start + PAGE_MASK);
+ pistart = OFF_TO_IDX(start);
+ piend = end == 0 ? OBJ_MAX_SIZE : OFF_TO_IDX(end);
+ same_page = pistart == piend;
+ if ((end != 0 && end <= start) || object == NULL)
+ return;
+
+ VM_OBJECT_WLOCK(object);
+
+ if (pi < piend)
+ vm_object_page_remove(object, pi, piend, 0);
+
+ if ((start & PAGE_MASK) != 0) {
+ base = (int)start & PAGE_MASK;
+ pend = same_page ? (int)end & PAGE_MASK : PAGE_SIZE;
+ m = vm_page_grab(object, pistart, VM_ALLOC_NOCREAT);
+ if (m != NULL) {
+ if (!vm_page_none_valid(m))
+ vnode_pager_subpage_purge(m, base, pend);
+ vm_page_xunbusy(m);
+ }
+ if (same_page)
+ goto out;
+ }
+ if ((end & PAGE_MASK) != 0) {
+ base = same_page ? (int)start & PAGE_MASK : 0 ;
+ pend = (int)end & PAGE_MASK;
+ m = vm_page_grab(object, piend, VM_ALLOC_NOCREAT);
+ if (m != NULL) {
+ if (!vm_page_none_valid(m))
+ vnode_pager_subpage_purge(m, base, pend);
+ vm_page_xunbusy(m);
+ }
+ }
+out:
+ VM_OBJECT_WUNLOCK(object);
+}
+
/*
* calculate the linear (byte) disk address of specified virtual
* file address

File Metadata

Mime Type
text/plain
Expires
Fri, Oct 24, 1:14 AM (49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24111190
Default Alt Text
D27194.diff (7 KB)

Event Timeline