0001
0002
0003
0004
0005
0006 #include <linux/module.h>
0007 #include <linux/compiler.h>
0008 #include <linux/fs.h>
0009 #include <linux/iomap.h>
0010 #include <linux/swap.h>
0011
0012
0013
0014 struct iomap_swapfile_info {
0015 struct iomap iomap;
0016 struct swap_info_struct *sis;
0017 uint64_t lowest_ppage;
0018 uint64_t highest_ppage;
0019 unsigned long nr_pages;
0020 int nr_extents;
0021 struct file *file;
0022 };
0023
0024
0025
0026
0027
0028
0029
0030 static int iomap_swapfile_add_extent(struct iomap_swapfile_info *isi)
0031 {
0032 struct iomap *iomap = &isi->iomap;
0033 unsigned long nr_pages;
0034 unsigned long max_pages;
0035 uint64_t first_ppage;
0036 uint64_t first_ppage_reported;
0037 uint64_t next_ppage;
0038 int error;
0039
0040 if (unlikely(isi->nr_pages >= isi->sis->max))
0041 return 0;
0042 max_pages = isi->sis->max - isi->nr_pages;
0043
0044
0045
0046
0047
0048 first_ppage = ALIGN(iomap->addr, PAGE_SIZE) >> PAGE_SHIFT;
0049 next_ppage = ALIGN_DOWN(iomap->addr + iomap->length, PAGE_SIZE) >>
0050 PAGE_SHIFT;
0051
0052
0053 if (first_ppage >= next_ppage)
0054 return 0;
0055 nr_pages = next_ppage - first_ppage;
0056 nr_pages = min(nr_pages, max_pages);
0057
0058
0059
0060
0061
0062
0063 first_ppage_reported = first_ppage;
0064 if (iomap->offset == 0)
0065 first_ppage_reported++;
0066 if (isi->lowest_ppage > first_ppage_reported)
0067 isi->lowest_ppage = first_ppage_reported;
0068 if (isi->highest_ppage < (next_ppage - 1))
0069 isi->highest_ppage = next_ppage - 1;
0070
0071
0072 error = add_swap_extent(isi->sis, isi->nr_pages, nr_pages, first_ppage);
0073 if (error < 0)
0074 return error;
0075 isi->nr_extents += error;
0076 isi->nr_pages += nr_pages;
0077 return 0;
0078 }
0079
0080 static int iomap_swapfile_fail(struct iomap_swapfile_info *isi, const char *str)
0081 {
0082 char *buf, *p = ERR_PTR(-ENOMEM);
0083
0084 buf = kmalloc(PATH_MAX, GFP_KERNEL);
0085 if (buf)
0086 p = file_path(isi->file, buf, PATH_MAX);
0087 pr_err("swapon: file %s %s\n", IS_ERR(p) ? "<unknown>" : p, str);
0088 kfree(buf);
0089 return -EINVAL;
0090 }
0091
0092
0093
0094
0095
0096
0097 static loff_t iomap_swapfile_iter(const struct iomap_iter *iter,
0098 struct iomap *iomap, struct iomap_swapfile_info *isi)
0099 {
0100 switch (iomap->type) {
0101 case IOMAP_MAPPED:
0102 case IOMAP_UNWRITTEN:
0103
0104 break;
0105 case IOMAP_INLINE:
0106
0107 return iomap_swapfile_fail(isi, "is inline");
0108 default:
0109 return iomap_swapfile_fail(isi, "has unallocated extents");
0110 }
0111
0112
0113 if (iomap->flags & IOMAP_F_DIRTY)
0114 return iomap_swapfile_fail(isi, "is not committed");
0115 if (iomap->flags & IOMAP_F_SHARED)
0116 return iomap_swapfile_fail(isi, "has shared extents");
0117
0118
0119 if (iomap->bdev != isi->sis->bdev)
0120 return iomap_swapfile_fail(isi, "outside the main device");
0121
0122 if (isi->iomap.length == 0) {
0123
0124 memcpy(&isi->iomap, iomap, sizeof(isi->iomap));
0125 } else if (isi->iomap.addr + isi->iomap.length == iomap->addr) {
0126
0127 isi->iomap.length += iomap->length;
0128 } else {
0129
0130 int error = iomap_swapfile_add_extent(isi);
0131 if (error)
0132 return error;
0133 memcpy(&isi->iomap, iomap, sizeof(isi->iomap));
0134 }
0135 return iomap_length(iter);
0136 }
0137
0138
0139
0140
0141
0142 int iomap_swapfile_activate(struct swap_info_struct *sis,
0143 struct file *swap_file, sector_t *pagespan,
0144 const struct iomap_ops *ops)
0145 {
0146 struct inode *inode = swap_file->f_mapping->host;
0147 struct iomap_iter iter = {
0148 .inode = inode,
0149 .pos = 0,
0150 .len = ALIGN_DOWN(i_size_read(inode), PAGE_SIZE),
0151 .flags = IOMAP_REPORT,
0152 };
0153 struct iomap_swapfile_info isi = {
0154 .sis = sis,
0155 .lowest_ppage = (sector_t)-1ULL,
0156 .file = swap_file,
0157 };
0158 int ret;
0159
0160
0161
0162
0163
0164 ret = vfs_fsync(swap_file, 1);
0165 if (ret)
0166 return ret;
0167
0168 while ((ret = iomap_iter(&iter, ops)) > 0)
0169 iter.processed = iomap_swapfile_iter(&iter, &iter.iomap, &isi);
0170 if (ret < 0)
0171 return ret;
0172
0173 if (isi.iomap.length) {
0174 ret = iomap_swapfile_add_extent(&isi);
0175 if (ret)
0176 return ret;
0177 }
0178
0179
0180
0181
0182
0183
0184 if (isi.nr_pages == 0) {
0185 pr_warn("swapon: Cannot find a single usable page in file.\n");
0186 return -EINVAL;
0187 }
0188
0189 *pagespan = 1 + isi.highest_ppage - isi.lowest_ppage;
0190 sis->max = isi.nr_pages;
0191 sis->pages = isi.nr_pages - 1;
0192 sis->highest_bit = isi.nr_pages - 1;
0193 return isi.nr_extents;
0194 }
0195 EXPORT_SYMBOL_GPL(iomap_swapfile_activate);