Skip to contentSkip to conversation

RFC: iomap-based swap file activation

PATCH In review Aleksei Besogonov 3 participants 8 messages Apr 20, 2018 – May 16, 2018

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

cover RFC: iomap-based swap file activation

This patch set adds iomap-based swap file initialization, this allows it to use files with holes on XFS for swap.

Aleksei Besogonov (2):
fs: Add iomap_swap_activate
xfs: add support for iomap-based swapfile activation

 fs/iomap.c            | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_aops.c     |  7 +++++
 include/linux/iomap.h |  5 +++
 mm/swapfile.c         |  1 +
 4 files changed, 100 insertions(+)
Signature · 1 line
2.14.1
#1 lore raw

PATCH 1/2 fs: Add iomap_swap_activate

This commit adds an alternative to generic_swapfile_activate function based on iomap family. The major driver for this is swap file support on XFS, currently it doesn't work on files with holes due to deficiencies in the old bmap() interface that is used by generic_swapfile_activate.

---
 fs/iomap.c            | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/iomap.h |  5 +++
 mm/swapfile.c         |  1 +
 3 files changed, 93 insertions(+)
fs/iomap.c +87 -0
index afd163586aa0..9f0980637dbc 100644
@@ -1089,3 +1089,90 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(iomap_dio_rw);
+
+struct iomap_swap_walker_context
+{
+    struct swap_info_struct *sis;
+    unsigned int page_no;
+    unsigned int nr_extents;
+    sector_t *span;
+};
+
+static loff_t
+iomap_swap_map(struct inode *inode, loff_t pos, loff_t length,
+		void *data, struct iomap *iomap)
+{
+	struct iomap_swap_walker_context *ctx = data;
+	unsigned int blocks_per_page = PAGE_SIZE >> inode->i_blkbits;
+	u64 num_pages;
+	u64 aligned_address;
+	sector_t disk_pos;
+	loff_t eff_length;
+	loff_t ret;
+
+	/*
+	 * Swap extents need to be PAGE_SIZE aligned on the disk
+	 */
+	aligned_address = ALIGN(iomap->addr, PAGE_SIZE);
+	eff_length = length - (aligned_address - iomap->addr);
+	BUG_ON(eff_length > length);
+	disk_pos = aligned_address >> inode->i_blkbits;
+
+	if (eff_length < 0)
+		return length; /* Continue probing */
+
+	num_pages = eff_length / PAGE_SIZE;
+
+	/* Can't add blocks less than 1 page */
+	if (num_pages == 0)
+		return length; /* Continue probing */
+
+	ret = add_swap_extent(ctx->sis, ctx->page_no, num_pages, disk_pos);
+	if (ret < 0)
+		return ret;
+
+	ctx->nr_extents += ret;
+	ctx->page_no += num_pages;
+	*(ctx->span) += num_pages * blocks_per_page;
+
+	return length; /* continue probing */
+}
+
+int
+iomap_swap_activate(struct swap_info_struct *sis, struct file *file,
+		sector_t *span, const struct iomap_ops *ops)
+{
+	struct iomap_swap_walker_context ctx = {
+		.sis = sis,
+		.page_no = 0,
+		.nr_extents = 0,
+		.span = span
+	};
+
+	struct inode * inode = file_inode(file);
+	loff_t len = i_size_read(inode);
+	loff_t pos = 0;
+	loff_t ret = -EINVAL;
+
+	while(len > 0) {
+		ret = iomap_apply(inode, pos, len, IOMAP_REPORT, ops,
+				  &ctx, iomap_swap_map);
+		if (ret <= 0)
+			break;
+
+		pos += ret;
+		len -= ret;
+	}
+
+	if (ret < 0) {
+		pr_err("Failed to activate the swap file\n");
+		return -EINVAL;
+	}
+
+	sis->max = ctx.page_no == 0 ? 1 : ctx.page_no;
+	sis->pages = ctx.page_no;
+	sis->highest_bit = ctx.page_no;
+
+	return ctx.nr_extents;
+}
+EXPORT_SYMBOL_GPL(iomap_swap_activate);
include/linux/iomap.h +5 -0
index 19a07de28212..a85da0db6c2e 100644
@@ -10,6 +10,8 @@ struct iov_iter;
 struct kiocb;
 struct vm_area_struct;
 struct vm_fault;
+struct file;
+struct swap_info_struct;
 
 /*
  * Types of block ranges for iomap mappings:
@@ -106,4 +108,7 @@ typedef int (iomap_dio_end_io_t)(struct kiocb *iocb, ssize_t ret,
 ssize_t iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
 		const struct iomap_ops *ops, iomap_dio_end_io_t end_io);
 
+int iomap_swap_activate(struct swap_info_struct *sis, struct file *file,
+			sector_t *span, const struct iomap_ops *ops);
+
 #endif /* LINUX_IOMAP_H */
