LCOV - code coverage report
Current view: top level - fs/iomap - swapfile.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_qemu_modules_combined.info Lines: 0 61 0.0 %
Date: 2020-09-30 20:25:01 Functions: 0 3 0.0 %
Branches: 0 35 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * Copyright (C) 2018 Oracle.  All Rights Reserved.
       4                 :            :  * Author: Darrick J. Wong <darrick.wong@oracle.com>
       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                 :            : /* Swapfile activation */
      13                 :            : 
      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 */
      21                 :            : };
      22                 :            : 
      23                 :            : /*
      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.
      28                 :            :  */
      29                 :          0 : static int iomap_swapfile_add_extent(struct iomap_swapfile_info *isi)
      30                 :            : {
      31                 :            :         struct iomap *iomap = &isi->iomap;
      32                 :            :         unsigned long nr_pages;
      33                 :            :         uint64_t first_ppage;
      34                 :            :         uint64_t first_ppage_reported;
      35                 :            :         uint64_t next_ppage;
      36                 :            :         int error;
      37                 :            : 
      38                 :            :         /*
      39                 :            :          * Round the start up and the end down so that the physical
      40                 :            :          * extent aligns to a page boundary.
      41                 :            :          */
      42                 :          0 :         first_ppage = ALIGN(iomap->addr, PAGE_SIZE) >> PAGE_SHIFT;
      43                 :          0 :         next_ppage = ALIGN_DOWN(iomap->addr + iomap->length, PAGE_SIZE) >>
      44                 :            :                         PAGE_SHIFT;
      45                 :            : 
      46                 :            :         /* Skip too-short physical extents. */
      47         [ #  # ]:          0 :         if (first_ppage >= next_ppage)
      48                 :            :                 return 0;
      49                 :          0 :         nr_pages = next_ppage - first_ppage;
      50                 :            : 
      51                 :            :         /*
      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.
      55                 :            :          */
      56                 :            :         first_ppage_reported = first_ppage;
      57         [ #  # ]:          0 :         if (iomap->offset == 0)
      58                 :          0 :                 first_ppage_reported++;
      59         [ #  # ]:          0 :         if (isi->lowest_ppage > first_ppage_reported)
      60                 :          0 :                 isi->lowest_ppage = first_ppage_reported;
      61         [ #  # ]:          0 :         if (isi->highest_ppage < (next_ppage - 1))
      62                 :          0 :                 isi->highest_ppage = next_ppage - 1;
      63                 :            : 
      64                 :            :         /* Add extent, set up for the next call. */
      65                 :          0 :         error = add_swap_extent(isi->sis, isi->nr_pages, nr_pages, first_ppage);
      66         [ #  # ]:          0 :         if (error < 0)
      67                 :            :                 return error;
      68                 :          0 :         isi->nr_extents += error;
      69                 :          0 :         isi->nr_pages += nr_pages;
      70                 :          0 :         return 0;
      71                 :            : }
      72                 :            : 
      73                 :            : /*
      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.
      77                 :            :  */
      78                 :          0 : static loff_t iomap_swapfile_activate_actor(struct inode *inode, loff_t pos,
      79                 :            :                 loff_t count, void *data, struct iomap *iomap)
      80                 :            : {
      81                 :            :         struct iomap_swapfile_info *isi = data;
      82                 :            :         int error;
      83                 :            : 
      84      [ #  #  # ]:          0 :         switch (iomap->type) {
      85                 :            :         case IOMAP_MAPPED:
      86                 :            :         case IOMAP_UNWRITTEN:
      87                 :            :                 /* Only real or unwritten extents. */
      88                 :            :                 break;
      89                 :            :         case IOMAP_INLINE:
      90                 :            :                 /* No inline data. */
      91                 :          0 :                 pr_err("swapon: file is inline\n");
      92                 :          0 :                 return -EINVAL;
      93                 :            :         default:
      94                 :          0 :                 pr_err("swapon: file has unallocated extents\n");
      95                 :          0 :                 return -EINVAL;
      96                 :            :         }
      97                 :            : 
      98                 :            :         /* No uncommitted metadata or shared blocks. */
      99         [ #  # ]:          0 :         if (iomap->flags & IOMAP_F_DIRTY) {
     100                 :          0 :                 pr_err("swapon: file is not committed\n");
     101                 :          0 :                 return -EINVAL;
     102                 :            :         }
     103         [ #  # ]:          0 :         if (iomap->flags & IOMAP_F_SHARED) {
     104                 :          0 :                 pr_err("swapon: file has shared extents\n");
     105                 :          0 :                 return -EINVAL;
     106                 :            :         }
     107                 :            : 
     108                 :            :         /* Only one bdev per swap file. */
     109         [ #  # ]:          0 :         if (iomap->bdev != isi->sis->bdev) {
     110                 :          0 :                 pr_err("swapon: file is on multiple devices\n");
     111                 :          0 :                 return -EINVAL;
     112                 :            :         }
     113                 :            : 
     114         [ #  # ]:          0 :         if (isi->iomap.length == 0) {
     115                 :            :                 /* No accumulated extent, so just store it. */
     116                 :          0 :                 memcpy(&isi->iomap, iomap, sizeof(isi->iomap));
     117         [ #  # ]:          0 :         } else if (isi->iomap.addr + isi->iomap.length == iomap->addr) {
     118                 :            :                 /* Append this to the accumulated extent. */
     119                 :          0 :                 isi->iomap.length += iomap->length;
     120                 :            :         } else {
     121                 :            :                 /* Otherwise, add the retained iomap and store this one. */
     122                 :          0 :                 error = iomap_swapfile_add_extent(isi);
     123         [ #  # ]:          0 :                 if (error)
     124                 :          0 :                         return error;
     125                 :          0 :                 memcpy(&isi->iomap, iomap, sizeof(isi->iomap));
     126                 :            :         }
     127                 :          0 :         return count;
     128                 :            : }
     129                 :            : 
     130                 :            : /*
     131                 :            :  * Iterate a swap file's iomaps to construct physical extents that can be
     132                 :            :  * passed to the swapfile subsystem.
     133                 :            :  */
     134                 :          0 : int iomap_swapfile_activate(struct swap_info_struct *sis,
     135                 :            :                 struct file *swap_file, sector_t *pagespan,
     136                 :            :                 const struct iomap_ops *ops)
     137                 :            : {
     138                 :          0 :         struct iomap_swapfile_info isi = {
     139                 :            :                 .sis = sis,
     140                 :            :                 .lowest_ppage = (sector_t)-1ULL,
     141                 :            :         };
     142                 :          0 :         struct address_space *mapping = swap_file->f_mapping;
     143                 :          0 :         struct inode *inode = mapping->host;
     144                 :            :         loff_t pos = 0;
     145                 :          0 :         loff_t len = ALIGN_DOWN(i_size_read(inode), PAGE_SIZE);
     146                 :            :         loff_t ret;
     147                 :            : 
     148                 :            :         /*
     149                 :            :          * Persist all file mapping metadata so that we won't have any
     150                 :            :          * IOMAP_F_DIRTY iomaps.
     151                 :            :          */
     152                 :          0 :         ret = vfs_fsync(swap_file, 1);
     153         [ #  # ]:          0 :         if (ret)
     154                 :            :                 return ret;
     155                 :            : 
     156         [ #  # ]:          0 :         while (len > 0) {
     157                 :          0 :                 ret = iomap_apply(inode, pos, len, IOMAP_REPORT,
     158                 :            :                                 ops, &isi, iomap_swapfile_activate_actor);
     159         [ #  # ]:          0 :                 if (ret <= 0)
     160                 :          0 :                         return ret;
     161                 :            : 
     162                 :          0 :                 pos += ret;
     163                 :          0 :                 len -= ret;
     164                 :            :         }
     165                 :            : 
     166         [ #  # ]:          0 :         if (isi.iomap.length) {
     167                 :          0 :                 ret = iomap_swapfile_add_extent(&isi);
     168         [ #  # ]:          0 :                 if (ret)
     169                 :            :                         return ret;
     170                 :            :         }
     171                 :            : 
     172                 :          0 :         *pagespan = 1 + isi.highest_ppage - isi.lowest_ppage;
     173                 :          0 :         sis->max = isi.nr_pages;
     174                 :          0 :         sis->pages = isi.nr_pages - 1;
     175                 :          0 :         sis->highest_bit = isi.nr_pages - 1;
     176                 :          0 :         return isi.nr_extents;
     177                 :            : }
     178                 :            : EXPORT_SYMBOL_GPL(iomap_swapfile_activate);

Generated by: LCOV version 1.14