332 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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#include <linux/fs.h>26 27struct xfs_failure_info {28 xfs_agblock_t startblock;29 xfs_extlen_t blockcount;30 int mf_flags;31 bool want_shutdown;32};33 34static pgoff_t35xfs_failure_pgoff(36 struct xfs_mount *mp,37 const struct xfs_rmap_irec *rec,38 const struct xfs_failure_info *notify)39{40 loff_t pos = XFS_FSB_TO_B(mp, rec->rm_offset);41 42 if (notify->startblock > rec->rm_startblock)43 pos += XFS_FSB_TO_B(mp,44 notify->startblock - rec->rm_startblock);45 return pos >> PAGE_SHIFT;46}47 48static unsigned long49xfs_failure_pgcnt(50 struct xfs_mount *mp,51 const struct xfs_rmap_irec *rec,52 const struct xfs_failure_info *notify)53{54 xfs_agblock_t end_rec;55 xfs_agblock_t end_notify;56 xfs_agblock_t start_cross;57 xfs_agblock_t end_cross;58 59 start_cross = max(rec->rm_startblock, notify->startblock);60 61 end_rec = rec->rm_startblock + rec->rm_blockcount;62 end_notify = notify->startblock + notify->blockcount;63 end_cross = min(end_rec, end_notify);64 65 return XFS_FSB_TO_B(mp, end_cross - start_cross) >> PAGE_SHIFT;66}67 68static int69xfs_dax_failure_fn(70 struct xfs_btree_cur *cur,71 const struct xfs_rmap_irec *rec,72 void *data)73{74 struct xfs_mount *mp = cur->bc_mp;75 struct xfs_inode *ip;76 struct xfs_failure_info *notify = data;77 struct address_space *mapping;78 pgoff_t pgoff;79 unsigned long pgcnt;80 int error = 0;81 82 if (XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) ||83 (rec->rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))) {84 /* Continue the query because this isn't a failure. */85 if (notify->mf_flags & MF_MEM_PRE_REMOVE)86 return 0;87 notify->want_shutdown = true;88 return 0;89 }90 91 /* Get files that incore, filter out others that are not in use. */92 error = xfs_iget(mp, cur->bc_tp, rec->rm_owner, XFS_IGET_INCORE,93 0, &ip);94 /* Continue the rmap query if the inode isn't incore */95 if (error == -ENODATA)96 return 0;97 if (error) {98 notify->want_shutdown = true;99 return 0;100 }101 102 mapping = VFS_I(ip)->i_mapping;103 pgoff = xfs_failure_pgoff(mp, rec, notify);104 pgcnt = xfs_failure_pgcnt(mp, rec, notify);105 106 /* Continue the rmap query if the inode isn't a dax file. */107 if (dax_mapping(mapping))108 error = mf_dax_kill_procs(mapping, pgoff, pgcnt,109 notify->mf_flags);110 111 /* Invalidate the cache in dax pages. */112 if (notify->mf_flags & MF_MEM_PRE_REMOVE)113 invalidate_inode_pages2_range(mapping, pgoff,114 pgoff + pgcnt - 1);115 116 xfs_irele(ip);117 return error;118}119 120static int121xfs_dax_notify_failure_freeze(122 struct xfs_mount *mp)123{124 struct super_block *sb = mp->m_super;125 int error;126 127 error = freeze_super(sb, FREEZE_HOLDER_KERNEL);128 if (error)129 xfs_emerg(mp, "already frozen by kernel, err=%d", error);130 131 return error;132}133 134static void135xfs_dax_notify_failure_thaw(136 struct xfs_mount *mp,137 bool kernel_frozen)138{139 struct super_block *sb = mp->m_super;140 int error;141 142 if (kernel_frozen) {143 error = thaw_super(sb, FREEZE_HOLDER_KERNEL);144 if (error)145 xfs_emerg(mp, "still frozen after notify failure, err=%d",146 error);147 }148 149 /*150 * Also thaw userspace call anyway because the device is about to be151 * removed immediately.152 */153 thaw_super(sb, FREEZE_HOLDER_USERSPACE);154}155 156static int157xfs_dax_notify_ddev_failure(158 struct xfs_mount *mp,159 xfs_daddr_t daddr,160 xfs_daddr_t bblen,161 int mf_flags)162{163 struct xfs_failure_info notify = { .mf_flags = mf_flags };164 struct xfs_trans *tp = NULL;165 struct xfs_btree_cur *cur = NULL;166 struct xfs_buf *agf_bp = NULL;167 int error = 0;168 bool kernel_frozen = false;169 xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, daddr);170 xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, fsbno);171 xfs_fsblock_t end_fsbno = XFS_DADDR_TO_FSB(mp,172 daddr + bblen - 1);173 xfs_agnumber_t end_agno = XFS_FSB_TO_AGNO(mp, end_fsbno);174 175 if (mf_flags & MF_MEM_PRE_REMOVE) {176 xfs_info(mp, "Device is about to be removed!");177 /*178 * Freeze fs to prevent new mappings from being created.179 * - Keep going on if others already hold the kernel forzen.180 * - Keep going on if other errors too because this device is181 * starting to fail.182 * - If kernel frozen state is hold successfully here, thaw it183 * here as well at the end.184 */185 kernel_frozen = xfs_dax_notify_failure_freeze(mp) == 0;186 }187 188 error = xfs_trans_alloc_empty(mp, &tp);189 if (error)190 goto out;191 192 for (; agno <= end_agno; agno++) {193 struct xfs_rmap_irec ri_low = { };194 struct xfs_rmap_irec ri_high;195 struct xfs_agf *agf;196 struct xfs_perag *pag;197 xfs_agblock_t range_agend;198 199 pag = xfs_perag_get(mp, agno);200 error = xfs_alloc_read_agf(pag, tp, 0, &agf_bp);201 if (error) {202 xfs_perag_put(pag);203 break;204 }205 206 cur = xfs_rmapbt_init_cursor(mp, tp, agf_bp, pag);207 208 /*209 * Set the rmap range from ri_low to ri_high, which represents210 * a [start, end] where we looking for the files or metadata.211 */212 memset(&ri_high, 0xFF, sizeof(ri_high));213 ri_low.rm_startblock = XFS_FSB_TO_AGBNO(mp, fsbno);214 if (agno == end_agno)215 ri_high.rm_startblock = XFS_FSB_TO_AGBNO(mp, end_fsbno);216 217 agf = agf_bp->b_addr;218 range_agend = min(be32_to_cpu(agf->agf_length) - 1,219 ri_high.rm_startblock);220 notify.startblock = ri_low.rm_startblock;221 notify.blockcount = range_agend + 1 - ri_low.rm_startblock;222 223 error = xfs_rmap_query_range(cur, &ri_low, &ri_high,224 xfs_dax_failure_fn, ¬ify);225 xfs_btree_del_cursor(cur, error);226 xfs_trans_brelse(tp, agf_bp);227 xfs_perag_put(pag);228 if (error)229 break;230 231 fsbno = XFS_AGB_TO_FSB(mp, agno + 1, 0);232 }233 234 xfs_trans_cancel(tp);235 236 /*237 * Shutdown fs from a force umount in pre-remove case which won't fail,238 * so errors can be ignored. Otherwise, shutdown the filesystem with239 * CORRUPT flag if error occured or notify.want_shutdown was set during240 * RMAP querying.241 */242 if (mf_flags & MF_MEM_PRE_REMOVE)243 xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);244 else if (error || notify.want_shutdown) {245 xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK);246 if (!error)247 error = -EFSCORRUPTED;248 }249 250out:251 /* Thaw the fs if it has been frozen before. */252 if (mf_flags & MF_MEM_PRE_REMOVE)253 xfs_dax_notify_failure_thaw(mp, kernel_frozen);254 255 return error;256}257 258static int259xfs_dax_notify_failure(260 struct dax_device *dax_dev,261 u64 offset,262 u64 len,263 int mf_flags)264{265 struct xfs_mount *mp = dax_holder(dax_dev);266 u64 ddev_start;267 u64 ddev_end;268 269 if (!(mp->m_super->s_flags & SB_BORN)) {270 xfs_warn(mp, "filesystem is not ready for notify_failure()!");271 return -EIO;272 }273 274 if (mp->m_rtdev_targp && mp->m_rtdev_targp->bt_daxdev == dax_dev) {275 xfs_debug(mp,276 "notify_failure() not supported on realtime device!");277 return -EOPNOTSUPP;278 }279 280 if (mp->m_logdev_targp && mp->m_logdev_targp->bt_daxdev == dax_dev &&281 mp->m_logdev_targp != mp->m_ddev_targp) {282 /*283 * In the pre-remove case the failure notification is attempting284 * to trigger a force unmount. The expectation is that the285 * device is still present, but its removal is in progress and286 * can not be cancelled, proceed with accessing the log device.287 */288 if (mf_flags & MF_MEM_PRE_REMOVE)289 return 0;290 xfs_err(mp, "ondisk log corrupt, shutting down fs!");291 xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK);292 return -EFSCORRUPTED;293 }294 295 if (!xfs_has_rmapbt(mp)) {296 xfs_debug(mp, "notify_failure() needs rmapbt enabled!");297 return -EOPNOTSUPP;298 }299 300 ddev_start = mp->m_ddev_targp->bt_dax_part_off;301 ddev_end = ddev_start + bdev_nr_bytes(mp->m_ddev_targp->bt_bdev) - 1;302 303 /* Notify failure on the whole device. */304 if (offset == 0 && len == U64_MAX) {305 offset = ddev_start;306 len = bdev_nr_bytes(mp->m_ddev_targp->bt_bdev);307 }308 309 /* Ignore the range out of filesystem area */310 if (offset + len - 1 < ddev_start)311 return -ENXIO;312 if (offset > ddev_end)313 return -ENXIO;314 315 /* Calculate the real range when it touches the boundary */316 if (offset > ddev_start)317 offset -= ddev_start;318 else {319 len -= ddev_start - offset;320 offset = 0;321 }322 if (offset + len - 1 > ddev_end)323 len = ddev_end - offset + 1;324 325 return xfs_dax_notify_ddev_failure(mp, BTOBB(offset), BTOBB(len),326 mf_flags);327}328 329const struct dax_holder_operations xfs_dax_holder_operations = {330 .notify_failure = xfs_dax_notify_failure,331};332