mm/swapfile.c +1 -0
index c7a33717d079..9e6d3c1a882e 100644
@@ -2381,6 +2381,7 @@ add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
 	list_add_tail(&new_se->list, &sis->first_swap_extent.list);
 	return 1;
 }
+EXPORT_SYMBOL_GPL(add_swap_extent);
 
 /*
  * A `swap extent' is a simple thing which maps a contiguous range of pages
Signature · 1 line
2.14.1
#2 lore raw

Re: [PATCH 1/2] fs: Add iomap_swap_activate

Thank you for the patch! Yet something to improve:

Hi Aleksei,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v4.17-rc2 next-20180424]
[cannot apply to dgc-xfs/for-next]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Aleksei-Besogonov/fs-Add-iomap_swap_activate/20180423-061348
config: x86_64-randconfig-s4-04260252 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-16) 7.3.0
reproduce:

        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

fs/iomap.c: In function 'iomap_swap_map':

>> fs/iomap.c:1130:8: error: implicit declaration of function 'add_swap_extent'; did you mean '__swap_count'? [-Werror=implicit-function-declaration]
     ret = add_swap_extent(ctx->sis, ctx->page_no, num_pages, disk_pos);
           ^~~~~~~~~~~~~~~
           __swap_count

cc1: some warnings being treated as errors

vim +1130 fs/iomap.c

1100
1101 static loff_t
1102 iomap_swap_map(struct inode *inode, loff_t pos, loff_t length,
1103 void *data, struct iomap *iomap)
1104 {
1105 struct iomap_swap_walker_context *ctx = data;
1106 unsigned int blocks_per_page = PAGE_SIZE >> inode->i_blkbits;
1107 u64 num_pages;
1108 u64 aligned_address;
1109 sector_t disk_pos;
1110 loff_t eff_length;
1111 loff_t ret;
1112
1113 /*
1114 * Swap extents need to be PAGE_SIZE aligned on the disk
1115 */
1116 aligned_address = ALIGN(iomap->addr, PAGE_SIZE);
1117 eff_length = length - (aligned_address - iomap->addr);
1118 BUG_ON(eff_length > length);
1119 disk_pos = aligned_address >> inode->i_blkbits;
1120
1121 if (eff_length < 0)
1122 return length; /* Continue probing */
1123
1124 num_pages = eff_length / PAGE_SIZE;
1125
1126 /* Can't add blocks less than 1 page */
1127 if (num_pages == 0)
1128 return length; /* Continue probing */
1129

> 1130		ret = add_swap_extent(ctx->sis, ctx->page_no, num_pages, disk_pos);

1131 if (ret < 0)
1132 return ret;
1133
1134 ctx->nr_extents += ret;
1135 ctx->page_no += num_pages;
1136 *(ctx->span) += num_pages * blocks_per_page;
1137
1138 return length; /* continue probing */
1139 }
1140

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

#3 lore raw

Re: [PATCH 1/2] fs: Add iomap_swap_activate

In reply to Aleksei Besogonov
Thank you for the patch! Yet something to improve:

Hi Aleksei,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v4.17-rc2 next-20180424]
[cannot apply to dgc-xfs/for-next]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Aleksei-Besogonov/fs-Add-iomap_swap_activate/20180423-061348
config: x86_64-randconfig-s2-04260250 (attached as .config)
compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026 reproduce:

        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

fs/iomap.c: In function 'iomap_swap_map':

>> fs/iomap.c:1130:8: error: implicit declaration of function 'add_swap_extent' [-Werror=implicit-function-declaration]
     ret = add_swap_extent(ctx->sis, ctx->page_no, num_pages, disk_pos);
           ^~~~~~~~~~~~~~~

cc1: some warnings being treated as errors

vim +/add_swap_extent +1130 fs/iomap.c

1100
1101 static loff_t
1102 iomap_swap_map(struct inode *inode, loff_t pos, loff_t length,
1103 void *data, struct iomap *iomap)
1104 {
1105 struct iomap_swap_walker_context *ctx = data;
1106 unsigned int blocks_per_page = PAGE_SIZE >> inode->i_blkbits;
1107 u64 num_pages;
1108 u64 aligned_address;
1109 sector_t disk_pos;
1110 loff_t eff_length;
1111 loff_t ret;
1112
1113 /*
1114 * Swap extents need to be PAGE_SIZE aligned on the disk
1115 */
1116 aligned_address = ALIGN(iomap->addr, PAGE_SIZE);
1117 eff_length = length - (aligned_address - iomap->addr);
1118 BUG_ON(eff_length > length);
1119 disk_pos = aligned_address >> inode->i_blkbits;
1120
1121 if (eff_length < 0)
1122 return length; /* Continue probing */
1123
1124 num_pages = eff_length / PAGE_SIZE;
1125
1126 /* Can't add blocks less than 1 page */
1127 if (num_pages == 0)
1128 return length; /* Continue probing */
1129

> 1130		ret = add_swap_extent(ctx->sis, ctx->page_no, num_pages, disk_pos);

1131 if (ret < 0)
1132 return ret;
1133
1134 ctx->nr_extents += ret;
1135 ctx->page_no += num_pages;
1136 *(ctx->span) += num_pages * blocks_per_page;
1137
1138 return length; /* continue probing */
1139 }
1140

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

