summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2012-08-14 11:45:47 +0000
committerkib <kib@FreeBSD.org>2012-08-14 11:45:47 +0000
commita3d0fb01750888083d0ed5945f2d835c310c40e6 (patch)
treec57999c31279d4b34edfa4c9044a68251f72d983
parent45e40c523ad8935b149fdb4ae70172fb3a3c0336 (diff)
downloadFreeBSD-src-a3d0fb01750888083d0ed5945f2d835c310c40e6.zip
FreeBSD-src-a3d0fb01750888083d0ed5945f2d835c310c40e6.tar.gz
Do not leave invalid pages in the object after the short read for a
network file systems (not only NFS proper). Short reads cause pages other then the requested one, which were not filled by read response, to stay invalid. Change the vm_page_readahead_finish() interface to not take the error code, but instead to make a decision to free or to (de)activate the page only by its validity. As result, not requested invalid pages are freed even if the read RPC indicated success. Noted and reviewed by: alc MFC after: 1 week
-rw-r--r--sys/fs/nfsclient/nfs_clbio.c12
-rw-r--r--sys/fs/nwfs/nwfs_io.c2
-rw-r--r--sys/fs/smbfs/smbfs_io.c2
-rw-r--r--sys/nfsclient/nfs_bio.c12
-rw-r--r--sys/vm/vm_page.c10
-rw-r--r--sys/vm/vm_page.h2
-rw-r--r--sys/vm/vnode_pager.c2
7 files changed, 28 insertions, 14 deletions
diff --git a/sys/fs/nfsclient/nfs_clbio.c b/sys/fs/nfsclient/nfs_clbio.c
index 6583b9b..26286c5 100644
--- a/sys/fs/nfsclient/nfs_clbio.c
+++ b/sys/fs/nfsclient/nfs_clbio.c
@@ -218,14 +218,18 @@ ncl_getpages(struct vop_getpages_args *ap)
("nfs_getpages: page %p is dirty", m));
} else {
/*
- * Read operation was short. If no error occured
- * we may have hit a zero-fill section. We simply
- * leave valid set to 0.
+ * Read operation was short. If no error
+ * occured we may have hit a zero-fill
+ * section. We leave valid set to 0, and page
+ * is freed by vm_page_readahead_finish() if
+ * its index is not equal to requested, or
+ * page is zeroed and set valid by
+ * vm_pager_get_pages() for requested page.
*/
;
}
if (i != ap->a_reqpage)
- vm_page_readahead_finish(m, error);
+ vm_page_readahead_finish(m);
}
VM_OBJECT_UNLOCK(object);
return (0);
diff --git a/sys/fs/nwfs/nwfs_io.c b/sys/fs/nwfs/nwfs_io.c
index 33f3649..cd3c989 100644
--- a/sys/fs/nwfs/nwfs_io.c
+++ b/sys/fs/nwfs/nwfs_io.c
@@ -459,7 +459,7 @@ nwfs_getpages(ap)
}
if (i != ap->a_reqpage)
- vm_page_readahead_finish(m, error);
+ vm_page_readahead_finish(m);
}
VM_OBJECT_UNLOCK(object);
return 0;
diff --git a/sys/fs/smbfs/smbfs_io.c b/sys/fs/smbfs/smbfs_io.c
index 9a4610f..6dacd06 100644
--- a/sys/fs/smbfs/smbfs_io.c
+++ b/sys/fs/smbfs/smbfs_io.c
@@ -523,7 +523,7 @@ smbfs_getpages(ap)
}
if (i != reqpage)
- vm_page_readahead_finish(m, error);
+ vm_page_readahead_finish(m);
}
VM_OBJECT_UNLOCK(object);
return 0;
diff --git a/sys/nfsclient/nfs_bio.c b/sys/nfsclient/nfs_bio.c
index ae35336..0003974 100644
--- a/sys/nfsclient/nfs_bio.c
+++ b/sys/nfsclient/nfs_bio.c
@@ -212,14 +212,18 @@ nfs_getpages(struct vop_getpages_args *ap)
("nfs_getpages: page %p is dirty", m));
} else {
/*
- * Read operation was short. If no error occured
- * we may have hit a zero-fill section. We simply
- * leave valid set to 0.
+ * Read operation was short. If no error
+ * occured we may have hit a zero-fill
+ * section. We leave valid set to 0, and page
+ * is freed by vm_page_readahead_finish() if
+ * its index is not equal to requested, or
+ * page is zeroed and set valid by
+ * vm_pager_get_pages() for requested page.
*/
;
}
if (i != ap->a_reqpage)
- vm_page_readahead_finish(m, error);
+ vm_page_readahead_finish(m);
}
VM_OBJECT_UNLOCK(object);
return (0);
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index b679290..b012065c 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -699,10 +699,10 @@ vm_page_free_zero(vm_page_t m)
* array which is not the request page.
*/
void
-vm_page_readahead_finish(vm_page_t m, int error)
+vm_page_readahead_finish(vm_page_t m)
{
- if (error == 0) {
+ if (m->valid != 0) {
/*
* Since the page is not the requested page, whether
* it should be activated or deactivated is not
@@ -721,6 +721,12 @@ vm_page_readahead_finish(vm_page_t m, int error)
}
vm_page_wakeup(m);
} else {
+ /*
+ * Free the completely invalid page. Such page state
+ * occurs due to the short read operation which did
+ * not covered our page at all, or in case when a read
+ * error happens.
+ */
vm_page_lock(m);
vm_page_free(m);
vm_page_unlock(m);
diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h
index 14c9436..410948b 100644
--- a/sys/vm/vm_page.h
+++ b/sys/vm/vm_page.h
@@ -388,7 +388,7 @@ vm_page_t vm_page_next(vm_page_t m);
int vm_page_pa_tryrelock(pmap_t, vm_paddr_t, vm_paddr_t *);
vm_page_t vm_page_prev(vm_page_t m);
void vm_page_putfake(vm_page_t m);
-void vm_page_readahead_finish(vm_page_t m, int error);
+void vm_page_readahead_finish(vm_page_t m);
void vm_page_reference(vm_page_t m);
void vm_page_remove (vm_page_t);
void vm_page_rename (vm_page_t, vm_object_t, vm_pindex_t);
diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c
index da88b08..b0139ce 100644
--- a/sys/vm/vnode_pager.c
+++ b/sys/vm/vnode_pager.c
@@ -987,7 +987,7 @@ vnode_pager_generic_getpages(vp, m, bytecount, reqpage)
}
if (i != reqpage)
- vm_page_readahead_finish(mt, error);
+ vm_page_readahead_finish(mt);
}
VM_OBJECT_UNLOCK(object);
if (error) {
OpenPOWER on IntegriCloud