ANDROID: 16K: Fix swapfile header
The swap header is usually in the first page, with the magic in the last 10 bytes of the page. In the emulated mode, mkswap tools might place the magic on the last 10 bytes of __PAGE_SIZE-ed page. Check if this is the case and place the magic on the first page and clear the magic from the end of the emulated page if it was found there; since the kernel still uses a 4KiB page size. Bug: 383389337 Bug: 366098040 Test: atest vts_ltp_test_x86_64 Change-Id: I0882a26b2e8a490fa82f490b1748903a25ff5652 Signed-off-by: Kalesh Singh <kaleshsingh@google.com>
This commit is contained in:
committed by
Carlos Llamas
parent
53ab86eb55
commit
03ce5534fc
@@ -162,6 +162,9 @@ static __always_inline void __filemap_fixup(unsigned long addr, unsigned long pr
|
||||
}
|
||||
|
||||
extern void __fold_filemap_fixup_entry(struct vma_iterator *iter, unsigned long *end);
|
||||
|
||||
extern int __fixup_swap_header(struct file *swap_file, struct address_space *mapping);
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
#endif /* __LINUX_PAGE_SIZE_COMPAT_H */
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/page_size_compat.h>
|
||||
#include <linux/swap.h>
|
||||
|
||||
#define MIN_PAGE_SHIFT_COMPAT (PAGE_SHIFT + 1)
|
||||
#define MAX_PAGE_SHIFT_COMPAT 16 /* Max of 64KB */
|
||||
@@ -259,3 +261,57 @@ void __fold_filemap_fixup_entry(struct vma_iterator *iter, unsigned long *end)
|
||||
/* Rewind iterator */
|
||||
vma_prev(iter);
|
||||
}
|
||||
|
||||
/*
|
||||
* The swap header is usually in the first page, with the magic in the last 10 bytes.
|
||||
* of the page. In the emulated mode, mkswap tools might place the magic on the last
|
||||
* 10 bytes of __PAGE_SIZE-ed page. Check if this is the case and place the magic on
|
||||
* the first page and clear the magic from the original page in which it was found.
|
||||
*
|
||||
*/
|
||||
int __fixup_swap_header(struct file *swap_file, struct address_space *mapping)
|
||||
{
|
||||
union swap_header *swap_header;
|
||||
struct page *header_page = NULL;
|
||||
struct page *magic_page = NULL;
|
||||
int index;
|
||||
int error = 0;
|
||||
const char* magic = "SWAPSPACE2";
|
||||
|
||||
if (__PAGE_SHIFT == PAGE_SHIFT)
|
||||
return 0;
|
||||
|
||||
index = (1 << (__PAGE_SHIFT - PAGE_SHIFT)) - 1;
|
||||
magic_page = read_mapping_page(mapping, index, swap_file);
|
||||
if (IS_ERR(magic_page)) {
|
||||
pgcompat_err("Failed reading swap magic page");
|
||||
return PTR_ERR(magic_page);
|
||||
}
|
||||
swap_header = kmap(magic_page);
|
||||
|
||||
/* Nothing to do; mkswap tool may have hardcoded a 4096 page size */
|
||||
if (memcmp(magic, swap_header->magic.magic, 10))
|
||||
goto free_magic;
|
||||
|
||||
memset(swap_header->magic.magic, 0, 10);
|
||||
|
||||
index = 0;
|
||||
header_page = read_mapping_page(mapping, index, swap_file);
|
||||
if (IS_ERR(header_page)) {
|
||||
pgcompat_err("Failed reading swap header page");
|
||||
error = PTR_ERR(header_page);
|
||||
goto free_magic;
|
||||
}
|
||||
swap_header = kmap(header_page);
|
||||
|
||||
memcpy(swap_header->magic.magic, magic, 10);
|
||||
|
||||
kunmap(header_page);
|
||||
put_page(header_page);
|
||||
|
||||
free_magic:
|
||||
kunmap(magic_page);
|
||||
put_page(magic_page);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/page_size_compat.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/shmem_fs.h>
|
||||
@@ -3458,6 +3459,13 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
|
||||
error = -EINVAL;
|
||||
goto bad_swap_unlock_inode;
|
||||
}
|
||||
|
||||
error = __fixup_swap_header(swap_file, mapping);
|
||||
if (error) {
|
||||
pgcompat_err("Failed __fixup_swap_header");
|
||||
goto bad_swap_unlock_inode;
|
||||
}
|
||||
|
||||
folio = read_mapping_folio(mapping, 0, swap_file);
|
||||
if (IS_ERR(folio)) {
|
||||
error = PTR_ERR(folio);
|
||||
|
||||
Reference in New Issue
Block a user