Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2022 Fujitsu.  All Rights Reserved.
0004  */
0005 
0006 #include "xfs.h"
0007 #include "xfs_shared.h"
0008 #include "xfs_format.h"
0009 #include "xfs_log_format.h"
0010 #include "xfs_trans_resv.h"
0011 #include "xfs_mount.h"
0012 #include "xfs_alloc.h"
0013 #include "xfs_bit.h"
0014 #include "xfs_btree.h"
0015 #include "xfs_inode.h"
0016 #include "xfs_icache.h"
0017 #include "xfs_rmap.h"
0018 #include "xfs_rmap_btree.h"
0019 #include "xfs_rtalloc.h"
0020 #include "xfs_trans.h"
0021 #include "xfs_ag.h"
0022 
0023 #include <linux/mm.h>
0024 #include <linux/dax.h>
0025 
0026 struct failure_info {
0027     xfs_agblock_t       startblock;
0028     xfs_extlen_t        blockcount;
0029     int         mf_flags;
0030 };
0031 
0032 static pgoff_t
0033 xfs_failure_pgoff(
0034     struct xfs_mount        *mp,
0035     const struct xfs_rmap_irec  *rec,
0036     const struct failure_info   *notify)
0037 {
0038     loff_t              pos = XFS_FSB_TO_B(mp, rec->rm_offset);
0039 
0040     if (notify->startblock > rec->rm_startblock)
0041         pos += XFS_FSB_TO_B(mp,
0042                 notify->startblock - rec->rm_startblock);
0043     return pos >> PAGE_SHIFT;
0044 }
0045 
0046 static unsigned long
0047 xfs_failure_pgcnt(
0048     struct xfs_mount        *mp,
0049     const struct xfs_rmap_irec  *rec,
0050     const struct failure_info   *notify)
0051 {
0052     xfs_agblock_t           end_rec;
0053     xfs_agblock_t           end_notify;
0054     xfs_agblock_t           start_cross;
0055     xfs_agblock_t           end_cross;
0056 
0057     start_cross = max(rec->rm_startblock, notify->startblock);
0058 
0059     end_rec = rec->rm_startblock + rec->rm_blockcount;
0060     end_notify = notify->startblock + notify->blockcount;
0061     end_cross = min(end_rec, end_notify);
0062 
0063     return XFS_FSB_TO_B(mp, end_cross - start_cross) >> PAGE_SHIFT;
0064 }
0065 
0066 static int
0067 xfs_dax_failure_fn(
0068     struct xfs_btree_cur        *cur,
0069     const struct xfs_rmap_irec  *rec,
0070     void                *data)
0071 {
0072     struct xfs_mount        *mp = cur->bc_mp;
0073     struct xfs_inode        *ip;
0074     struct failure_info     *notify = data;
0075     int             error = 0;
0076 
0077     if (XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) ||
0078         (rec->rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))) {
0079         xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK);
0080         return -EFSCORRUPTED;
0081     }
0082 
0083     /* Get files that incore, filter out others that are not in use. */
0084     error = xfs_iget(mp, cur->bc_tp, rec->rm_owner, XFS_IGET_INCORE,
0085              0, &ip);
0086     /* Continue the rmap query if the inode isn't incore */
0087     if (error == -ENODATA)
0088         return 0;
0089     if (error)
0090         return error;
0091 
0092     error = mf_dax_kill_procs(VFS_I(ip)->i_mapping,
0093                   xfs_failure_pgoff(mp, rec, notify),
0094                   xfs_failure_pgcnt(mp, rec, notify),
0095                   notify->mf_flags);
0096     xfs_irele(ip);
0097     return error;
0098 }
0099 
0100 static int
0101 xfs_dax_notify_ddev_failure(
0102     struct xfs_mount    *mp,
0103     xfs_daddr_t     daddr,
0104     xfs_daddr_t     bblen,
0105     int         mf_flags)
0106 {
0107     struct xfs_trans    *tp = NULL;
0108     struct xfs_btree_cur    *cur = NULL;
0109     struct xfs_buf      *agf_bp = NULL;
0110     int         error = 0;
0111     xfs_fsblock_t       fsbno = XFS_DADDR_TO_FSB(mp, daddr);
0112     xfs_agnumber_t      agno = XFS_FSB_TO_AGNO(mp, fsbno);
0113     xfs_fsblock_t       end_fsbno = XFS_DADDR_TO_FSB(mp, daddr + bblen);
0114     xfs_agnumber_t      end_agno = XFS_FSB_TO_AGNO(mp, end_fsbno);
0115 
0116     error = xfs_trans_alloc_empty(mp, &tp);
0117     if (error)
0118         return error;
0119 
0120     for (; agno <= end_agno; agno++) {
0121         struct xfs_rmap_irec    ri_low = { };
0122         struct xfs_rmap_irec    ri_high;
0123         struct failure_info notify;
0124         struct xfs_agf      *agf;
0125         xfs_agblock_t       agend;
0126         struct xfs_perag    *pag;
0127 
0128         pag = xfs_perag_get(mp, agno);
0129         error = xfs_alloc_read_agf(pag, tp, 0, &agf_bp);
0130         if (error) {
0131             xfs_perag_put(pag);
0132             break;
0133         }
0134 
0135         cur = xfs_rmapbt_init_cursor(mp, tp, agf_bp, pag);
0136 
0137         /*
0138          * Set the rmap range from ri_low to ri_high, which represents
0139          * a [start, end] where we looking for the files or metadata.
0140          */
0141         memset(&ri_high, 0xFF, sizeof(ri_high));
0142         ri_low.rm_startblock = XFS_FSB_TO_AGBNO(mp, fsbno);
0143         if (agno == end_agno)
0144             ri_high.rm_startblock = XFS_FSB_TO_AGBNO(mp, end_fsbno);
0145 
0146         agf = agf_bp->b_addr;
0147         agend = min(be32_to_cpu(agf->agf_length),
0148                 ri_high.rm_startblock);
0149         notify.startblock = ri_low.rm_startblock;
0150         notify.blockcount = agend - ri_low.rm_startblock;
0151 
0152         error = xfs_rmap_query_range(cur, &ri_low, &ri_high,
0153                 xfs_dax_failure_fn, &notify);
0154         xfs_btree_del_cursor(cur, error);
0155         xfs_trans_brelse(tp, agf_bp);
0156         xfs_perag_put(pag);
0157         if (error)
0158             break;
0159 
0160         fsbno = XFS_AGB_TO_FSB(mp, agno + 1, 0);
0161     }
0162 
0163     xfs_trans_cancel(tp);
0164     return error;
0165 }
0166 
0167 static int
0168 xfs_dax_notify_failure(
0169     struct dax_device   *dax_dev,
0170     u64         offset,
0171     u64         len,
0172     int         mf_flags)
0173 {
0174     struct xfs_mount    *mp = dax_holder(dax_dev);
0175     u64         ddev_start;
0176     u64         ddev_end;
0177 
0178     if (!(mp->m_super->s_flags & SB_BORN)) {
0179         xfs_warn(mp, "filesystem is not ready for notify_failure()!");
0180         return -EIO;
0181     }
0182 
0183     if (mp->m_rtdev_targp && mp->m_rtdev_targp->bt_daxdev == dax_dev) {
0184         xfs_debug(mp,
0185              "notify_failure() not supported on realtime device!");
0186         return -EOPNOTSUPP;
0187     }
0188 
0189     if (mp->m_logdev_targp && mp->m_logdev_targp->bt_daxdev == dax_dev &&
0190         mp->m_logdev_targp != mp->m_ddev_targp) {
0191         xfs_err(mp, "ondisk log corrupt, shutting down fs!");
0192         xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK);
0193         return -EFSCORRUPTED;
0194     }
0195 
0196     if (!xfs_has_rmapbt(mp)) {
0197         xfs_debug(mp, "notify_failure() needs rmapbt enabled!");
0198         return -EOPNOTSUPP;
0199     }
0200 
0201     ddev_start = mp->m_ddev_targp->bt_dax_part_off;
0202     ddev_end = ddev_start + bdev_nr_bytes(mp->m_ddev_targp->bt_bdev) - 1;
0203 
0204     /* Ignore the range out of filesystem area */
0205     if (offset + len < ddev_start)
0206         return -ENXIO;
0207     if (offset > ddev_end)
0208         return -ENXIO;
0209 
0210     /* Calculate the real range when it touches the boundary */
0211     if (offset > ddev_start)
0212         offset -= ddev_start;
0213     else {
0214         len -= ddev_start - offset;
0215         offset = 0;
0216     }
0217     if (offset + len > ddev_end)
0218         len -= ddev_end - offset;
0219 
0220     return xfs_dax_notify_ddev_failure(mp, BTOBB(offset), BTOBB(len),
0221             mf_flags);
0222 }
0223 
0224 const struct dax_holder_operations xfs_dax_holder_operations = {
0225     .notify_failure     = xfs_dax_notify_failure,
0226 };