diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/sys/fs/tmpfs/tmpfs_vnops.c --- a/sys/fs/tmpfs/tmpfs_vnops.c +++ b/sys/fs/tmpfs/tmpfs_vnops.c @@ -2092,40 +2092,10 @@ static off_t tmpfs_seek_data_locked(vm_object_t obj, off_t noff) { - vm_page_t m; - vm_pindex_t p, p_swp; + vm_pindex_t p; - p = OFF_TO_IDX(noff); - m = vm_page_find_least(obj, p); - - /* - * Microoptimize the most common case for SEEK_DATA, where - * there is no hole and the page is resident. - */ - if (m != NULL && m->pindex == p && vm_page_any_valid(m)) - return (noff); - - p_swp = swap_pager_find_least(obj, p); - if (p_swp == p) - return (noff); - - /* - * Find the first resident page after p, before p_swp. - */ - while (m != NULL && m->pindex < p_swp) { - if (vm_page_any_valid(m)) - return (IDX_TO_OFF(m->pindex)); - m = TAILQ_NEXT(m, listq); - } - if (p_swp == OBJ_MAX_SIZE) - p_swp = obj->size; - return (IDX_TO_OFF(p_swp)); -} - -static off_t -tmpfs_seek_next(off_t noff) -{ - return (noff + PAGE_SIZE - (noff & PAGE_MASK)); + p = swap_pager_seek_data(obj, OFF_TO_IDX(noff)); + return (p == OFF_TO_IDX(noff) ? noff : IDX_TO_OFF(p)); } static int @@ -2142,30 +2112,8 @@ static off_t tmpfs_seek_hole_locked(vm_object_t obj, off_t noff) { - vm_page_t m; - vm_pindex_t p, p_swp; - - for (;; noff = tmpfs_seek_next(noff)) { - /* - * Walk over the largest sequential run of the valid pages. - */ - for (m = vm_page_lookup(obj, OFF_TO_IDX(noff)); - m != NULL && vm_page_any_valid(m); - m = vm_page_next(m), noff = tmpfs_seek_next(noff)) - ; - /* - * Found a hole in the object's page queue. Check if - * there is a hole in the swap at the same place. - */ - p = OFF_TO_IDX(noff); - p_swp = swap_pager_find_least(obj, p); - if (p_swp != p) { - noff = IDX_TO_OFF(p); - break; - } - } - return (noff); + return (IDX_TO_OFF(swap_pager_seek_hole(obj, OFF_TO_IDX(noff)))); } static int diff --git a/sys/vm/swap_pager.h b/sys/vm/swap_pager.h --- a/sys/vm/swap_pager.h +++ b/sys/vm/swap_pager.h @@ -74,8 +74,9 @@ struct xswdev; int swap_dev_info(int name, struct xswdev *xs, char *devname, size_t len); void swap_pager_copy(vm_object_t, vm_object_t, vm_pindex_t, int); -vm_pindex_t swap_pager_find_least(vm_object_t object, vm_pindex_t pindex); bool swap_pager_scan_all_shadowed(vm_object_t object); +vm_pindex_t swap_pager_seek_data(vm_object_t object, vm_pindex_t pindex); +vm_pindex_t swap_pager_seek_hole(vm_object_t object, vm_pindex_t pindex); void swap_pager_freespace(vm_object_t object, vm_pindex_t start, vm_size_t size, vm_size_t *freed); void swap_pager_swap_init(void); diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c --- a/sys/vm/swap_pager.c +++ b/sys/vm/swap_pager.c @@ -111,6 +111,7 @@ #include #include #include +#include #include #include #include @@ -2476,17 +2477,62 @@ } /* - * Returns the least page index which is greater than or equal to the parameter - * pindex and for which there is a swap block allocated. Returns OBJ_MAX_SIZE - * if are no allocated swap blocks for the object after the requested pindex. + * Find the first index >= pindex that has either a valid page or a swap + * block. */ vm_pindex_t -swap_pager_find_least(vm_object_t object, vm_pindex_t pindex) +swap_pager_seek_data(vm_object_t object, vm_pindex_t pindex) { - struct pctrie_iter blks; + struct pctrie_iter blks, pages; + vm_page_t m; + vm_pindex_t swap_index; + + VM_OBJECT_ASSERT_WLOCKED(object); + vm_page_iter_init(&pages, object); + m = vm_page_iter_lookup_ge(&pages, pindex); + if (m != NULL) { + if (!vm_page_any_valid(m)) + m = NULL; + else if (pages.index == pindex) + return (pages.index); + } + swblk_iter_init_only(&blks, object); + swap_index = swap_pager_iter_find_least(&blks, pindex); + if (swap_index == pindex) + return (swap_index); + if (swap_index == OBJ_MAX_SIZE) + swap_index = object->size; + if (m == NULL) + return (swap_index); + + while ((m = vm_radix_iter_step(&pages)) != NULL && + pages.index < swap_index) { + if (vm_page_any_valid(m)) + return (pages.index); + } + return (swap_index); +} + +/* + * Find the first index >= pindex that has neither a valid page nor a swap + * block. + */ +vm_pindex_t +swap_pager_seek_hole(vm_object_t object, vm_pindex_t pindex) +{ + struct pctrie_iter blks, pages; + struct swblk *sb; + vm_page_t m; + VM_OBJECT_ASSERT_WLOCKED(object); + vm_page_iter_init(&pages, object); swblk_iter_init_only(&blks, object); - return (swap_pager_iter_find_least(&blks, pindex)); + while (((m = vm_page_iter_lookup(&pages, pindex)) != NULL && + vm_page_any_valid(m)) || + ((sb = swblk_iter_lookup(&blks, pindex)) != NULL && + sb->d[pindex % SWAP_META_PAGES] != SWAPBLK_NONE)) + pindex++; + return (pindex); } /*