Skip to content

Commit a45c0ec

Browse files
committed
iomap: move the swapfile code into a separate file
Move the swapfile activation code into a separate file so that we can group related functions in a single file instead of having a single enormous source file. Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]>
1 parent 1c23020 commit a45c0ec

File tree

3 files changed

+183
-170
lines changed

3 files changed

+183
-170
lines changed

fs/iomap.c

Lines changed: 0 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -2000,176 +2000,6 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
20002000
}
20012001
EXPORT_SYMBOL_GPL(iomap_dio_rw);
20022002

2003-
/* Swapfile activation */
2004-
2005-
#ifdef CONFIG_SWAP
2006-
struct iomap_swapfile_info {
2007-
struct iomap iomap; /* accumulated iomap */
2008-
struct swap_info_struct *sis;
2009-
uint64_t lowest_ppage; /* lowest physical addr seen (pages) */
2010-
uint64_t highest_ppage; /* highest physical addr seen (pages) */
2011-
unsigned long nr_pages; /* number of pages collected */
2012-
int nr_extents; /* extent count */
2013-
};
2014-
2015-
/*
2016-
* Collect physical extents for this swap file. Physical extents reported to
2017-
* the swap code must be trimmed to align to a page boundary. The logical
2018-
* offset within the file is irrelevant since the swapfile code maps logical
2019-
* page numbers of the swap device to the physical page-aligned extents.
2020-
*/
2021-
static int iomap_swapfile_add_extent(struct iomap_swapfile_info *isi)
2022-
{
2023-
struct iomap *iomap = &isi->iomap;
2024-
unsigned long nr_pages;
2025-
uint64_t first_ppage;
2026-
uint64_t first_ppage_reported;
2027-
uint64_t next_ppage;
2028-
int error;
2029-
2030-
/*
2031-
* Round the start up and the end down so that the physical
2032-
* extent aligns to a page boundary.
2033-
*/
2034-
first_ppage = ALIGN(iomap->addr, PAGE_SIZE) >> PAGE_SHIFT;
2035-
next_ppage = ALIGN_DOWN(iomap->addr + iomap->length, PAGE_SIZE) >>
2036-
PAGE_SHIFT;
2037-
2038-
/* Skip too-short physical extents. */
2039-
if (first_ppage >= next_ppage)
2040-
return 0;
2041-
nr_pages = next_ppage - first_ppage;
2042-
2043-
/*
2044-
* Calculate how much swap space we're adding; the first page contains
2045-
* the swap header and doesn't count. The mm still wants that first
2046-
* page fed to add_swap_extent, however.
2047-
*/
2048-
first_ppage_reported = first_ppage;
2049-
if (iomap->offset == 0)
2050-
first_ppage_reported++;
2051-
if (isi->lowest_ppage > first_ppage_reported)
2052-
isi->lowest_ppage = first_ppage_reported;
2053-
if (isi->highest_ppage < (next_ppage - 1))
2054-
isi->highest_ppage = next_ppage - 1;
2055-
2056-
/* Add extent, set up for the next call. */
2057-
error = add_swap_extent(isi->sis, isi->nr_pages, nr_pages, first_ppage);
2058-
if (error < 0)
2059-
return error;
2060-
isi->nr_extents += error;
2061-
isi->nr_pages += nr_pages;
2062-
return 0;
2063-
}
2064-
2065-
/*
2066-
* Accumulate iomaps for this swap file. We have to accumulate iomaps because
2067-
* swap only cares about contiguous page-aligned physical extents and makes no
2068-
* distinction between written and unwritten extents.
2069-
*/
2070-
static loff_t iomap_swapfile_activate_actor(struct inode *inode, loff_t pos,
2071-
loff_t count, void *data, struct iomap *iomap)
2072-
{
2073-
struct iomap_swapfile_info *isi = data;
2074-
int error;
2075-
2076-
switch (iomap->type) {
2077-
case IOMAP_MAPPED:
2078-
case IOMAP_UNWRITTEN:
2079-
/* Only real or unwritten extents. */
2080-
break;
2081-
case IOMAP_INLINE:
2082-
/* No inline data. */
2083-
pr_err("swapon: file is inline\n");
2084-
return -EINVAL;
2085-
default:
2086-
pr_err("swapon: file has unallocated extents\n");
2087-
return -EINVAL;
2088-
}
2089-
2090-
/* No uncommitted metadata or shared blocks. */
2091-
if (iomap->flags & IOMAP_F_DIRTY) {
2092-
pr_err("swapon: file is not committed\n");
2093-
return -EINVAL;
2094-
}
2095-
if (iomap->flags & IOMAP_F_SHARED) {
2096-
pr_err("swapon: file has shared extents\n");
2097-
return -EINVAL;
2098-
}
2099-
2100-
/* Only one bdev per swap file. */
2101-
if (iomap->bdev != isi->sis->bdev) {
2102-
pr_err("swapon: file is on multiple devices\n");
2103-
return -EINVAL;
2104-
}
2105-
2106-
if (isi->iomap.length == 0) {
2107-
/* No accumulated extent, so just store it. */
2108-
memcpy(&isi->iomap, iomap, sizeof(isi->iomap));
2109-
} else if (isi->iomap.addr + isi->iomap.length == iomap->addr) {
2110-
/* Append this to the accumulated extent. */
2111-
isi->iomap.length += iomap->length;
2112-
} else {
2113-
/* Otherwise, add the retained iomap and store this one. */
2114-
error = iomap_swapfile_add_extent(isi);
2115-
if (error)
2116-
return error;
2117-
memcpy(&isi->iomap, iomap, sizeof(isi->iomap));
2118-
}
2119-
return count;
2120-
}
2121-
2122-
/*
2123-
* Iterate a swap file's iomaps to construct physical extents that can be
2124-
* passed to the swapfile subsystem.
2125-
*/
2126-
int iomap_swapfile_activate(struct swap_info_struct *sis,
2127-
struct file *swap_file, sector_t *pagespan,
2128-
const struct iomap_ops *ops)
2129-
{
2130-
struct iomap_swapfile_info isi = {
2131-
.sis = sis,
2132-
.lowest_ppage = (sector_t)-1ULL,
2133-
};
2134-
struct address_space *mapping = swap_file->f_mapping;
2135-
struct inode *inode = mapping->host;
2136-
loff_t pos = 0;
2137-
loff_t len = ALIGN_DOWN(i_size_read(inode), PAGE_SIZE);
2138-
loff_t ret;
2139-
2140-
/*
2141-
* Persist all file mapping metadata so that we won't have any
2142-
* IOMAP_F_DIRTY iomaps.
2143-
*/
2144-
ret = vfs_fsync(swap_file, 1);
2145-
if (ret)
2146-
return ret;
2147-
2148-
while (len > 0) {
2149-
ret = iomap_apply(inode, pos, len, IOMAP_REPORT,
2150-
ops, &isi, iomap_swapfile_activate_actor);
2151-
if (ret <= 0)
2152-
return ret;
2153-
2154-
pos += ret;
2155-
len -= ret;
2156-
}
2157-
2158-
if (isi.iomap.length) {
2159-
ret = iomap_swapfile_add_extent(&isi);
2160-
if (ret)
2161-
return ret;
2162-
}
2163-
2164-
*pagespan = 1 + isi.highest_ppage - isi.lowest_ppage;
2165-
sis->max = isi.nr_pages;
2166-
sis->pages = isi.nr_pages - 1;
2167-
sis->highest_bit = isi.nr_pages - 1;
2168-
return isi.nr_extents;
2169-
}
2170-
EXPORT_SYMBOL_GPL(iomap_swapfile_activate);
2171-
#endif /* CONFIG_SWAP */
2172-
21732003
static loff_t
21742004
iomap_bmap_actor(struct inode *inode, loff_t pos, loff_t length,
21752005
void *data, struct iomap *iomap)

