Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2018 Oracle.  All Rights Reserved.
0004  * Author: Darrick J. Wong <darrick.wong@oracle.com>
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 /* Swapfile activation */
0013 
0014 struct iomap_swapfile_info {
0015     struct iomap iomap;     /* accumulated iomap */
0016     struct swap_info_struct *sis;
0017     uint64_t lowest_ppage;      /* lowest physical addr seen (pages) */
0018     uint64_t highest_ppage;     /* highest physical addr seen (pages) */
0019     unsigned long nr_pages;     /* number of pages collected */
0020     int nr_extents;         /* extent count */
0021     struct file *file;
0022 };
0023 
0024 /*
0025  * Collect physical extents for this swap file.  Physical extents reported to
0026  * the swap code must be trimmed to align to a page boundary.  The logical
0027  * offset within the file is irrelevant since the swapfile code maps logical
0028  * page numbers of the swap device to the physical page-aligned extents.
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      * Round the start up and the end down so that the physical
0046      * extent aligns to a page boundary.
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     /* Skip too-short physical extents. */
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      * Calculate how much swap space we're adding; the first page contains
0060      * the swap header and doesn't count.  The mm still wants that first
0061      * page fed to add_swap_extent, however.
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     /* Add extent, set up for the next call. */
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  * Accumulate iomaps for this swap file.  We have to accumulate iomaps because
0094  * swap only cares about contiguous page-aligned physical extents and makes no
0095  * distinction between written and unwritten extents.
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         /* Only real or unwritten extents. */
0104         break;
0105     case IOMAP_INLINE:
0106         /* No inline data. */
0107         return iomap_swapfile_fail(isi, "is inline");
0108     default:
0109         return iomap_swapfile_fail(isi, "has unallocated extents");
0110     }
0111 
0112     /* No uncommitted metadata or shared blocks. */
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     /* Only one bdev per swap file. */
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         /* No accumulated extent, so just store it. */
0124         memcpy(&isi->iomap, iomap, sizeof(isi->iomap));
0125     } else if (isi->iomap.addr + isi->iomap.length == iomap->addr) {
0126         /* Append this to the accumulated extent. */
0127         isi->iomap.length += iomap->length;
0128     } else {
0129         /* Otherwise, add the retained iomap and store this one. */
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  * Iterate a swap file's iomaps to construct physical extents that can be
0140  * passed to the swapfile subsystem.
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      * Persist all file mapping metadata so that we won't have any
0162      * IOMAP_F_DIRTY iomaps.
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      * If this swapfile doesn't contain even a single page-aligned
0181      * contiguous range of blocks, reject this useless swapfile to
0182      * prevent confusion later on.
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);