Skip to content

Commit d198ad5

Browse files
committed
swap_pager_getpages(): some pages from ma[] might be bogus
Same as vnode_pager_generic_getpages_async(), swap_pager_getpages() must handle a possibility of the provided page run to include bogus_page on some positions, when called from sendfile_swapin(). The swap pager is used for tmpfs vnodes. In particular, the bogus page must not be used for pindex calculation, we better not update the flags on it or wait for the flag clearing, and we must not call vm_page_valid() because the function expects busy page. This was bisected down to 72ddb6d (unix: increase net.local.(stream|seqpacket).(recv|send)space to 64 KiB), which is somewhat surprising, but apparently reasonable because it allowed the run of more than one page for page-in from the swap pager, which now might include valid pages replaced by bogus one. In collaboration with: pho Reviewed by: glebius, markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D54713
1 parent b02ddb5 commit d198ad5

File tree

1 file changed

+29
-8
lines changed

1 file changed

+29
-8
lines changed

sys/vm/swap_pager.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,14 +1362,22 @@ static int
13621362
swap_pager_getpages_locked(struct pctrie_iter *blks, vm_object_t object,
13631363
vm_page_t *ma, int count, int *a_rbehind, int *a_rahead, struct buf *bp)
13641364
{
1365+
vm_page_t m;
13651366
vm_pindex_t pindex;
1366-
int rahead, rbehind;
1367+
int i, rahead, rbehind;
13671368

13681369
VM_OBJECT_ASSERT_WLOCKED(object);
13691370

13701371
KASSERT((object->flags & OBJ_SWAP) != 0,
13711372
("%s: object not swappable", __func__));
1372-
pindex = ma[0]->pindex;
1373+
for (i = 0; i < count; i++) {
1374+
m = ma[i];
1375+
if (m != bogus_page) {
1376+
pindex = m->pindex - i;
1377+
break;
1378+
}
1379+
}
1380+
MPASS(i != count);
13731381
if (!swp_pager_haspage_iter(pindex, &rbehind, &rahead, blks)) {
13741382
VM_OBJECT_WUNLOCK(object);
13751383
uma_zfree(swrbuf_zone, bp);
@@ -1399,8 +1407,11 @@ swap_pager_getpages_locked(struct pctrie_iter *blks, vm_object_t object,
13991407
KASSERT(bp->b_npages <= PBUF_PAGES,
14001408
("bp_npages %d (rb %d c %d ra %d) not less than PBUF_PAGES %jd",
14011409
bp->b_npages, rbehind, count, rahead, (uintmax_t)PBUF_PAGES));
1402-
for (int i = 0; i < bp->b_npages; i++)
1403-
bp->b_pages[i]->oflags |= VPO_SWAPINPROG;
1410+
for (i = 0; i < bp->b_npages; i++) {
1411+
m = bp->b_pages[i];
1412+
if (m != bogus_page)
1413+
m->oflags |= VPO_SWAPINPROG;
1414+
}
14041415
bp->b_blkno = swp_pager_meta_lookup(blks, pindex - rbehind);
14051416
KASSERT(bp->b_blkno != SWAPBLK_NONE,
14061417
("no swap blocking containing %p(%jx)", object, (uintmax_t)pindex));
@@ -1448,8 +1459,14 @@ swap_pager_getpages_locked(struct pctrie_iter *blks, vm_object_t object,
14481459
*/
14491460
VM_OBJECT_WLOCK(object);
14501461
/* This could be implemented more efficiently with aflags */
1451-
while ((ma[0]->oflags & VPO_SWAPINPROG) != 0) {
1452-
ma[0]->oflags |= VPO_SWAPSLEEP;
1462+
for (i = 0; i < count; i++) {
1463+
m = ma[i];
1464+
if (m != bogus_page)
1465+
break;
1466+
}
1467+
MPASS(i != count);
1468+
while ((m->oflags & VPO_SWAPINPROG) != 0) {
1469+
m->oflags |= VPO_SWAPSLEEP;
14531470
VM_CNT_INC(v_intrans);
14541471
if (VM_OBJECT_SLEEP(object, &object->handle, PSWP,
14551472
"swread", hz * 20)) {
@@ -1463,9 +1480,10 @@ swap_pager_getpages_locked(struct pctrie_iter *blks, vm_object_t object,
14631480
/*
14641481
* If we had an unrecoverable read error pages will not be valid.
14651482
*/
1466-
for (int i = 0; i < count; i++)
1467-
if (ma[i]->valid != VM_PAGE_BITS_ALL)
1483+
for (i = 0; i < count; i++) {
1484+
if (ma[i] != bogus_page && ma[i]->valid != VM_PAGE_BITS_ALL)
14681485
return (VM_PAGER_ERROR);
1486+
}
14691487

14701488
return (VM_PAGER_OK);
14711489

@@ -1730,6 +1748,9 @@ swp_pager_async_iodone(struct buf *bp)
17301748
for (i = 0; i < bp->b_npages; ++i) {
17311749
vm_page_t m = bp->b_pages[i];
17321750

1751+
if (m == bogus_page)
1752+
continue;
1753+
17331754
m->oflags &= ~VPO_SWAPINPROG;
17341755
if (m->oflags & VPO_SWAPSLEEP) {
17351756
m->oflags &= ~VPO_SWAPSLEEP;

0 commit comments

Comments
 (0)