mm: swapoff prototype: frontswap handling added
Subsystems (2)
RFC v7 2/2 mm: swapoff prototype: frontswap handling added
The prototype of the new swapoff (without the quadratic complexity) presently ignores the frontswap case. Pass the count of pages_to_unuse down the page table walks in try_to_unuse(), and return from the walk when the desired number of pages has been swapped back in.
---
Changes since v6:
- In try_to_unuse(), copy pages_to_unuse to local fs_pages_to_unuse and pass by reference (instead of value) down the page table walk
- create #define FRONTSWAP_PAGES_UNUSED to pass special code back up the chain from unuse_pte_range()
- Test for this return code in try_to_unuse() and exit before orphans cleanup and retries
- In unuse_pte_range, move decrement of frontswap pages count next to call to delete_from_swap_cache(), so that it happens on every unused swap slot instead of every pte unmap
- Remove unnecessary goto after call to unuse_mm() in try_to_unuse()
- Remove blank line in shmem.c/shmem_unuse_inode()
--- mm/swapfile.c | 60 +++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 18 deletions(-)
mm/swapfile.c +42 -18
@@ -1144,9 +1144,11 @@ out_nolock:return ret; } +#define FRONTSWAP_PAGES_UNUSED 2static int unuse_pte_range (struct vm_area_struct *vma,pmd_t *pmd,unsigned long addr,unsigned long end, -unsigned int type) +unsigned int type, +unsigned long *fs_pages_to_unuse) {struct page *page;swp_entry_t entry;
@@ -1169,6 +1171,8 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,continue ;if (found_type != type)continue ; +if ((*fs_pages_to_unuse >0 ) && (!frontswap_test (si, offset))) +continue ; swap_map = &si->swap_map[offset];if (!swap_count (*swap_map))
@@ -1205,11 +1209,18 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,if (PageSwapCache (page) && (swap_count (*swap_map) ==0 )) {wait_on_page_writeback (page);delete_from_swap_cache (page); +if (*fs_pages_to_unuse >0 ) { + (*fs_pages_to_unuse)--; +if (*fs_pages_to_unuse ==0 ) + ret =FRONTSWAP_PAGES_UNUSED ; + } }SetPageDirty (page);unlock_page (page);page_cache_release (page); +if (ret ==FRONTSWAP_PAGES_UNUSED ) + goto out; try_next: pte =pte_offset_map (pmd, addr); }while (pte++, addr +=PAGE_SIZE , addr != end);
@@ -1220,7 +1231,8 @@ out:static inline int unuse_pmd_range (struct vm_area_struct *vma,pud_t *pud,unsigned long addr,unsigned long end, -unsigned int type) +unsigned int type, +unsigned long *fs_pages_to_unuse) {pmd_t *pmd;unsigned long next;
@@ -1231,8 +1243,9 @@ static inline int unuse_pmd_range(struct vm_area_struct *vma, pud_t *pud, next =pmd_addr_end (addr, end);if (pmd_none_or_trans_huge_or_clear_bad (pmd))continue ; - ret =unuse_pte_range (vma, pmd, addr, next, type); -if (ret <0 ) + ret =unuse_pte_range (vma, pmd, addr, next, type, + fs_pages_to_unuse); +if (ret <0 || ret ==2 )return ret; }while (pmd++, addr = next, addr != end);return 0 ;
@@ -1240,7 +1253,8 @@ static inline int unuse_pmd_range(struct vm_area_struct *vma, pud_t *pud,static inline int unuse_pud_range (struct vm_area_struct *vma,pgd_t *pgd,unsigned long addr,unsigned long end, -unsigned int type) +unsigned int type, +unsigned long *fs_pages_to_unuse) {pud_t *pud;unsigned long next;
@@ -1251,14 +1265,16 @@ static inline int unuse_pud_range(struct vm_area_struct *vma, pgd_t *pgd, next =pud_addr_end (addr, end);if (pud_none_or_clear_bad (pud))continue ; - ret =unuse_pmd_range (vma, pud, addr, next, type); -if (ret <0 ) + ret =unuse_pmd_range (vma, pud, addr, next, type, + fs_pages_to_unuse); +if (ret <0 || ret ==2 )return ret; }while (pud++, addr = next, addr != end);return 0 ; } -static int unuse_vma (struct vm_area_struct *vma,unsigned int type) +static int unuse_vma (struct vm_area_struct *vma,unsigned int type, +unsigned long *fs_pages_to_unuse) {pgd_t *pgd;unsigned long addr, end, next;
@@ -1272,14 +1288,16 @@ static int unuse_vma(struct vm_area_struct *vma, unsigned int type) next =pgd_addr_end (addr, end);if (pgd_none_or_clear_bad (pgd))continue ; - ret =unuse_pud_range (vma, pgd, addr, next, type); -if (ret <0 ) + ret =unuse_pud_range (vma, pgd, addr, next, type, + fs_pages_to_unuse); +if (ret <0 || ret ==2 )return ret; }while (pgd++, addr = next, addr != end);return 0 ; } -static int unuse_mm (struct mm_struct *mm,unsigned int type) +static int unuse_mm (struct mm_struct *mm,unsigned int type, +unsigned long *fs_pages_to_unuse) {struct vm_area_struct *vma;int ret =0 ;
@@ -1287,7 +1305,7 @@ static int unuse_mm(struct mm_struct *mm, unsigned int type)down_read (&mm->mmap_sem);for (vma = mm->mmap; vma; vma = vma->vm_next) {if (vma->anon_vma) { - ret =unuse_vma (vma, type); + ret =unuse_vma (vma, type, fs_pages_to_unuse);if (ret)break ; }
@@ -1342,7 +1360,6 @@ static unsigned int find_next_to_unuse(struct swap_info_struct *si,return i; } -/* TODO: frontswap */ #define MAX_RETRIES 3int try_to_unuse (unsigned int type,bool frontswap,unsigned long pages_to_unuse)
@@ -1354,10 +1371,14 @@ int try_to_unuse(unsigned int type, bool frontswap,struct swap_info_struct *si = swap_info[type];struct page *page;swp_entry_t entry; +unsigned long fs_pages_to_unuse =0 ;unsigned int i =0 ;unsigned int oldi =0 ;int retries =0 ; +if (frontswap) + fs_pages_to_unuse = pages_to_unuse; + retry: retval =shmem_unuse (type);if (retval)
@@ -1381,9 +1402,7 @@ retry:mmput (prev_mm); prev_mm = mm; - retval =unuse_mm (mm, type); -if (retval) - goto out_put; + retval =unuse_mm (mm, type, &fs_pages_to_unuse);/* * Make sure that we aren't completely killing
@@ -1396,8 +1415,13 @@ retry: out_put:mmput (prev_mm); -if (retval) +if (retval <0 ) + goto out; +if (retval ==FRONTSWAP_PAGES_UNUSED ) { + retval =0 ; goto out; + } +while ((i =find_next_to_unuse (si, i, frontswap)) !=0 ) {/* * under global memory pressure, swap entries
@@ -1410,7 +1434,7 @@ out_put:*/ if (i < oldi) { retries++; -if (retries >MAX_RETRIES ) { +if ((retries >MAX_RETRIES ) || frontswap) { retval = -EBUSY ; goto out; }
Signature · 7 lines
1.8.3.2 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerQuoted 5 lines · On Thu, 19 Mar 2015 03:55:45 -0700 Kelley Nielsen <[email protected]> wrote:
The prototype of the new swapoff (without the quadratic complexity) presently ignores the frontswap case. Pass the count of
pages_to_unusedown the page table walks intry_to_unuse(), and return from the walk when the desired number of pages has been swapped back in.
Does this fix the "TODO" in [1/2]?
Do you think this patchset is ready for testing (while Hugh reviews it :)), or is there some deeper reason behind the "RFC"?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Rik van Riel
Acked-byQuoted 8 lines · Andrew Morton
Quoted 5 lines · On Thu, 19 Mar 2015 03:55:45 -0700 Kelley Nielsen <[email protected]> wrote:
The prototype of the new swapoff (without the quadratic complexity) presently ignores the frontswap case. Pass the count of
pages_to_unusedown the page table walks intry_to_unuse(), and return from the walk when the desired number of pages has been swapped back in.
Quoted 4 lines
Does this fix the "TODO" in [1/2]?
Do you think this patchset is ready for testing (while Hugh reviews it :)), or is there some deeper reason behind the "RFC"?
The patches look good to me, and this seems to
address the TODO from patch 1/2.
Kelley put in a heroic amount of effort tracking down and fixing the corner cases I failed to anticipate before putting this up as an OPW internship project.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 11 lines · Kelley Nielsen
The prototype of the new swapoff (without the quadratic complexity) presently ignores the frontswap case. Pass the count of
pages_to_unusedown the page table walks intry_to_unuse(), and return from the walk when the desired number of pages has been swapped back in.Signed-off-by Kelley Nielsen <[email protected]>---
Changes since v6:
Quoted 11 lines
- In
try_to_unuse(), copypages_to_unuseto localfs_pages_to_unuseand pass by reference (instead of value) down the page table walk
- create #defineFRONTSWAP_PAGES_UNUSEDto pass special code back up the chain fromunuse_pte_range()
- Test for this return code intry_to_unuse()and exit before orphans cleanup and retries
- Inunuse_pte_range, move decrement of frontswap pages count next to call todelete_from_swap_cache(), so that it happens on every unused swap slot instead of every pte unmap
- Remove unnecessary goto after call tounuse_mm()intry_to_unuse()
- Remove blank line in shmem.c/shmem_unuse_inode()
Some of those seem just cleanups to fold into the previous patch.
I'd be okay if you just folded the two patches together, but if you prefer to handle the frontswap partial case in this separate patch, that's fine.
Quoted 3 lines
--- mm/swapfile.c | 60 +++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 18 deletions(-)
This is incomplete: why no change to shmem_unuse_inode()? You're often unable to satisfy frontswap's demand without that.
mm/swapfile.c out_nolock: · line 1147
Quoted 9 lines
mm/swapfile.c +1
-0@@ -1144,9 +1144,11 @@ out_nolock:return ret; } +#define FRONTSWAP_PAGES_UNUSED 2
Okay, that'll work. But I wonder why you chose 2 rather than the more obvious 1 - coupled with the name, it makes it sound like a number of pages.
(Personally I'd have gone for a different approach, returning the negative error, or the number of pages still to be unused: that has the benefit that you get out of long scans sooner, even in the non-frontswap case: once si->inuse_pages falls to 0, there's no more work to be done. Or perhaps you tried that way, but it doesn't work out - might need exporting info from swapfile.c to shmem.c.)
Quoted 9 lines
mm/swapfile.c +2
-1static int unuse_pte_range (struct vm_area_struct *vma,pmd_t *pmd,unsigned long addr,unsigned long end, -unsigned int type) +unsigned int type, +unsigned long *fs_pages_to_unuse) {struct page *page;swp_entry_t entry;
mm/swapfile.c static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd, · line 1175
Quoted 5 lines
mm/swapfile.c +2
-0@@ -1169,6 +1171,8 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,continue ;if (found_type != type)continue ; +if ((*fs_pages_to_unuse >0 ) && (!frontswap_test (si, offset))) +continue ;
There's a tab too many on the line above.
Quoted 32 lines
mm/swapfile.c +9
-1swap_map = &si->swap_map[offset];if (!swap_count (*swap_map))@@ -1205,11 +1209,18 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,if (PageSwapCache (page) && (swap_count (*swap_map) ==0 )) {wait_on_page_writeback (page);delete_from_swap_cache (page); +if (*fs_pages_to_unuse >0 ) { + (*fs_pages_to_unuse)--; +if (*fs_pages_to_unuse ==0 ) + ret =FRONTSWAP_PAGES_UNUSED ; + } }SetPageDirty (page);unlock_page (page);page_cache_release (page); +if (ret ==FRONTSWAP_PAGES_UNUSED ) + goto out; try_next: pte =pte_offset_map (pmd, addr); }while (pte++, addr +=PAGE_SIZE , addr != end);@@ -1220,7 +1231,8 @@ out:static inline int unuse_pmd_range (struct vm_area_struct *vma,pud_t *pud,unsigned long addr,unsigned long end, -unsigned int type) +unsigned int type, +unsigned long *fs_pages_to_unuse) {pmd_t *pmd;unsigned long next;
mm/swapfile.c static inline int unuse_pmd_range(struct vm_area_struct *vma, pud_t *pud, · line 1248
Quoted 8 lines
mm/swapfile.c +3
-2@@ -1231,8 +1243,9 @@ static inline int unuse_pmd_range(struct vm_area_struct *vma, pud_t *pud, next =pmd_addr_end (addr, end);if (pmd_none_or_trans_huge_or_clear_bad (pmd))continue ; - ret =unuse_pte_range (vma, pmd, addr, next, type); -if (ret <0 ) + ret =unuse_pte_range (vma, pmd, addr, next, type, + fs_pages_to_unuse); +if (ret <0 || ret ==2 )
FRONTSWAP_PAGES_UNUSED there.
Quoted 14 lines
mm/swapfile.c +2
-1return ret; }while (pmd++, addr = next, addr != end);return 0 ;@@ -1240,7 +1253,8 @@ static inline int unuse_pmd_range(struct vm_area_struct *vma, pud_t *pud,static inline int unuse_pud_range (struct vm_area_struct *vma,pgd_t *pgd,unsigned long addr,unsigned long end, -unsigned int type) +unsigned int type, +unsigned long *fs_pages_to_unuse) {pud_t *pud;unsigned long next;
mm/swapfile.c static inline int unuse_pud_range(struct vm_area_struct *vma, pgd_t *pgd, · line 1270
Quoted 8 lines
mm/swapfile.c +3
-2@@ -1251,14 +1265,16 @@ static inline int unuse_pud_range(struct vm_area_struct *vma, pgd_t *pgd, next =pud_addr_end (addr, end);if (pud_none_or_clear_bad (pud))continue ; - ret =unuse_pmd_range (vma, pud, addr, next, type); -if (ret <0 ) + ret =unuse_pmd_range (vma, pud, addr, next, type, + fs_pages_to_unuse); +if (ret <0 || ret ==2 )
FRONTSWAP_PAGES_UNUSED there.
Quoted 12 lines
mm/swapfile.c +2
-1return ret; }while (pud++, addr = next, addr != end);return 0 ; } -static int unuse_vma (struct vm_area_struct *vma,unsigned int type) +static int unuse_vma (struct vm_area_struct *vma,unsigned int type, +unsigned long *fs_pages_to_unuse) {pgd_t *pgd;unsigned long addr, end, next;
mm/swapfile.c static int unuse_vma(struct vm_area_struct *vma, unsigned int type) · line 1293
Quoted 8 lines
mm/swapfile.c +3
-2@@ -1272,14 +1288,16 @@ static int unuse_vma(struct vm_area_struct *vma, unsigned int type) next =pgd_addr_end (addr, end);if (pgd_none_or_clear_bad (pgd))continue ; - ret =unuse_pud_range (vma, pgd, addr, next, type); -if (ret <0 ) + ret =unuse_pud_range (vma, pgd, addr, next, type, + fs_pages_to_unuse); +if (ret <0 || ret ==2 )
FRONTSWAP_PAGES_UNUSED there.
Quoted 30 lines
mm/swapfile.c +3
-3return ret; }while (pgd++, addr = next, addr != end);return 0 ; } -static int unuse_mm (struct mm_struct *mm,unsigned int type) +static int unuse_mm (struct mm_struct *mm,unsigned int type, +unsigned long *fs_pages_to_unuse) {struct vm_area_struct *vma;int ret =0 ;@@ -1287,7 +1305,7 @@ static int unuse_mm(struct mm_struct *mm, unsigned int type)down_read (&mm->mmap_sem);for (vma = mm->mmap; vma; vma = vma->vm_next) {if (vma->anon_vma) { - ret =unuse_vma (vma, type); + ret =unuse_vma (vma, type, fs_pages_to_unuse);if (ret)break ; }@@ -1342,7 +1360,6 @@ static unsigned int find_next_to_unuse(struct swap_info_struct *si,return i; } -/* TODO: frontswap */ #define MAX_RETRIES 3int try_to_unuse (unsigned int type,bool frontswap,unsigned long pages_to_unuse)@@ -1354,10 +1371,14 @@ int try_to_unuse(unsigned int type, bool frontswap,struct swap_info_struct *si = swap_info[type];
mm/swapfile.c int try_to_unuse(unsigned int type, bool frontswap, · line 1381
Quoted 10 lines
mm/swapfile.c +4
-0struct page *page;swp_entry_t entry; +unsigned long fs_pages_to_unuse =0 ;unsigned int i =0 ;unsigned int oldi =0 ;int retries =0 ; +if (frontswap) + fs_pages_to_unuse = pages_to_unuse; +
If you wish. But I can't see why you don't just use pages_to_unuse throughout. (That "bool frontswap" in the interface was always silly.)
Quoted 30 lines
mm/swapfile.c +7
-4retry: retval =shmem_unuse (type);if (retval)@@ -1381,9 +1402,7 @@ retry:mmput (prev_mm); prev_mm = mm; - retval =unuse_mm (mm, type); -if (retval) - goto out_put; + retval =unuse_mm (mm, type, &fs_pages_to_unuse);/* * Make sure that we aren't completely killing @@ -1396,8 +1415,13 @@ retry: out_put:mmput (prev_mm); -if (retval) +if (retval <0 ) + goto out; +if (retval ==FRONTSWAP_PAGES_UNUSED ) { + retval =0 ; goto out; + } +while ((i =find_next_to_unuse (si, i, frontswap)) !=0 ) {/* * under global memory pressure, swap entries
mm/swapfile.c out_put: · line 1437
Quoted 5 lines
mm/swapfile.c +1
-1@@ -1410,7 +1434,7 @@ out_put:*/ if (i < oldi) { retries++; -if (retries >MAX_RETRIES ) { +if ((retries >MAX_RETRIES ) || frontswap) {
I don't understand why you omit retrying in the frontswap case?
Quoted 5 lines
mm/swapfile.c +0
-0retval = -EBUSY ; goto out; }Signature · 1 line
1.8.3.2
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>