mm: Swap checksum
Subsystems (5)
v2 cover mm: Swap checksum
Add support for checksumming the swap pages written to disk, using the same checksum as btrfs (crc32c). Since the contents of the swap do not matter after a shutdown, the checksum is kept in memory only.
This protects against silent corruption of the swap caused by hardware problems, the same way the btrfs checksum protects against silent corruption of the filesystem. It is useful even with CONFIG_BLK_DEV_INTEGRITY because it also protects against reads of stale data.
The checksum is done in the swap layer (instead of in a separate block device or in the block layer) to allow the checksums to be tracked together with the rest of swap state (also allowing later for things like Avi Kivity's suggestions of keeping the checksum in the pte when possible and converting zeroed pages to a pte_none), to better allow for different things to be done by the software suspend code (which writes to the same place but has different needs), to simplify configuration (no need to edit the fstab), and because it felt the most natural layer to do it.
Note that this code does not currently checksum the software suspend image. That will need to be done later.
Lightly tested on a x86 VM.
Changes since -v1:
Rebase to 2.6.35-rc1 (code moved from swap.c to block_io.c) Use bio_data_dir() instead of acessing bi_rw directly Use __read_mostly for swapcsum_workqueue
Include highmem.h instead of pagemap.h
Cesar Eduardo Barros (3):
mm/swapfile.c: better messages for swap_info_get kernel/power/block_io.c: do not use end_swap_bio_read
mm: Swap checksum
include/linux/swap.h | 31 ++++++- kernel/power/block_io.c | 22 +++++- mm/Kconfig | 22 +++++ mm/Makefile | 1 + mm/page_io.c | 92 +++++++++++++++++-- mm/swapcsum.c | 94 ++++++++++++++++++++ mm/swapfile.c | 187 +++++++++++++++++++++++++++++++++++++-- 7 files changed, 431 insertions(+), 18 deletions(-) create mode 100644 mm/swapcsum.c
Signature · 9 lines
Cesar Eduardo Barros [email protected] [email protected] -- 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>
PATCH v2 1/3 mm/swapfile.c: better messages for swap_info_get
swap_info_get() is used for more than swap_free().
Use "swap_info_get:" instead of "swap_free:" in the error messages.
--- mm/swapfile.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
mm/swapfile.c +4 -4
@@ -525,16 +525,16 @@ static struct swap_info_struct *swap_info_get(swp_entry_t entry)return p; bad_free: -printk (KERN_ERR "swap_free: %s%08lx\n" , Unused_offset, entry.val); +printk (KERN_ERR "swap_info_get: %s%08lx\n" , Unused_offset, entry.val); goto out; bad_offset: -printk (KERN_ERR "swap_free: %s%08lx\n" , Bad_offset, entry.val); +printk (KERN_ERR "swap_info_get: %s%08lx\n" , Bad_offset, entry.val); goto out; bad_device: -printk (KERN_ERR "swap_free: %s%08lx\n" , Unused_file, entry.val); +printk (KERN_ERR "swap_info_get: %s%08lx\n" , Unused_file, entry.val); goto out; bad_nofile: -printk (KERN_ERR "swap_free: %s%08lx\n" , Bad_file, entry.val); +printk (KERN_ERR "swap_info_get: %s%08lx\n" , Bad_file, entry.val); out:return NULL ; }
Signature · 1 line
1.6.6.1
PATCH v2 1/3 mm/swapfile.c: better messages for swap_info_get
In reply to Cesar Eduardo Barrosswap_info_get() is used for more than swap_free().
Use "swap_info_get:" instead of "swap_free:" in the error messages.
--- mm/swapfile.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
mm/swapfile.c +4 -4
@@ -525,16 +525,16 @@ static struct swap_info_struct *swap_info_get(swp_entry_t entry)return p; bad_free: -printk (KERN_ERR "swap_free: %s%08lx\n" , Unused_offset, entry.val); +printk (KERN_ERR "swap_info_get: %s%08lx\n" , Unused_offset, entry.val); goto out; bad_offset: -printk (KERN_ERR "swap_free: %s%08lx\n" , Bad_offset, entry.val); +printk (KERN_ERR "swap_info_get: %s%08lx\n" , Bad_offset, entry.val); goto out; bad_device: -printk (KERN_ERR "swap_free: %s%08lx\n" , Unused_file, entry.val); +printk (KERN_ERR "swap_info_get: %s%08lx\n" , Unused_file, entry.val); goto out; bad_nofile: -printk (KERN_ERR "swap_free: %s%08lx\n" , Bad_file, entry.val); +printk (KERN_ERR "swap_info_get: %s%08lx\n" , Bad_file, entry.val); out:return NULL ; }
Signature · 7 lines
1.6.6.1 -- 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>
PATCH v2 2/3 kernel/power/block_io.c: do not use end_swap_bio_read
In reply to Cesar Eduardo BarrosThe swap checksum patches will change end_swap_bio_read to also verify the page's checksum. This is not compatible with its use at submit() from kernel/power/block_io.c.
Make kernel/power/block_io.c use a private copy of end_swap_bio_read, and modify it to not say "Read-error" if the error was on a write.
Changes since -v1:
Rebase to 2.6.35-rc1 (code moved from swap.c to block_io.c) Use bio_data_dir() instead of acessing bi_rw directly
--- include/linux/swap.h | 1 - kernel/power/block_io.c | 22 +++++++++++++++++++++- mm/page_io.c | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-)
include/linux/swap.h +0 -1
@@ -293,7 +293,6 @@ extern void swap_unplug_io_fn(struct backing_dev_info *, struct page *);/* linux/mm/page_io.c */ extern int swap_readpage (struct page *);extern int swap_writepage (struct page *page,struct writeback_control *wbc); -extern void end_swap_bio_read (struct bio *bio,int err);/* linux/mm/swap_state.c */ extern struct address_space swapper_space;
kernel/power/block_io.c +21 -1
@@ -14,6 +14,26 @@#include "power.h" +static void end_swap_bio (struct bio *bio,int err) +{ +const int uptodate =test_bit (BIO_UPTODATE , &bio->bi_flags); +struct page *page = bio->bi_io_vec[0 ].bv_page; + +if (!uptodate) { +SetPageError (page); +ClearPageUptodate (page); +printk (KERN_ALERT "%s-error on swap-device (%u:%u:%Lu)\n" , +bio_data_dir (bio) ==READ ?"Read" :"Write" , +imajor (bio->bi_bdev->bd_inode), +iminor (bio->bi_bdev->bd_inode), + (unsigned long long )bio->bi_sector); + }else { +SetPageUptodate (page); + } +unlock_page (page); +bio_put (bio); +} +/** * submit - submit BIO request. * @rw: READ or WRITE.
@@ -34,7 +54,7 @@ static int submit(int rw, struct block_device *bdev, sector_t sector, bio =bio_alloc (__GFP_WAIT | __GFP_HIGH,1 ); bio->bi_sector = sector; bio->bi_bdev = bdev; - bio->bi_end_io = end_swap_bio_read; + bio->bi_end_io = end_swap_bio;if (bio_add_page (bio, page,PAGE_SIZE ,0 ) <PAGE_SIZE ) { printk(KERN_ERR "PM: Adding page to bio failed at %llu\n",
mm/page_io.c +1 -1
@@ -66,7 +66,7 @@ static void end_swap_bio_write(struct bio *bio, int err)bio_put (bio); } -void end_swap_bio_read (struct bio *bio,int err) +static void end_swap_bio_read (struct bio *bio,int err) {const int uptodate =test_bit (BIO_UPTODATE , &bio->bi_flags);struct page *page = bio->bi_io_vec[0 ].bv_page;
Signature · 1 line
1.6.6.1
PATCH v2 2/3 kernel/power/block_io.c: do not use end_swap_bio_read
In reply to Cesar Eduardo BarrosThe swap checksum patches will change end_swap_bio_read to also verify the page's checksum. This is not compatible with its use at submit() from kernel/power/block_io.c.
Make kernel/power/block_io.c use a private copy of end_swap_bio_read, and modify it to not say "Read-error" if the error was on a write.
Changes since -v1:
Rebase to 2.6.35-rc1 (code moved from swap.c to block_io.c) Use bio_data_dir() instead of acessing bi_rw directly
--- include/linux/swap.h | 1 - kernel/power/block_io.c | 22 +++++++++++++++++++++- mm/page_io.c | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-)
include/linux/swap.h +0 -1
@@ -293,7 +293,6 @@ extern void swap_unplug_io_fn(struct backing_dev_info *, struct page *);/* linux/mm/page_io.c */ extern int swap_readpage (struct page *);extern int swap_writepage (struct page *page,struct writeback_control *wbc); -extern void end_swap_bio_read (struct bio *bio,int err);/* linux/mm/swap_state.c */ extern struct address_space swapper_space;
kernel/power/block_io.c +21 -1
@@ -14,6 +14,26 @@#include "power.h" +static void end_swap_bio (struct bio *bio,int err) +{ +const int uptodate =test_bit (BIO_UPTODATE , &bio->bi_flags); +struct page *page = bio->bi_io_vec[0 ].bv_page; + +if (!uptodate) { +SetPageError (page); +ClearPageUptodate (page); +printk (KERN_ALERT "%s-error on swap-device (%u:%u:%Lu)\n" , +bio_data_dir (bio) ==READ ?"Read" :"Write" , +imajor (bio->bi_bdev->bd_inode), +iminor (bio->bi_bdev->bd_inode), + (unsigned long long )bio->bi_sector); + }else { +SetPageUptodate (page); + } +unlock_page (page); +bio_put (bio); +} +/** * submit - submit BIO request. * @rw: READ or WRITE.
@@ -34,7 +54,7 @@ static int submit(int rw, struct block_device *bdev, sector_t sector, bio =bio_alloc (__GFP_WAIT | __GFP_HIGH,1 ); bio->bi_sector = sector; bio->bi_bdev = bdev; - bio->bi_end_io = end_swap_bio_read; + bio->bi_end_io = end_swap_bio;if (bio_add_page (bio, page,PAGE_SIZE ,0 ) <PAGE_SIZE ) { printk(KERN_ERR "PM: Adding page to bio failed at %llu\n",
mm/page_io.c +1 -1
@@ -66,7 +66,7 @@ static void end_swap_bio_write(struct bio *bio, int err)bio_put (bio); } -void end_swap_bio_read (struct bio *bio,int err) +static void end_swap_bio_read (struct bio *bio,int err) {const int uptodate =test_bit (BIO_UPTODATE , &bio->bi_flags);struct page *page = bio->bi_io_vec[0 ].bv_page;
Signature · 7 lines
1.6.6.1 -- 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>
PATCH v2 3/3 mm: Swap checksum
In reply to Cesar Eduardo BarrosAdd support for checksumming the swap pages written to disk, using the same checksum as btrfs (crc32c). Since the contents of the swap do not matter after a shutdown, the checksum is kept in memory only.
This protects against silent corruption of the swap caused by hardware problems, the same way the btrfs checksum protects against silent corruption of the filesystem. It is useful even with CONFIG_BLK_DEV_INTEGRITY because it also protects against reads of stale data.
The checksum is done in the swap layer (instead of in a separate block device or in the block layer) to allow the checksums to be tracked together with the rest of swap state (also allowing later for things like Avi Kivity's suggestions of keeping the checksum in the pte when possible and converting zeroed pages to a pte_none), to better allow for different things to be done by the software suspend code (which writes to the same place but has different needs), to simplify configuration (no need to edit the fstab), and because it felt the most natural layer to do it.
Note that this code does not currently checksum the software suspend image. That will need to be done later.
Lightly tested on a x86 VM.
Changes since -v1:
Use __read_mostly for swapcsum_workqueue
Include highmem.h instead of pagemap.h
--- include/linux/swap.h | 30 ++++++++ mm/Kconfig | 22 ++++++ mm/Makefile | 1 + mm/page_io.c | 90 +++++++++++++++++++++++--- mm/swapcsum.c | 94 ++++++++++++++++++++++++++ mm/swapfile.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 405 insertions(+), 11 deletions(-) create mode 100644 mm/swapcsum.c
include/linux/swap.h +30 -0
@@ -15,6 +15,9 @@struct notifier_block ;struct bio ; +struct bio_vec ; + +struct workqueue_struct ;#define SWAP_FLAG_PREFER 0x8000/* set if swap priority specified */ #define SWAP_FLAG_PRIO_MASK 0x7fff
@@ -182,6 +185,10 @@ struct swap_info_struct {struct swap_extent *curr_swap_extent;struct swap_extent first_swap_extent;struct block_device *bdev;/* swap device or bdev of swap file */ +#ifdef CONFIG_SWAP_CHECKSUM +unsigned short *csum_count;/* usage count of a csum page */ +u32 **csum;/* vmalloc'ed array of swap csums */ +#endif struct file *swap_file;/* seldom referenced */ unsigned int old_block_size;/* seldom referenced */ };
@@ -371,6 +378,29 @@ static inline void mem_cgroup_uncharge_swap(swp_entry_t ent) }#endif +#ifdef CONFIG_SWAP_CHECKSUM +/* linux/mm/swapfile.c */ +extern int swap_csum_set (swp_entry_t entry,u32 crc); +extern int swap_csum_get (swp_entry_t entry,u32 *crc); + +/* linux/mm/swapcsum.c */ +extern bool noswapcsum__read_mostly ; +extern bool swap_csum_verify (struct page *page); +extern struct workqueue_struct *swapcsum_workqueue__read_mostly ; +#else +#define noswapcsum true +#endif + +/* linux/mm/swapcsum.c */ +extern int _swap_csum_write (struct page *page); + +static inline int swap_csum_write (struct page *page) +{ +if (noswapcsum) +return 0 ; +return _swap_csum_write (page); +} +#else /* CONFIG_SWAP */ #define nr_swap_pages 0L
mm/Kconfig +22 -0
@@ -298,3 +298,25 @@ config NOMMU_INITIAL_TRIM_EXCESS of 1 says that all excess pages should be trimmed. See Documentation/nommu-mmap.txt for more information. + +config SWAP_CHECKSUM + bool "Swap checksum" + depends on SWAP && EXPERIMENTAL + select LIBCRC32C + default n + help + This option enables checksumming of swap pages when saved to disk. + + Use the kernel command line options "swapcsum" to enable and + "noswapcsum" to disable. The default value is configurable. + + Note that this option does not checksum the software suspend image. + +config SWAP_CHECKSUM_DEFAULT + bool "Enable swap checksum by default" + depends on SWAP_CHECKSUM + default y + help + You can use the kernel command line options "swapcsum" to enable and + "noswapcsum" to disable swap checksumming. This option controls the + default value.
mm/Makefile +1 -0
@@ -17,6 +17,7 @@ obj-y += init-mm.o obj-$(CONFIG_BOUNCE) += bounce.o obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o +obj-$(CONFIG_SWAP_CHECKSUM) += swapcsum.o obj-$(CONFIG_HAS_DMA) += dmapool.o obj-$(CONFIG_HUGETLBFS) += hugetlb.o obj-$(CONFIG_NUMA) += mempolicy.o
mm/page_io.c +81 -9
138 lines not on this page · raw message
mm/swapcsum.c new file +94 -0
94 lines not on this page · raw message
mm/swapfile.c +177 -2
253 lines not on this page · raw message
Signature · 1 line
1.6.6.1
PATCH v2 3/3 mm: Swap checksum
In reply to Cesar Eduardo BarrosAdd support for checksumming the swap pages written to disk, using the same checksum as btrfs (crc32c). Since the contents of the swap do not matter after a shutdown, the checksum is kept in memory only.
This protects against silent corruption of the swap caused by hardware problems, the same way the btrfs checksum protects against silent corruption of the filesystem. It is useful even with CONFIG_BLK_DEV_INTEGRITY because it also protects against reads of stale data.
The checksum is done in the swap layer (instead of in a separate block device or in the block layer) to allow the checksums to be tracked together with the rest of swap state (also allowing later for things like Avi Kivity's suggestions of keeping the checksum in the pte when possible and converting zeroed pages to a pte_none), to better allow for different things to be done by the software suspend code (which writes to the same place but has different needs), to simplify configuration (no need to edit the fstab), and because it felt the most natural layer to do it.
Note that this code does not currently checksum the software suspend image. That will need to be done later.
Lightly tested on a x86 VM.
Changes since -v1:
Use __read_mostly for swapcsum_workqueue
Include highmem.h instead of pagemap.h
--- include/linux/swap.h | 30 ++++++++ mm/Kconfig | 22 ++++++ mm/Makefile | 1 + mm/page_io.c | 90 +++++++++++++++++++++++--- mm/swapcsum.c | 94 ++++++++++++++++++++++++++ mm/swapfile.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 405 insertions(+), 11 deletions(-) create mode 100644 mm/swapcsum.c
include/linux/swap.h +30 -0
@@ -15,6 +15,9 @@struct notifier_block ;struct bio ; +struct bio_vec ; + +struct workqueue_struct ;#define SWAP_FLAG_PREFER 0x8000/* set if swap priority specified */ #define SWAP_FLAG_PRIO_MASK 0x7fff
@@ -182,6 +185,10 @@ struct swap_info_struct {struct swap_extent *curr_swap_extent;struct swap_extent first_swap_extent;struct block_device *bdev;/* swap device or bdev of swap file */ +#ifdef CONFIG_SWAP_CHECKSUM +unsigned short *csum_count;/* usage count of a csum page */ +u32 **csum;/* vmalloc'ed array of swap csums */ +#endif struct file *swap_file;/* seldom referenced */ unsigned int old_block_size;/* seldom referenced */ };
@@ -371,6 +378,29 @@ static inline void mem_cgroup_uncharge_swap(swp_entry_t ent) }#endif +#ifdef CONFIG_SWAP_CHECKSUM +/* linux/mm/swapfile.c */ +extern int swap_csum_set (swp_entry_t entry,u32 crc); +extern int swap_csum_get (swp_entry_t entry,u32 *crc); + +/* linux/mm/swapcsum.c */ +extern bool noswapcsum__read_mostly ; +extern bool swap_csum_verify (struct page *page); +extern struct workqueue_struct *swapcsum_workqueue__read_mostly ; +#else +#define noswapcsum true +#endif + +/* linux/mm/swapcsum.c */ +extern int _swap_csum_write (struct page *page); + +static inline int swap_csum_write (struct page *page) +{ +if (noswapcsum) +return 0 ; +return _swap_csum_write (page); +} +#else /* CONFIG_SWAP */ #define nr_swap_pages 0L
mm/Kconfig +22 -0
@@ -298,3 +298,25 @@ config NOMMU_INITIAL_TRIM_EXCESS of 1 says that all excess pages should be trimmed. See Documentation/nommu-mmap.txt for more information. + +config SWAP_CHECKSUM + bool "Swap checksum" + depends on SWAP && EXPERIMENTAL + select LIBCRC32C + default n + help + This option enables checksumming of swap pages when saved to disk. + + Use the kernel command line options "swapcsum" to enable and + "noswapcsum" to disable. The default value is configurable. + + Note that this option does not checksum the software suspend image. + +config SWAP_CHECKSUM_DEFAULT + bool "Enable swap checksum by default" + depends on SWAP_CHECKSUM + default y + help + You can use the kernel command line options "swapcsum" to enable and + "noswapcsum" to disable swap checksumming. This option controls the + default value.
mm/Makefile +1 -0
@@ -17,6 +17,7 @@ obj-y += init-mm.o obj-$(CONFIG_BOUNCE) += bounce.o obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o +obj-$(CONFIG_SWAP_CHECKSUM) += swapcsum.o obj-$(CONFIG_HAS_DMA) += dmapool.o obj-$(CONFIG_HUGETLBFS) += hugetlb.o obj-$(CONFIG_NUMA) += mempolicy.o
mm/page_io.c +81 -9
138 lines not on this page · raw message
mm/swapcsum.c new file +94 -0
94 lines not on this page · raw message
mm/swapfile.c +177 -2
253 lines not on this page · raw message
Signature · 7 lines
1.6.6.1 -- 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>