aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/vfs_cluster.c
diff options
context:
space:
mode:
authorAlan Cox <alc@FreeBSD.org>2009-06-27 21:37:36 +0000
committerAlan Cox <alc@FreeBSD.org>2009-06-27 21:37:36 +0000
commitde0c3e08959b1711d3f1423c72f98526adf76287 (patch)
treee9c5b8120c04ddc718420c6d8cd8c68d68befcf7 /sys/kern/vfs_cluster.c
parent29bd7d7e9aab730430419bb7be64e1a26aaf39b2 (diff)
downloadsrc-de0c3e08959b1711d3f1423c72f98526adf76287.tar.gz
src-de0c3e08959b1711d3f1423c72f98526adf76287.zip
Correct a long-standing performance bug in cluster_rbuild(). Specifically,
in the case of a file system with a block size that is less than the page size, cluster_rbuild() looks at too many of the page's valid bits. Consequently, it may terminate prematurely, resulting in poor performance. Reported by: bde Reviewed by: tegge Approved by: re (kib)
Notes
Notes: svn path=/head/; revision=195122
Diffstat (limited to 'sys/kern/vfs_cluster.c')
-rw-r--r--sys/kern/vfs_cluster.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/sys/kern/vfs_cluster.c b/sys/kern/vfs_cluster.c
index 34af452223ce..5082f1febf55 100644
--- a/sys/kern/vfs_cluster.c
+++ b/sys/kern/vfs_cluster.c
@@ -310,7 +310,9 @@ cluster_rbuild(vp, filesize, lbn, blkno, size, run, fbp)
struct bufobj *bo;
struct buf *bp, *tbp;
daddr_t bn;
- int i, inc, j;
+ off_t off;
+ long tinc, tsize;
+ int i, inc, j, toff;
KASSERT(size == vp->v_mount->mnt_stat.f_iosize,
("cluster_rbuild: size %ld != filesize %jd\n",
@@ -402,15 +404,24 @@ cluster_rbuild(vp, filesize, lbn, blkno, size, run, fbp)
* take part in the cluster. If it is partially valid
* then we stop.
*/
+ off = tbp->b_offset;
+ tsize = size;
VM_OBJECT_LOCK(tbp->b_bufobj->bo_object);
- for (j = 0;j < tbp->b_npages; j++) {
+ for (j = 0; tsize > 0; j++) {
+ toff = off & PAGE_MASK;
+ tinc = tsize;
+ if (toff + tinc > PAGE_SIZE)
+ tinc = PAGE_SIZE - toff;
VM_OBJECT_LOCK_ASSERT(tbp->b_pages[j]->object,
MA_OWNED);
- if (tbp->b_pages[j]->valid)
+ if ((tbp->b_pages[j]->valid &
+ vm_page_bits(toff, tinc)) != 0)
break;
+ off += tinc;
+ tsize -= tinc;
}
VM_OBJECT_UNLOCK(tbp->b_bufobj->bo_object);
- if (j != tbp->b_npages) {
+ if (tsize > 0) {
bqrelse(tbp);
break;
}