1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
6 #include <linux/module.h>
7 #include <linux/compiler.h>
9 #include <linux/iomap.h>
10 #include <linux/swap.h>
12 /* Swapfile activation */
14 struct iomap_swapfile_info
{
15 struct iomap iomap
; /* accumulated iomap */
16 struct swap_info_struct
*sis
;
17 uint64_t lowest_ppage
; /* lowest physical addr seen (pages) */
18 uint64_t highest_ppage
; /* highest physical addr seen (pages) */
19 unsigned long nr_pages
; /* number of pages collected */
20 int nr_extents
; /* extent count */
24 * Collect physical extents for this swap file. Physical extents reported to
25 * the swap code must be trimmed to align to a page boundary. The logical
26 * offset within the file is irrelevant since the swapfile code maps logical
27 * page numbers of the swap device to the physical page-aligned extents.
29 static int iomap_swapfile_add_extent(struct iomap_swapfile_info
*isi
)
31 struct iomap
*iomap
= &isi
->iomap
;
32 unsigned long nr_pages
;
34 uint64_t first_ppage_reported
;
39 * Round the start up and the end down so that the physical
40 * extent aligns to a page boundary.
42 first_ppage
= ALIGN(iomap
->addr
, PAGE_SIZE
) >> PAGE_SHIFT
;
43 next_ppage
= ALIGN_DOWN(iomap
->addr
+ iomap
->length
, PAGE_SIZE
) >>
46 /* Skip too-short physical extents. */
47 if (first_ppage
>= next_ppage
)
49 nr_pages
= next_ppage
- first_ppage
;
52 * Calculate how much swap space we're adding; the first page contains
53 * the swap header and doesn't count. The mm still wants that first
54 * page fed to add_swap_extent, however.
56 first_ppage_reported
= first_ppage
;
57 if (iomap
->offset
== 0)
58 first_ppage_reported
++;
59 if (isi
->lowest_ppage
> first_ppage_reported
)
60 isi
->lowest_ppage
= first_ppage_reported
;
61 if (isi
->highest_ppage
< (next_ppage
- 1))
62 isi
->highest_ppage
= next_ppage
- 1;
64 /* Add extent, set up for the next call. */
65 error
= add_swap_extent(isi
->sis
, isi
->nr_pages
, nr_pages
, first_ppage
);
68 isi
->nr_extents
+= error
;
69 isi
->nr_pages
+= nr_pages
;
74 * Accumulate iomaps for this swap file. We have to accumulate iomaps because
75 * swap only cares about contiguous page-aligned physical extents and makes no
76 * distinction between written and unwritten extents.
78 static loff_t
iomap_swapfile_activate_actor(struct inode
*inode
, loff_t pos
,
79 loff_t count
, void *data
, struct iomap
*iomap
,
82 struct iomap_swapfile_info
*isi
= data
;
85 switch (iomap
->type
) {
88 /* Only real or unwritten extents. */
92 pr_err("swapon: file is inline\n");
95 pr_err("swapon: file has unallocated extents\n");
99 /* No uncommitted metadata or shared blocks. */
100 if (iomap
->flags
& IOMAP_F_DIRTY
) {
101 pr_err("swapon: file is not committed\n");
104 if (iomap
->flags
& IOMAP_F_SHARED
) {
105 pr_err("swapon: file has shared extents\n");
109 /* Only one bdev per swap file. */
110 if (iomap
->bdev
!= isi
->sis
->bdev
) {
111 pr_err("swapon: file is on multiple devices\n");
115 if (isi
->iomap
.length
== 0) {
116 /* No accumulated extent, so just store it. */
117 memcpy(&isi
->iomap
, iomap
, sizeof(isi
->iomap
));
118 } else if (isi
->iomap
.addr
+ isi
->iomap
.length
== iomap
->addr
) {
119 /* Append this to the accumulated extent. */
120 isi
->iomap
.length
+= iomap
->length
;
122 /* Otherwise, add the retained iomap and store this one. */
123 error
= iomap_swapfile_add_extent(isi
);
126 memcpy(&isi
->iomap
, iomap
, sizeof(isi
->iomap
));
132 * Iterate a swap file's iomaps to construct physical extents that can be
133 * passed to the swapfile subsystem.
135 int iomap_swapfile_activate(struct swap_info_struct
*sis
,
136 struct file
*swap_file
, sector_t
*pagespan
,
137 const struct iomap_ops
*ops
)
139 struct iomap_swapfile_info isi
= {
141 .lowest_ppage
= (sector_t
)-1ULL,
143 struct address_space
*mapping
= swap_file
->f_mapping
;
144 struct inode
*inode
= mapping
->host
;
146 loff_t len
= ALIGN_DOWN(i_size_read(inode
), PAGE_SIZE
);
150 * Persist all file mapping metadata so that we won't have any
151 * IOMAP_F_DIRTY iomaps.
153 ret
= vfs_fsync(swap_file
, 1);
158 ret
= iomap_apply(inode
, pos
, len
, IOMAP_REPORT
,
159 ops
, &isi
, iomap_swapfile_activate_actor
);
167 if (isi
.iomap
.length
) {
168 ret
= iomap_swapfile_add_extent(&isi
);
173 *pagespan
= 1 + isi
.highest_ppage
- isi
.lowest_ppage
;
174 sis
->max
= isi
.nr_pages
;
175 sis
->pages
= isi
.nr_pages
- 1;
176 sis
->highest_bit
= isi
.nr_pages
- 1;
177 return isi
.nr_extents
;
179 EXPORT_SYMBOL_GPL(iomap_swapfile_activate
);