Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F151108909
D20001.id56467.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D20001.id56467.diff
View Options
Index: sys/kern/subr_blist.c
===================================================================
--- sys/kern/subr_blist.c
+++ sys/kern/subr_blist.c
@@ -130,6 +130,8 @@
/*
* static support functions
*/
+static int blst_next_leaf_alloc(blmeta_t *scan, daddr_t blk, int count,
+ int exact);
static daddr_t blst_leaf_alloc(blmeta_t *scan, daddr_t blk, int count);
static daddr_t blst_meta_alloc(blmeta_t *scan, daddr_t cursor, daddr_t count,
u_daddr_t radix);
@@ -312,6 +314,71 @@
}
}
+/*
+ * blist_grow_alloc() - reserve more space in the block bitmap. Return the
+ * number of blocks allocated to extend the last
+ * allocated contiguous region.
+ */
+daddr_t
+blist_grow_alloc(blist_t bl, daddr_t count)
+{
+ daddr_t blk;
+ blmeta_t *scan;
+ u_daddr_t mask, radix;
+ int digit, hi, lo;
+
+ if (count == 0)
+ return (0);
+ if (bl->bl_cursor == 0) {
+ /* There's no previous allocation to extend. */
+ return (0);
+ }
+ if (count > BLIST_MAX_ALLOC)
+ panic("grow allocation too large");
+ scan = bl->bl_root;
+ blk = bl->bl_cursor;
+ radix = bl->bl_radix;
+ while (radix > BLIST_BMAP_RADIX) {
+ radix /= BLIST_META_RADIX;
+ digit = (blk / radix) & BLIST_META_MASK;
+ scan += 1 + digit * radix_to_skip(radix);
+ }
+ lo = blk & BLIST_BMAP_MASK;
+ mask = ~(scan->bm_bitmap | bitrange(0, lo));
+ if (mask != 0) {
+ /* Count the 1 bits starting at position lo. */
+ hi = bitpos(mask );
+ if (count >= hi - lo)
+ count = hi - lo;
+ else
+ hi = lo + count;
+ } else if (count <= BLIST_BMAP_RADIX - lo)
+ hi = lo + count;
+ else {
+ /* Allocate the 1 bits starting the next leaf. */
+ count -= BLIST_BMAP_RADIX - lo;
+ count = blst_next_leaf_alloc(scan, blk, count, 0);
+ count += BLIST_BMAP_RADIX - lo;
+ hi = BLIST_BMAP_RADIX;
+ }
+ /* Clear the allocated bits from this leaf. */
+ scan->bm_bitmap &= ~bitrange(lo, hi - lo);
+ /* Fix parent bitmaps */
+ while (scan->bm_bitmap == 0) {
+ digit = (blk / radix) & BLIST_META_MASK;
+ scan -= 1 + digit * radix_to_skip(radix);
+ scan->bm_bitmap ^= (u_daddr_t)1 << digit;
+ if (scan == bl->bl_root)
+ break;
+ radix *= BLIST_META_RADIX;
+ }
+ bl->bl_cursor += count;
+ if (bl->bl_cursor == bl->bl_blocks)
+ bl->bl_cursor = 0;
+ bl->bl_avail -= count;
+ return (count);
+}
+
/*
* blist_avail() - return the number of free blocks.
*/
@@ -603,10 +670,9 @@
* common ancestor to mark any subtrees made completely empty.
*/
static int
-blst_next_leaf_alloc(blmeta_t *scan, daddr_t blk, int count)
+blst_next_leaf_alloc(blmeta_t *scan, daddr_t blk, int count, int exact)
{
blmeta_t *next;
- daddr_t skip;
u_daddr_t radix;
int digit;
@@ -618,27 +684,33 @@
next++;
radix *= BLIST_META_RADIX;
}
- if (((next->bm_bitmap + 1) & ~((u_daddr_t)-1 << count)) != 0) {
- /*
- * The next leaf doesn't have enough free blocks at the
- * beginning to complete the spanning allocation.
- */
- return (ENOMEM);
+ if (!exact) {
+ if (0 != ~next->bm_bitmap)
+ count = ummin(bitpos(~next->bm_bitmap), count);
}
+ else if (((next->bm_bitmap + 1) & ~((u_daddr_t)-1 << count)) != 0) {
+ /*
+ * The next leaf doesn't have enough free blocks at the
+ * beginning to complete the spanning allocation.
+ */
+ return (0);
+ }
/* Clear the first 'count' bits in the next leaf to allocate. */
next->bm_bitmap &= (u_daddr_t)-1 << count;
/*
* Update bitmaps of next-ancestors, up to least common ancestor.
*/
- skip = radix_to_skip(radix);
- while (radix != BLIST_BMAP_RADIX && next->bm_bitmap == 0) {
- (--next)->bm_bitmap ^= 1;
- radix /= BLIST_META_RADIX;
- }
- if (next->bm_bitmap == 0)
- scan[-digit * skip].bm_bitmap ^= (u_daddr_t)1 << digit;
- return (0);
+ while (next->bm_bitmap == 0) {
+ if (--next == scan) {
+ next[-digit * radix_to_skip(radix)].bm_bitmap ^=
+ (u_daddr_t)1 << digit;
+ break;
+ }
+ next->bm_bitmap ^= 1;
+ }
+
+ return (count);
}
/*
@@ -722,7 +794,8 @@
* An allocation within this leaf is impossible, so a successful
* allocation depends on the next leaf providing some of the blocks.
*/
- if (blst_next_leaf_alloc(scan, blk, hi - BLIST_BMAP_RADIX) != 0)
+ if (0 ==
+ blst_next_leaf_alloc(scan, blk, hi - BLIST_BMAP_RADIX, 1))
/*
* The hint cannot be updated, because the same
* allocation request could be satisfied later, by this
@@ -1109,6 +1182,14 @@
printf("?\n");
}
break;
+ case 'x':
+ if (sscanf(buf + 1, "%lld", &count) == 1) {
+ daddr_t size = blist_grow_alloc(bl, count);
+ printf(" R=%08llx\n", (long long)size);
+ } else {
+ printf("?\n");
+ }
+ break;
case 'f':
if (sscanf(buf + 1, "%llx %lld", &da, &count) == 2) {
blist_free(bl, da, count);
@@ -1130,16 +1211,22 @@
"p -print\n"
"s -stats\n"
"a %d -allocate\n"
+ "x %d -extend\n"
"f %x %d -free\n"
"l %x %d -fill\n"
"r %d -resize\n"
- "h/? -help"
+ "h/? -help\n"
+ "q -quit"
);
break;
+ case 'q':
+ break;
default:
printf("?\n");
break;
}
+ if (buf[0] == 'q')
+ break;
}
return(0);
}
Index: sys/sys/blist.h
===================================================================
--- sys/sys/blist.h
+++ sys/sys/blist.h
@@ -34,6 +34,7 @@
* blist = blist_create(blocks, flags)
* (void) blist_destroy(blist)
* blkno = blist_alloc(blist, count)
+ * count += blist_grow_alloc(blist, grow_count)
* (void) blist_free(blist, blkno, count)
* nblks = blist_fill(blist, blkno, count)
* (void) blist_resize(&blist, count, freeextra, flags)
@@ -69,11 +70,11 @@
#define SWAPBLK_NONE ((daddr_t)((u_daddr_t)SWAPBLK_MASK + 1))/* flag */
/*
- * Both blmeta and bmu_bitmap MUST be a power of 2 in size.
+ * Both blmeta and bm_bitmap MUST be a power of 2 in size.
*/
typedef struct blmeta {
- u_daddr_t bm_bitmap; /* bitmap if we are a leaf */
+ u_daddr_t bm_bitmap; /* bitmap marking unfilled block sets*/
daddr_t bm_bighint; /* biggest contiguous block hint*/
} blmeta_t;
@@ -93,6 +94,7 @@
struct sbuf;
daddr_t blist_alloc(blist_t blist, daddr_t count);
+daddr_t blist_grow_alloc(blist_t blist, daddr_t count);
daddr_t blist_avail(blist_t blist);
blist_t blist_create(daddr_t blocks, int flags);
void blist_destroy(blist_t blist);
Index: sys/vm/swap_pager.c
===================================================================
--- sys/vm/swap_pager.c
+++ sys/vm/swap_pager.c
@@ -407,7 +407,7 @@
* Swap bitmap functions
*/
static void swp_pager_freeswapspace(daddr_t blk, daddr_t npages);
-static daddr_t swp_pager_getswapspace(int npages);
+static daddr_t swp_pager_getswapspace(int *npages);
/*
* Metadata functions
@@ -708,7 +708,7 @@
/*
* SWP_PAGER_GETSWAPSPACE() - allocate raw swap space
*
- * Allocate swap for the requested number of pages. The starting
+ * Allocate swap for up to the requested number of pages. The starting
* swap block number (a page index) is returned or SWAPBLK_NONE
* if the allocation failed.
*
@@ -720,38 +720,50 @@
* We allocate in round-robin fashion from the configured devices.
*/
static daddr_t
-swp_pager_getswapspace(int npages)
+swp_pager_getswapspace(int *io_npages)
{
daddr_t blk;
struct swdevt *sp;
- int i;
+ int mpages, npages;
blk = SWAPBLK_NONE;
mtx_lock(&sw_dev_mtx);
sp = swdevhd;
- for (i = 0; i < nswapdev; i++) {
- if (sp == NULL)
- sp = TAILQ_FIRST(&swtailq);
- if (!(sp->sw_flags & SW_CLOSING)) {
+ npages = *io_npages;
+ mpages = 0;
+ while (npages > 0) {
+ do {
+ if (sp == NULL)
+ sp = TAILQ_FIRST(&swtailq);
+ if (sp->sw_flags & SW_CLOSING)
+ continue;
blk = blist_alloc(sp->sw_blist, npages);
- if (blk != SWAPBLK_NONE) {
- blk += sp->sw_first;
- sp->sw_used += npages;
- swap_pager_avail -= npages;
- swp_sizecheck();
- swdevhd = TAILQ_NEXT(sp, sw_list);
- goto done;
- }
+ if (blk != SWAPBLK_NONE)
+ break;
+ sp = TAILQ_NEXT(sp, sw_list);
+ } while (sp != swdevhd);
+ if (blk != SWAPBLK_NONE)
+ break;
+ mpages = (npages - 1) >> 1;
+ npages -= mpages + 1;
+ }
+ if (blk != SWAPBLK_NONE) {
+ npages += blist_grow_alloc(sp->sw_blist, mpages);
+ *io_npages = npages;
+ blk += sp->sw_first;
+ sp->sw_used += npages;
+ swap_pager_avail -= npages;
+ swp_sizecheck();
+ swdevhd = TAILQ_NEXT(sp, sw_list);
+ } else {
+ if (swap_pager_full != 2) {
+ printf("swap_pager_getswapspace(%d): failed\n",
+ *io_npages);
+ swap_pager_full = 2;
+ swap_pager_almost_full = 1;
}
- sp = TAILQ_NEXT(sp, sw_list);
- }
- if (swap_pager_full != 2) {
- printf("swap_pager_getswapspace(%d): failed\n", npages);
- swap_pager_full = 2;
- swap_pager_almost_full = 1;
+ swdevhd = NULL;
}
- swdevhd = NULL;
-done:
mtx_unlock(&sw_dev_mtx);
return (blk);
}
@@ -886,35 +898,32 @@
int
swap_pager_reserve(vm_object_t object, vm_pindex_t start, vm_size_t size)
{
- int n = 0;
- daddr_t blk = SWAPBLK_NONE;
- vm_pindex_t beg = start; /* save start index */
+ int i, n;
+ daddr_t blk;
+ vm_pindex_t end;
daddr_t addr, n_free, s_free;
+ end = start + size;
swp_pager_init_freerange(&s_free, &n_free);
VM_OBJECT_WLOCK(object);
- while (size) {
- if (n == 0) {
- n = BLIST_MAX_ALLOC;
- while ((blk = swp_pager_getswapspace(n)) == SWAPBLK_NONE) {
- n >>= 1;
- if (n == 0) {
- swp_pager_meta_free(object, beg, start - beg);
- VM_OBJECT_WUNLOCK(object);
- return (-1);
- }
- }
+ while (start < end) {
+ n = min(BLIST_MAX_ALLOC, end - start);
+ blk = swp_pager_getswapspace(&n);
+ if (blk == SWAPBLK_NONE) {
+ end -= size;
+ swp_pager_meta_free(object, end, start - end);
+ VM_OBJECT_WUNLOCK(object);
+ return (-1);
}
- addr = swp_pager_meta_build(object, start, blk);
- if (addr != SWAPBLK_NONE)
+ for (i = 0; i < n; ++i) {
+ addr = swp_pager_meta_build(object, start + i, blk + i);
+ if (addr == SWAPBLK_NONE)
+ continue;
swp_pager_update_freerange(&s_free, &n_free, addr);
- --size;
- ++start;
- ++blk;
- --n;
+ }
+ start += n;
}
swp_pager_freeswapspace(s_free, n_free);
- swp_pager_meta_free(object, start, n);
VM_OBJECT_WUNLOCK(object);
return (0);
}
@@ -1384,18 +1393,8 @@
n = min(BLIST_MAX_ALLOC, count - i);
n = min(n, nsw_cluster_max);
- /*
- * Get biggest block of swap we can. If we fail, fall
- * back and try to allocate a smaller block. Don't go
- * overboard trying to allocate space if it would overly
- * fragment swap.
- */
- while (
- (blk = swp_pager_getswapspace(n)) == SWAPBLK_NONE &&
- n > 4
- ) {
- n >>= 1;
- }
+ /* Get a block of swap of size up to size n. */
+ blk = swp_pager_getswapspace(&n);
if (blk == SWAPBLK_NONE) {
for (j = 0; j < n; ++j)
rtvals[i+j] = VM_PAGER_FAIL;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Apr 7, 3:22 AM (5 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31008410
Default Alt Text
D20001.id56467.diff (10 KB)
Attached To
Mode
D20001: Let swp_pager_getswapspace allocate bigger blocks
Attached
Detach File
Event Timeline
Log In to Comment