fs/iomap/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@
33
# Copyright (c) 2019 Oracle.
44
# All Rights Reserved.
55
#
6+
obj-$(CONFIG_FS_IOMAP) += iomap.o
7+
8+
iomap-$(CONFIG_SWAP) += swapfile.o

fs/iomap/swapfile.c

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2018 Oracle. All Rights Reserved.
4+
* Author: Darrick J. Wong <[email protected]>
5+
*/
6+
#include <linux/module.h>
7+
#include <linux/compiler.h>
8+
#include <linux/fs.h>
9+
#include <linux/iomap.h>
10+
#include <linux/swap.h>
11+
12+
#include "../internal.h"
13+
14+
/* Swapfile activation */
15+
16+
struct iomap_swapfile_info {
17+
struct iomap iomap; /* accumulated iomap */
18+
struct swap_info_struct *sis;
19+
uint64_t lowest_ppage; /* lowest physical addr seen (pages) */
20+
uint64_t highest_ppage; /* highest physical addr seen (pages) */
21+
unsigned long nr_pages; /* number of pages collected */
22+
int nr_extents; /* extent count */
23+
};
24+
25+
/*
26+
* Collect physical extents for this swap file. Physical extents reported to
27+
* the swap code must be trimmed to align to a page boundary. The logical
28+
* offset within the file is irrelevant since the swapfile code maps logical
29+
* page numbers of the swap device to the physical page-aligned extents.
30+
*/
31+
static int iomap_swapfile_add_extent(struct iomap_swapfile_info *isi)
32+
{
33+
struct iomap *iomap = &isi->iomap;
34+
unsigned long nr_pages;
35+
uint64_t first_ppage;
36+
uint64_t first_ppage_reported;
37+
uint64_t next_ppage;
38+
int error;
39+
40+
/*
41+
* Round the start up and the end down so that the physical
42+
* extent aligns to a page boundary.
43+
*/
44+
first_ppage = ALIGN(iomap->addr, PAGE_SIZE) >> PAGE_SHIFT;
45+
next_ppage = ALIGN_DOWN(iomap->addr + iomap->length, PAGE_SIZE) >>
46+
PAGE_SHIFT;
47+
48+
/* Skip too-short physical extents. */
49+
if (first_ppage >= next_ppage)
50+
return 0;
51+
nr_pages = next_ppage - first_ppage;
52+
53+
/*
54+
* Calculate how much swap space we're adding; the first page contains
55+
* the swap header and doesn't count. The mm still wants that first
56+
* page fed to add_swap_extent, however.
57+
*/
58+
first_ppage_reported = first_ppage;
59+
if (iomap->offset == 0)
60+
first_ppage_reported++;
61+
if (isi->lowest_ppage > first_ppage_reported)
62+
isi->lowest_ppage = first_ppage_reported;
63+
if (isi->highest_ppage < (next_ppage - 1))
64+
isi->highest_ppage = next_ppage - 1;
65+
66+
/* Add extent, set up for the next call. */
67+
error = add_swap_extent(isi->sis, isi->nr_pages, nr_pages, first_ppage);
68+
if (error < 0)
69+
return error;
70+
isi->nr_extents += error;
71+
isi->nr_pages += nr_pages;
72+
return 0;
73+
}
74+
75+
/*
76+
* Accumulate iomaps for this swap file. We have to accumulate iomaps because
77+
* swap only cares about contiguous page-aligned physical extents and makes no
78+
* distinction between written and unwritten extents.
79+
*/
80+
static loff_t iomap_swapfile_activate_actor(struct inode *inode, loff_t pos,
81+
loff_t count, void *data, struct iomap *iomap)
82+
{
83+
struct iomap_swapfile_info *isi = data;
84+
int error;
85+
86+
switch (iomap->type) {
87+
case IOMAP_MAPPED:
88+
case IOMAP_UNWRITTEN:
89+
/* Only real or unwritten extents. */
90+
break;
91+
case IOMAP_INLINE:
92+
/* No inline data. */
93+
pr_err("swapon: file is inline\n");
94+
return -EINVAL;
95+
default:
96+
pr_err("swapon: file has unallocated extents\n");
97+
return -EINVAL;
98+
}
99+
100+
/* No uncommitted metadata or shared blocks. */
101+
if (iomap->flags & IOMAP_F_DIRTY) {
102+
pr_err("swapon: file is not committed\n");
103+
return -EINVAL;
104+
}
105+
if (iomap->flags & IOMAP_F_SHARED) {
106+
pr_err("swapon: file has shared extents\n");
107+
return -EINVAL;
108+
}
109+
110+
/* Only one bdev per swap file. */
111+
if (iomap->bdev != isi->sis->bdev) {
112+
pr_err("swapon: file is on multiple devices\n");
113+
return -EINVAL;
114+
}
115+
116+
if (isi->iomap.length == 0) {
117+
/* No accumulated extent, so just store it. */
118+
memcpy(&isi->iomap, iomap, sizeof(isi->iomap));
119+
} else if (isi->iomap.addr + isi->iomap.length == iomap->addr) {
120+
/* Append this to the accumulated extent. */
121+
isi->iomap.length += iomap->length;
122+
} else {
123+
/* Otherwise, add the retained iomap and store this one. */
124+
error = iomap_swapfile_add_extent(isi);
125+
if (error)
126+
return error;
127+
memcpy(&isi->iomap, iomap, sizeof(isi->iomap));
128+
}
129+
return count;
130+
}
131+
132+
/*
133+
* Iterate a swap file's iomaps to construct physical extents that can be
134+
* passed to the swapfile subsystem.
135+
*/
136+
int iomap_swapfile_activate(struct swap_info_struct *sis,
137+
struct file *swap_file, sector_t *pagespan,
138+
const struct iomap_ops *ops)
139+
{
140+
struct iomap_swapfile_info isi = {
141+
.sis = sis,
142+
.lowest_ppage = (sector_t)-1ULL,
143+
};
144+
struct address_space *mapping = swap_file->f_mapping;
145+
struct inode *inode = mapping->host;
146+
loff_t pos = 0;
147+
loff_t len = ALIGN_DOWN(i_size_read(inode), PAGE_SIZE);
148+
loff_t ret;
149+
150+
/*
151+
* Persist all file mapping metadata so that we won't have any
152+
* IOMAP_F_DIRTY iomaps.
153+
*/
154+
ret = vfs_fsync(swap_file, 1);
155+
if (ret)
156+
return ret;
157+
158+
while (len > 0) {
159+
ret = iomap_apply(inode, pos, len, IOMAP_REPORT,
160+
ops, &isi, iomap_swapfile_activate_actor);
161+
if (ret <= 0)
162+
return ret;
163+
164+
pos += ret;
165+
len -= ret;
166+
}
167+
168+
if (isi.iomap.length) {
169+
ret = iomap_swapfile_add_extent(&isi);
170+
if (ret)
171+
return ret;
172+
}
173+
174+
*pagespan = 1 + isi.highest_ppage - isi.lowest_ppage;
175+
sis->max = isi.nr_pages;
176+
sis->pages = isi.nr_pages - 1;
177+
sis->highest_bit = isi.nr_pages - 1;
178+
return isi.nr_extents;
179+
}
180+
EXPORT_SYMBOL_GPL(iomap_swapfile_activate);

0 commit comments

Comments
 (0)