summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2017-08-02 08:07:13 +0000
committerkib <kib@FreeBSD.org>2017-08-02 08:07:13 +0000
commitcb043642c2bc0bdbf5116d3592b0e8d83d30ffd1 (patch)
tree6344d83ca7295ad2e70205c52c3f35c1fd9e8483
parentc9a29f3ff46efaef98da66e7314436ea7c8ee5fd (diff)
downloadFreeBSD-src-cb043642c2bc0bdbf5116d3592b0e8d83d30ffd1.zip
FreeBSD-src-cb043642c2bc0bdbf5116d3592b0e8d83d30ffd1.tar.gz
MFC r321581:
Mark pages after EOF as clean after pageout.
-rw-r--r--sys/fs/nfsclient/nfs_clbio.c6
-rw-r--r--sys/fs/smbfs/smbfs_io.c8
-rw-r--r--sys/vm/vnode_pager.c48
-rw-r--r--sys/vm/vnode_pager.h3
4 files changed, 56 insertions, 9 deletions
diff --git a/sys/fs/nfsclient/nfs_clbio.c b/sys/fs/nfsclient/nfs_clbio.c
index 2b60754..0fa8bc8 100644
--- a/sys/fs/nfsclient/nfs_clbio.c
+++ b/sys/fs/nfsclient/nfs_clbio.c
@@ -336,8 +336,10 @@ ncl_putpages(struct vop_putpages_args *ap)
cred);
crfree(cred);
- if (error == 0 || !nfs_keep_dirty_on_error)
- vnode_pager_undirty_pages(pages, rtvals, count - uio.uio_resid);
+ if (error == 0 || !nfs_keep_dirty_on_error) {
+ vnode_pager_undirty_pages(pages, rtvals, count - uio.uio_resid,
+ np->n_size - offset, npages * PAGE_SIZE);
+ }
return (rtvals[0]);
}
diff --git a/sys/fs/smbfs/smbfs_io.c b/sys/fs/smbfs/smbfs_io.c
index 498d063..6bcffee 100644
--- a/sys/fs/smbfs/smbfs_io.c
+++ b/sys/fs/smbfs/smbfs_io.c
@@ -621,9 +621,11 @@ smbfs_putpages(ap)
relpbuf(bp, &smbfs_pbuf_freecnt);
- if (!error)
- vnode_pager_undirty_pages(pages, rtvals, count - uio.uio_resid);
- return rtvals[0];
+ if (error == 0) {
+ vnode_pager_undirty_pages(pages, rtvals, count - uio.uio_resid,
+ npages * PAGE_SIZE, npages * PAGE_SIZE);
+ }
+ return (rtvals[0]);
#endif /* SMBFS_RWGENERIC */
}
diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c
index 06dff5e..4c0dae9 100644
--- a/sys/vm/vnode_pager.c
+++ b/sys/vm/vnode_pager.c
@@ -1276,13 +1276,24 @@ vnode_pager_putpages_ioflags(int pager_flags)
return (ioflags);
}
+/*
+ * vnode_pager_undirty_pages().
+ *
+ * A helper to mark pages as clean after pageout that was possibly
+ * done with a short write. The lpos argument specifies the page run
+ * length in bytes, and the written argument specifies how many bytes
+ * were actually written. eof is the offset past the last valid byte
+ * in the vnode using the absolute file position of the first byte in
+ * the run as the base from which it is computed.
+ */
void
-vnode_pager_undirty_pages(vm_page_t *ma, int *rtvals, int written)
+vnode_pager_undirty_pages(vm_page_t *ma, int *rtvals, int written, off_t eof,
+ int lpos)
{
vm_object_t obj;
- int i, pos;
+ int i, pos, pos_devb;
- if (written == 0)
+ if (written == 0 && eof >= lpos)
return;
obj = ma[0]->object;
VM_OBJECT_WLOCK(obj);
@@ -1296,6 +1307,37 @@ vnode_pager_undirty_pages(vm_page_t *ma, int *rtvals, int written)
vm_page_clear_dirty(ma[i], 0, written & PAGE_MASK);
}
}
+ if (eof >= lpos) /* avoid truncation */
+ goto done;
+ for (pos = eof, i = OFF_TO_IDX(trunc_page(pos)); pos < lpos; i++) {
+ if (pos != trunc_page(pos)) {
+ /*
+ * The page contains the last valid byte in
+ * the vnode, mark the rest of the page as
+ * clean, potentially making the whole page
+ * clean.
+ */
+ pos_devb = roundup2(pos & PAGE_MASK, DEV_BSIZE);
+ vm_page_clear_dirty(ma[i], pos_devb, PAGE_SIZE -
+ pos_devb);
+
+ /*
+ * If the page was cleaned, report the pageout
+ * on it as successful. msync() no longer
+ * needs to write out the page, endlessly
+ * creating write requests and dirty buffers.
+ */
+ if (ma[i]->dirty == 0)
+ rtvals[i] = VM_PAGER_OK;
+
+ pos = round_page(pos);
+ } else {
+ /* vm_pageout_flush() clears dirty */
+ rtvals[i] = VM_PAGER_BAD;
+ pos += PAGE_SIZE;
+ }
+ }
+done:
VM_OBJECT_WUNLOCK(obj);
}
diff --git a/sys/vm/vnode_pager.h b/sys/vm/vnode_pager.h
index bfcb98a..80ad634 100644
--- a/sys/vm/vnode_pager.h
+++ b/sys/vm/vnode_pager.h
@@ -50,7 +50,8 @@ int vnode_pager_local_getpages_async(struct vop_getpages_async_args *ap);
int vnode_pager_putpages_ioflags(int pager_flags);
void vnode_pager_release_writecount(vm_object_t object, vm_offset_t start,
vm_offset_t end);
-void vnode_pager_undirty_pages(vm_page_t *ma, int *rtvals, int written);
+void vnode_pager_undirty_pages(vm_page_t *ma, int *rtvals, int written,
+ off_t eof, int lpos);
void vnode_pager_update_writecount(vm_object_t object, vm_offset_t start,
vm_offset_t end);
OpenPOWER on IntegriCloud