/*
* 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