📄 xfs_trans_buf.c
字号:
/* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_types.h"#include "xfs_bit.h"#include "xfs_log.h"#include "xfs_inum.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_bmap_btree.h"#include "xfs_alloc_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_buf_item.h"#include "xfs_trans_priv.h"#include "xfs_error.h"#include "xfs_rw.h"STATIC xfs_buf_t *xfs_trans_buf_item_match(xfs_trans_t *, xfs_buftarg_t *, xfs_daddr_t, int);STATIC xfs_buf_t *xfs_trans_buf_item_match_all(xfs_trans_t *, xfs_buftarg_t *, xfs_daddr_t, int);/* * Get and lock the buffer for the caller if it is not already * locked within the given transaction. If it is already locked * within the transaction, just increment its lock recursion count * and return a pointer to it. * * Use the fast path function xfs_trans_buf_item_match() or the buffer * cache routine incore_match() to find the buffer * if it is already owned by this transaction. * * If we don't already own the buffer, use get_buf() to get it. * If it doesn't yet have an associated xfs_buf_log_item structure, * then allocate one and add the item to this transaction. * * If the transaction pointer is NULL, make this just a normal * get_buf() call. */xfs_buf_t *xfs_trans_get_buf(xfs_trans_t *tp, xfs_buftarg_t *target_dev, xfs_daddr_t blkno, int len, uint flags){ xfs_buf_t *bp; xfs_buf_log_item_t *bip; if (flags == 0) flags = XFS_BUF_LOCK | XFS_BUF_MAPPED; /* * Default to a normal get_buf() call if the tp is NULL. */ if (tp == NULL) { bp = xfs_buf_get_flags(target_dev, blkno, len, flags | BUF_BUSY); return(bp); } /* * If we find the buffer in the cache with this transaction * pointer in its b_fsprivate2 field, then we know we already * have it locked. In this case we just increment the lock * recursion count and return the buffer to the caller. */ if (tp->t_items.lic_next == NULL) { bp = xfs_trans_buf_item_match(tp, target_dev, blkno, len); } else { bp = xfs_trans_buf_item_match_all(tp, target_dev, blkno, len); } if (bp != NULL) { ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); if (XFS_FORCED_SHUTDOWN(tp->t_mountp)) { xfs_buftrace("TRANS GET RECUR SHUT", bp); XFS_BUF_SUPER_STALE(bp); } /* * If the buffer is stale then it was binval'ed * since last read. This doesn't matter since the * caller isn't allowed to use the data anyway. */ else if (XFS_BUF_ISSTALE(bp)) { xfs_buftrace("TRANS GET RECUR STALE", bp); ASSERT(!XFS_BUF_ISDELAYWRITE(bp)); } ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); ASSERT(bip != NULL); ASSERT(atomic_read(&bip->bli_refcount) > 0); bip->bli_recur++; xfs_buftrace("TRANS GET RECUR", bp); xfs_buf_item_trace("GET RECUR", bip); return (bp); } /* * We always specify the BUF_BUSY flag within a transaction so * that get_buf does not try to push out a delayed write buffer * which might cause another transaction to take place (if the * buffer was delayed alloc). Such recursive transactions can * easily deadlock with our current transaction as well as cause * us to run out of stack space. */ bp = xfs_buf_get_flags(target_dev, blkno, len, flags | BUF_BUSY); if (bp == NULL) { return NULL; } ASSERT(!XFS_BUF_GETERROR(bp)); /* * The xfs_buf_log_item pointer is stored in b_fsprivate. If * it doesn't have one yet, then allocate one and initialize it. * The checks to see if one is there are in xfs_buf_item_init(). */ xfs_buf_item_init(bp, tp->t_mountp); /* * Set the recursion count for the buffer within this transaction * to 0. */ bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); bip->bli_recur = 0; /* * Take a reference for this transaction on the buf item. */ atomic_inc(&bip->bli_refcount); /* * Get a log_item_desc to point at the new item. */ (void) xfs_trans_add_item(tp, (xfs_log_item_t*)bip); /* * Initialize b_fsprivate2 so we can find it with incore_match() * above. */ XFS_BUF_SET_FSPRIVATE2(bp, tp); xfs_buftrace("TRANS GET", bp); xfs_buf_item_trace("GET", bip); return (bp);}/* * Get and lock the superblock buffer of this file system for the * given transaction. * * We don't need to use incore_match() here, because the superblock * buffer is a private buffer which we keep a pointer to in the * mount structure. */xfs_buf_t *xfs_trans_getsb(xfs_trans_t *tp, struct xfs_mount *mp, int flags){ xfs_buf_t *bp; xfs_buf_log_item_t *bip; /* * Default to just trying to lock the superblock buffer * if tp is NULL. */ if (tp == NULL) { return (xfs_getsb(mp, flags)); } /* * If the superblock buffer already has this transaction * pointer in its b_fsprivate2 field, then we know we already * have it locked. In this case we just increment the lock * recursion count and return the buffer to the caller. */ bp = mp->m_sb_bp; if (XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp) { bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); ASSERT(bip != NULL); ASSERT(atomic_read(&bip->bli_refcount) > 0); bip->bli_recur++; xfs_buf_item_trace("GETSB RECUR", bip); return (bp); } bp = xfs_getsb(mp, flags); if (bp == NULL) { return NULL; } /* * The xfs_buf_log_item pointer is stored in b_fsprivate. If * it doesn't have one yet, then allocate one and initialize it. * The checks to see if one is there are in xfs_buf_item_init(). */ xfs_buf_item_init(bp, mp); /* * Set the recursion count for the buffer within this transaction * to 0. */ bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); bip->bli_recur = 0; /* * Take a reference for this transaction on the buf item. */ atomic_inc(&bip->bli_refcount); /* * Get a log_item_desc to point at the new item. */ (void) xfs_trans_add_item(tp, (xfs_log_item_t*)bip); /* * Initialize b_fsprivate2 so we can find it with incore_match() * above. */ XFS_BUF_SET_FSPRIVATE2(bp, tp); xfs_buf_item_trace("GETSB", bip); return (bp);}#ifdef DEBUGxfs_buftarg_t *xfs_error_target;int xfs_do_error;int xfs_req_num;int xfs_error_mod = 33;#endif/* * Get and lock the buffer for the caller if it is not already * locked within the given transaction. If it has not yet been * read in, read it from disk. If it is already locked * within the transaction and already read in, just increment its * lock recursion count and return a pointer to it. * * Use the fast path function xfs_trans_buf_item_match() or the buffer * cache routine incore_match() to find the buffer * if it is already owned by this transaction. * * If we don't already own the buffer, use read_buf() to get it. * If it doesn't yet have an associated xfs_buf_log_item structure, * then allocate one and add the item to this transaction. * * If the transaction pointer is NULL, make this just a normal * read_buf() call. */intxfs_trans_read_buf( xfs_mount_t *mp, xfs_trans_t *tp, xfs_buftarg_t *target, xfs_daddr_t blkno, int len, uint flags, xfs_buf_t **bpp){ xfs_buf_t *bp; xfs_buf_log_item_t *bip; int error; if (flags == 0) flags = XFS_BUF_LOCK | XFS_BUF_MAPPED; /* * Default to a normal get_buf() call if the tp is NULL. */ if (tp == NULL) { bp = xfs_buf_read_flags(target, blkno, len, flags | BUF_BUSY); if (!bp) return XFS_ERROR(ENOMEM); if ((bp != NULL) && (XFS_BUF_GETERROR(bp) != 0)) { xfs_ioerror_alert("xfs_trans_read_buf", mp, bp, blkno); error = XFS_BUF_GETERROR(bp); xfs_buf_relse(bp); return error; }#ifdef DEBUG if (xfs_do_error && (bp != NULL)) { if (xfs_error_target == target) { if (((xfs_req_num++) % xfs_error_mod) == 0) { xfs_buf_relse(bp); cmn_err(CE_DEBUG, "Returning error!\n"); return XFS_ERROR(EIO); } } }#endif if (XFS_FORCED_SHUTDOWN(mp)) goto shutdown_abort; *bpp = bp; return 0; } /* * If we find the buffer in the cache with this transaction * pointer in its b_fsprivate2 field, then we know we already * have it locked. If it is already read in we just increment * the lock recursion count and return the buffer to the caller. * If the buffer is not yet read in, then we read it in, increment * the lock recursion count, and return it to the caller. */ if (tp->t_items.lic_next == NULL) { bp = xfs_trans_buf_item_match(tp, target, blkno, len); } else { bp = xfs_trans_buf_item_match_all(tp, target, blkno, len); } if (bp != NULL) { ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); ASSERT((XFS_BUF_ISERROR(bp)) == 0); if (!(XFS_BUF_ISDONE(bp))) { xfs_buftrace("READ_BUF_INCORE !DONE", bp); ASSERT(!XFS_BUF_ISASYNC(bp)); XFS_BUF_READ(bp); xfsbdstrat(tp->t_mountp, bp); xfs_iowait(bp); if (XFS_BUF_GETERROR(bp) != 0) { xfs_ioerror_alert("xfs_trans_read_buf", mp, bp, blkno); error = XFS_BUF_GETERROR(bp); xfs_buf_relse(bp); /* * We can gracefully recover from most * read errors. Ones we can't are those * that happen after the transaction's * already dirty. */ if (tp->t_flags & XFS_TRANS_DIRTY) xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR); return error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -