1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2022 Fujitsu. All Rights Reserved. 4 */ 5 6 #include "xfs.h" 7 #include "xfs_shared.h" 8 #include "xfs_format.h" 9 #include "xfs_log_format.h" 10 #include "xfs_trans_resv.h" 11 #include "xfs_mount.h" 12 #include "xfs_alloc.h" 13 #include "xfs_bit.h" 14 #include "xfs_btree.h" 15 #include "xfs_inode.h" 16 #include "xfs_icache.h" 17 #include "xfs_rmap.h" 18 #include "xfs_rmap_btree.h" 19 #include "xfs_rtalloc.h" 20 #include "xfs_trans.h" 21 #include "xfs_ag.h" 22 23 #include <linux/mm.h> 24 #include <linux/dax.h> 25 26 struct failure_info { 27 xfs_agblock_t startblock; 28 xfs_extlen_t blockcount; 29 int mf_flags; 30 }; 31 32 static pgoff_t 33 xfs_failure_pgoff( 34 struct xfs_mount *mp, 35 const struct xfs_rmap_irec *rec, 36 const struct failure_info *notify) 37 { 38 loff_t pos = XFS_FSB_TO_B(mp, rec->rm_offset); 39 40 if (notify->startblock > rec->rm_startblock) 41 pos += XFS_FSB_TO_B(mp, 42 notify->startblock - rec->rm_startblock); 43 return pos >> PAGE_SHIFT; 44 } 45 46 static unsigned long 47 xfs_failure_pgcnt( 48 struct xfs_mount *mp, 49 const struct xfs_rmap_irec *rec, 50 const struct failure_info *notify) 51 { 52 xfs_agblock_t end_rec; 53 xfs_agblock_t end_notify; 54 xfs_agblock_t start_cross; 55 xfs_agblock_t end_cross; 56 57 start_cross = max(rec->rm_startblock, notify->startblock); 58 59 end_rec = rec->rm_startblock + rec->rm_blockcount; 60 end_notify = notify->startblock + notify->blockcount; 61 end_cross = min(end_rec, end_notify); 62 63 return XFS_FSB_TO_B(mp, end_cross - start_cross) >> PAGE_SHIFT; 64 } 65 66 static int 67 xfs_dax_failure_fn( 68 struct xfs_btree_cur *cur, 69 const struct xfs_rmap_irec *rec, 70 void *data) 71 { 72 struct xfs_mount *mp = cur->bc_mp; 73 struct xfs_inode *ip; 74 struct failure_info *notify = data; 75 int error = 0; 76 77 if (XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) || 78 (rec->rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))) { 79 xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK); 80 return -EFSCORRUPTED; 81 } 82 83 /* Get files that incore, filter out others that are not in use. */ 84 error = xfs_iget(mp, cur->bc_tp, rec->rm_owner, XFS_IGET_INCORE, 85 0, &ip); 86 /* Continue the rmap query if the inode isn't incore */ 87 if (error == -ENODATA) 88 return 0; 89 if (error) 90 return error; 91 92 error = mf_dax_kill_procs(VFS_I(ip)->i_mapping, 93 xfs_failure_pgoff(mp, rec, notify), 94 xfs_failure_pgcnt(mp, rec, notify), 95 notify->mf_flags); 96 xfs_irele(ip); 97 return error; 98 } 99 100 static int 101 xfs_dax_notify_ddev_failure( 102 struct xfs_mount *mp, 103 xfs_daddr_t daddr, 104 xfs_daddr_t bblen, 105 int mf_flags) 106 { 107 struct xfs_trans *tp = NULL; 108 struct xfs_btree_cur *cur = NULL; 109 struct xfs_buf *agf_bp = NULL; 110 int error = 0; 111 xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, daddr); 112 xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, fsbno); 113 xfs_fsblock_t end_fsbno = XFS_DADDR_TO_FSB(mp, daddr + bblen); 114 xfs_agnumber_t end_agno = XFS_FSB_TO_AGNO(mp, end_fsbno); 115 116 error = xfs_trans_alloc_empty(mp, &tp); 117 if (error) 118 return error; 119 120 for (; agno <= end_agno; agno++) { 121 struct xfs_rmap_irec ri_low = { }; 122 struct xfs_rmap_irec ri_high; 123 struct failure_info notify; 124 struct xfs_agf *agf; 125 xfs_agblock_t agend; 126 struct xfs_perag *pag; 127 128 pag = xfs_perag_get(mp, agno); 129 error = xfs_alloc_read_agf(pag, tp, 0, &agf_bp); 130 if (error) { 131 xfs_perag_put(pag); 132 break; 133 } 134 135 cur = xfs_rmapbt_init_cursor(mp, tp, agf_bp, pag); 136 137 /* 138 * Set the rmap range from ri_low to ri_high, which represents 139 * a [start, end] where we looking for the files or metadata. 140 */ 141 memset(&ri_high, 0xFF, sizeof(ri_high)); 142 ri_low.rm_startblock = XFS_FSB_TO_AGBNO(mp, fsbno); 143 if (agno == end_agno) 144 ri_high.rm_startblock = XFS_FSB_TO_AGBNO(mp, end_fsbno); 145 146 agf = agf_bp->b_addr; 147 agend = min(be32_to_cpu(agf->agf_length), 148 ri_high.rm_startblock); 149 notify.startblock = ri_low.rm_startblock; 150 notify.blockcount = agend - ri_low.rm_startblock; 151 152 error = xfs_rmap_query_range(cur, &ri_low, &ri_high, 153 xfs_dax_failure_fn, ¬ify); 154 xfs_btree_del_cursor(cur, error); 155 xfs_trans_brelse(tp, agf_bp); 156 xfs_perag_put(pag); 157 if (error) 158 break; 159 160 fsbno = XFS_AGB_TO_FSB(mp, agno + 1, 0); 161 } 162 163 xfs_trans_cancel(tp); 164 return error; 165 } 166 167 static int 168 xfs_dax_notify_failure( 169 struct dax_device *dax_dev, 170 u64 offset, 171 u64 len, 172 int mf_flags) 173 { 174 struct xfs_mount *mp = dax_holder(dax_dev); 175 u64 ddev_start; 176 u64 ddev_end; 177 178 if (!(mp->m_super->s_flags & SB_BORN)) { 179 xfs_warn(mp, "filesystem is not ready for notify_failure()!"); 180 return -EIO; 181 } 182 183 if (mp->m_rtdev_targp && mp->m_rtdev_targp->bt_daxdev == dax_dev) { 184 xfs_debug(mp, 185 "notify_failure() not supported on realtime device!"); 186 return -EOPNOTSUPP; 187 } 188 189 if (mp->m_logdev_targp && mp->m_logdev_targp->bt_daxdev == dax_dev && 190 mp->m_logdev_targp != mp->m_ddev_targp) { 191 xfs_err(mp, "ondisk log corrupt, shutting down fs!"); 192 xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK); 193 return -EFSCORRUPTED; 194 } 195 196 if (!xfs_has_rmapbt(mp)) { 197 xfs_debug(mp, "notify_failure() needs rmapbt enabled!"); 198 return -EOPNOTSUPP; 199 } 200 201 ddev_start = mp->m_ddev_targp->bt_dax_part_off; 202 ddev_end = ddev_start + bdev_nr_bytes(mp->m_ddev_targp->bt_bdev) - 1; 203 204 /* Ignore the range out of filesystem area */ 205 if (offset + len < ddev_start) 206 return -ENXIO; 207 if (offset > ddev_end) 208 return -ENXIO; 209 210 /* Calculate the real range when it touches the boundary */ 211 if (offset > ddev_start) 212 offset -= ddev_start; 213 else { 214 len -= ddev_start - offset; 215 offset = 0; 216 } 217 if (offset + len > ddev_end) 218 len -= ddev_end - offset; 219 220 return xfs_dax_notify_ddev_failure(mp, BTOBB(offset), BTOBB(len), 221 mf_flags); 222 } 223 224 const struct dax_holder_operations xfs_dax_holder_operations = { 225 .notify_failure = xfs_dax_notify_failure, 226 }; 227