#4 lore raw

PATCH 2/2 xfs: add support for iomap-based swapfile activation

In reply to Aleksei Besogonov

Use iomap-based swapfile activation instead of the default generic_swapfile_activate bmap-based infrastructure.

---
 fs/xfs/xfs_aops.c | 7 +++++++
 1 file changed, 7 insertions(+)
fs/xfs/xfs_aops.c +7 -0
index 31f1f10eecd1..878ff3872883 100644
@@ -1491,6 +1491,12 @@ xfs_vm_set_page_dirty(
 	return newly_dirty;
 }
 
+static int xfs_swap_activate(struct swap_info_struct *sis, struct file *file,
+			     sector_t *span)
+{
+	return iomap_swap_activate(sis, file, span, &xfs_iomap_ops);
+}
+
 const struct address_space_operations xfs_address_space_operations = {
 	.readpage		= xfs_vm_readpage,
 	.readpages		= xfs_vm_readpages,
@@ -1504,4 +1510,5 @@ const struct address_space_operations xfs_address_space_operations = {
 	.migratepage		= buffer_migrate_page,
 	.is_partially_uptodate  = block_is_partially_uptodate,
 	.error_remove_page	= generic_error_remove_page,
+	.swap_activate          = xfs_swap_activate,
 };
Signature · 1 line
2.14.1
#5 lore raw
In reply to Aleksei Besogonov
Quoted 2 lines · Aleksei Besogonov

This patch set adds iomap-based swap file initialization, this allows it to use files with holes on XFS for swap.

Um... there's already a patch[1] implementing this out for review on the mailing list. Could you please take a look at that instead?

--D

[1] https://marc.info/?l=linux-xfs&m=152401984810062&w=2

Quoted 18 lines

Aleksei Besogonov (2):
fs: Add iomap_swap_activate
xfs: add support for iomap-based swapfile activation

 fs/iomap.c            | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_aops.c     |  7 +++++
 include/linux/iomap.h |  5 +++
 mm/swapfile.c         |  1 +
 4 files changed, 100 insertions(+)
Signature · 6 lines
2.14.1

--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#6 lore raw

Sorry for top-posting.

I'm sorry I missed your patch. It's definitely better than mine in the number of validations it does.

My only comment is, shouldn't we allow blocks that are not page-aligned? The current generic_swapfile_activate will simply discard the leading unaligned sectors. Your patch will immediately error out in this case.

I tried to replicate the same behavior by doing ALIGN on the iomap addr.

On 4/20/18, 15:26, "Darrick J. Wong" <[email protected]> wrote:

    On Fri, Apr 20, 2018 at 10:08:13PM +0000, Aleksei Besogonov wrote:
    > This patch set adds iomap-based swap file initialization, this allows
    > it to use files with holes on XFS for swap.
    
    Um... there's already a patch[1] implementing this out for review on the
    mailing list.  Could you please take a look at that instead?
    
    --D
    
    [1] https://marc.info/?l=linux-xfs&m=152401984810062&w=2
    
    > 
    > Aleksei Besogonov (2):
    >   fs: Add iomap_swap_activate
    >   xfs: add support for iomap-based swapfile activation
    > 
    >  fs/iomap.c            | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++
    >  fs/xfs/xfs_aops.c     |  7 +++++
    >  include/linux/iomap.h |  5 +++
    >  mm/swapfile.c         |  1 +
    >  4 files changed, 100 insertions(+)
    > 
    > -- 
    > 2.14.1
    > 
    > --
    > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
    > the body of a message to [email protected]
    > More majordomo info at  http://vger.kernel.org/majordomo-info.html
#7 lore raw
In reply to Aleksei Besogonov
Quoted 2 lines · Aleksei Besogonov

This patch set adds iomap-based swap file initialization, this allows it to use files with holes on XFS for swap.

Just out of curiosity (well after the fact, sorry...), what's the motivation for having sparse swap files?

--D

Quoted 17 lines

Aleksei Besogonov (2):
fs: Add iomap_swap_activate
xfs: add support for iomap-based swapfile activation

 fs/iomap.c            | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/xfs_aops.c     |  7 +++++
 include/linux/iomap.h |  5 +++
 mm/swapfile.c         |  1 +
 4 files changed, 100 insertions(+)
Signature · 6 lines
2.14.1

--
To unsubscribe from this list: send the line "unsubscribe linux-xfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html