提交 c3eabd36 编写于 作者: D Darrick J. Wong

Merge tag 'xfs-perag-conv-tag' of...

Merge tag 'xfs-perag-conv-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/dgc/linux-xfs into xfs-5.14-merge2

xfs: initial agnumber -> perag conversions for shrink

If we want to use active references to the perag to be able to gate
shrink removing AGs and hence perags safely, we've got a fair bit of
work to do actually use perags in all the places we need to.

There's a lot of code that iterates ag numbers and then
looks up perags from that, often multiple times for the same perag
in the one operation. If we want to use reference counted perags for
access control, then we need to convert all these uses to perag
iterators, not agno iterators.

[Patches 1-4]

The first step of this is consolidating all the perag management -
init, free, get, put, etc into a common location. THis is spread all
over the place right now, so move it all into libxfs/xfs_ag.[ch].
This does expose kernel only bits of the perag to libxfs and hence
userspace, so the structures and code is rearranged to minimise the
number of ifdefs that need to be added to the userspace codebase.
The perag iterator in xfs_icache.c is promoted to a first class API
and expanded to the needs of the code as required.

[Patches 5-10]

These are the first basic perag iterator conversions and changes to
pass the perag down the stack from those iterators where
appropriate. A lot of this is obvious, simple changes, though in
some places we stop passing the perag down the stack because the
code enters into an as yet unconverted subsystem that still uses raw
AGs.

[Patches 11-16]

These replace the agno passed in the btree cursor for per-ag btree
operations with a perag that is passed to the cursor init function.
The cursor takes it's own reference to the perag, and the reference
is dropped when the cursor is deleted. Hence we get reference
coverage for the entire time the cursor is active, even if the code
that initialised the cursor drops it's reference before the cursor
or any of it's children (duplicates) have been deleted.

The first patch adds the perag infrastructure for the cursor, the
next four patches convert a btree cursor at a time, and the last
removes the agno from the cursor once it is unused.

[Patches 17-21]

These patches are a demonstration of the simplifications and
cleanups that come from plumbing the perag through interfaces that
select and then operate on a specific AG. In this case the inode
allocation algorithm does up to three walks across all AGs before it
either allocates an inode or fails. Two of these walks are purely
just to select the AG, and even then it doesn't guarantee inode
allocation success so there's a third walk if the selected AG
allocation fails.

These patches collapse the selection and allocation into a single
loop, simplifies the error handling because xfs_dir_ialloc() always
returns ENOSPC if no AG was selected for inode allocation or we fail
to allocate an inode in any AG, gets rid of xfs_dir_ialloc()
wrapper, converts inode allocation to run entirely from a single
perag instance, and then factors xfs_dialloc() into a much, much
simpler loop which is easy to understand.

Hence we end up with the same inode allocation logic, but it only
needs two complete iterations at worst, makes AG selection and
allocation atomic w.r.t. shrink and chops out out over 100 lines of
code from this hot code path.

[Patch 22]

Converts the unlink path to pass perags through it.

There's more conversion work to be done, but this patchset gets
through a large chunk of it in one hit. Most of the iterators are
converted, so once this is solidified we can move on to converting
these to active references for being able to free perags while the
fs is still active.

* tag 'xfs-perag-conv-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/dgc/linux-xfs: (23 commits)
  xfs: remove xfs_perag_t
  xfs: use perag through unlink processing
  xfs: clean up and simplify xfs_dialloc()
  xfs: inode allocation can use a single perag instance
  xfs: get rid of xfs_dir_ialloc()
  xfs: collapse AG selection for inode allocation
  xfs: simplify xfs_dialloc_select_ag() return values
  xfs: remove agno from btree cursor
  xfs: use perag for ialloc btree cursors
  xfs: convert allocbt cursors to use perags
  xfs: convert refcount btree cursor to use perags
  xfs: convert rmap btree cursor to using a perag
  xfs: add a perag to the btree cursor
  xfs: pass perags around in fsmap data dev functions
  xfs: push perags through the ag reservation callouts
  xfs: pass perags through to the busy extent code
  xfs: convert secondary superblock walk to use perags
  xfs: convert xfs_iwalk to use perag references
  xfs: convert raw ag walks to use for_each_perag
  xfs: make for_each_perag... a first class citizen
  ...
...@@ -27,6 +27,276 @@ ...@@ -27,6 +27,276 @@
#include "xfs_defer.h" #include "xfs_defer.h"
#include "xfs_log_format.h" #include "xfs_log_format.h"
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_trace.h"
#include "xfs_inode.h"
#include "xfs_icache.h"
/*
* Passive reference counting access wrappers to the perag structures. If the
* per-ag structure is to be freed, the freeing code is responsible for cleaning
* up objects with passive references before freeing the structure. This is
* things like cached buffers.
*/
struct xfs_perag *
xfs_perag_get(
struct xfs_mount *mp,
xfs_agnumber_t agno)
{
struct xfs_perag *pag;
int ref = 0;
rcu_read_lock();
pag = radix_tree_lookup(&mp->m_perag_tree, agno);
if (pag) {
ASSERT(atomic_read(&pag->pag_ref) >= 0);
ref = atomic_inc_return(&pag->pag_ref);
}
rcu_read_unlock();
trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
return pag;
}
/*
* search from @first to find the next perag with the given tag set.
*/
struct xfs_perag *
xfs_perag_get_tag(
struct xfs_mount *mp,
xfs_agnumber_t first,
int tag)
{
struct xfs_perag *pag;
int found;
int ref;
rcu_read_lock();
found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
(void **)&pag, first, 1, tag);
if (found <= 0) {
rcu_read_unlock();
return NULL;
}
ref = atomic_inc_return(&pag->pag_ref);
rcu_read_unlock();
trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_);
return pag;
}
void
xfs_perag_put(
struct xfs_perag *pag)
{
int ref;
ASSERT(atomic_read(&pag->pag_ref) > 0);
ref = atomic_dec_return(&pag->pag_ref);
trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
}
/*
* xfs_initialize_perag_data
*
* Read in each per-ag structure so we can count up the number of
* allocated inodes, free inodes and used filesystem blocks as this
* information is no longer persistent in the superblock. Once we have
* this information, write it into the in-core superblock structure.
*/
int
xfs_initialize_perag_data(
struct xfs_mount *mp,
xfs_agnumber_t agcount)
{
xfs_agnumber_t index;
struct xfs_perag *pag;
struct xfs_sb *sbp = &mp->m_sb;
uint64_t ifree = 0;
uint64_t ialloc = 0;
uint64_t bfree = 0;
uint64_t bfreelst = 0;
uint64_t btree = 0;
uint64_t fdblocks;
int error = 0;
for (index = 0; index < agcount; index++) {
/*
* read the agf, then the agi. This gets us
* all the information we need and populates the
* per-ag structures for us.
*/
error = xfs_alloc_pagf_init(mp, NULL, index, 0);
if (error)
return error;
error = xfs_ialloc_pagi_init(mp, NULL, index);
if (error)
return error;
pag = xfs_perag_get(mp, index);
ifree += pag->pagi_freecount;
ialloc += pag->pagi_count;
bfree += pag->pagf_freeblks;
bfreelst += pag->pagf_flcount;
btree += pag->pagf_btreeblks;
xfs_perag_put(pag);
}
fdblocks = bfree + bfreelst + btree;
/*
* If the new summary counts are obviously incorrect, fail the
* mount operation because that implies the AGFs are also corrupt.
* Clear FS_COUNTERS so that we don't unmount with a dirty log, which
* will prevent xfs_repair from fixing anything.
*/
if (fdblocks > sbp->sb_dblocks || ifree > ialloc) {
xfs_alert(mp, "AGF corruption. Please run xfs_repair.");
error = -EFSCORRUPTED;
goto out;
}
/* Overwrite incore superblock counters with just-read data */
spin_lock(&mp->m_sb_lock);
sbp->sb_ifree = ifree;
sbp->sb_icount = ialloc;
sbp->sb_fdblocks = fdblocks;
spin_unlock(&mp->m_sb_lock);
xfs_reinit_percpu_counters(mp);
out:
xfs_fs_mark_healthy(mp, XFS_SICK_FS_COUNTERS);
return error;
}
STATIC void
__xfs_free_perag(
struct rcu_head *head)
{
struct xfs_perag *pag = container_of(head, struct xfs_perag, rcu_head);
ASSERT(!delayed_work_pending(&pag->pag_blockgc_work));
ASSERT(atomic_read(&pag->pag_ref) == 0);
kmem_free(pag);
}
/*
* Free up the per-ag resources associated with the mount structure.
*/
void
xfs_free_perag(
struct xfs_mount *mp)
{
struct xfs_perag *pag;
xfs_agnumber_t agno;
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
spin_lock(&mp->m_perag_lock);
pag = radix_tree_delete(&mp->m_perag_tree, agno);
spin_unlock(&mp->m_perag_lock);
ASSERT(pag);
ASSERT(atomic_read(&pag->pag_ref) == 0);
cancel_delayed_work_sync(&pag->pag_blockgc_work);
xfs_iunlink_destroy(pag);
xfs_buf_hash_destroy(pag);
call_rcu(&pag->rcu_head, __xfs_free_perag);
}
}
int
xfs_initialize_perag(
struct xfs_mount *mp,
xfs_agnumber_t agcount,
xfs_agnumber_t *maxagi)
{
struct xfs_perag *pag;
xfs_agnumber_t index;
xfs_agnumber_t first_initialised = NULLAGNUMBER;
int error;
/*
* Walk the current per-ag tree so we don't try to initialise AGs
* that already exist (growfs case). Allocate and insert all the
* AGs we don't find ready for initialisation.
*/
for (index = 0; index < agcount; index++) {
pag = xfs_perag_get(mp, index);
if (pag) {
xfs_perag_put(pag);
continue;
}
pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL);
if (!pag) {
error = -ENOMEM;
goto out_unwind_new_pags;
}
pag->pag_agno = index;
pag->pag_mount = mp;
error = radix_tree_preload(GFP_NOFS);
if (error)
goto out_free_pag;
spin_lock(&mp->m_perag_lock);
if (radix_tree_insert(&mp->m_perag_tree, index, pag)) {
WARN_ON_ONCE(1);
spin_unlock(&mp->m_perag_lock);
radix_tree_preload_end();
error = -EEXIST;
goto out_free_pag;
}
spin_unlock(&mp->m_perag_lock);
radix_tree_preload_end();
/* Place kernel structure only init below this point. */
spin_lock_init(&pag->pag_ici_lock);
spin_lock_init(&pag->pagb_lock);
spin_lock_init(&pag->pag_state_lock);
INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
init_waitqueue_head(&pag->pagb_wait);
pag->pagb_count = 0;
pag->pagb_tree = RB_ROOT;
error = xfs_buf_hash_init(pag);
if (error)
goto out_remove_pag;
error = xfs_iunlink_init(pag);
if (error)
goto out_hash_destroy;
/* first new pag is fully initialized */
if (first_initialised == NULLAGNUMBER)
first_initialised = index;
}
index = xfs_set_inode_alloc(mp, agcount);
if (maxagi)
*maxagi = index;
mp->m_ag_prealloc_blocks = xfs_prealloc_blocks(mp);
return 0;
out_hash_destroy:
xfs_buf_hash_destroy(pag);
out_remove_pag:
radix_tree_delete(&mp->m_perag_tree, index);
out_free_pag:
kmem_free(pag);
out_unwind_new_pags:
/* unwind any prior newly initialized pags */
for (index = first_initialised; index < agcount; index++) {
pag = radix_tree_delete(&mp->m_perag_tree, index);
if (!pag)
break;
xfs_buf_hash_destroy(pag);
xfs_iunlink_destroy(pag);
kmem_free(pag);
}
return error;
}
static int static int
xfs_get_aghdr_buf( xfs_get_aghdr_buf(
...@@ -645,7 +915,7 @@ xfs_ag_extend_space( ...@@ -645,7 +915,7 @@ xfs_ag_extend_space(
* XFS_RMAP_OINFO_SKIP_UPDATE is used here to tell the rmap btree that * XFS_RMAP_OINFO_SKIP_UPDATE is used here to tell the rmap btree that
* this doesn't actually exist in the rmap btree. * this doesn't actually exist in the rmap btree.
*/ */
error = xfs_rmap_free(tp, bp, id->agno, error = xfs_rmap_free(tp, bp, bp->b_pag,
be32_to_cpu(agf->agf_length) - len, be32_to_cpu(agf->agf_length) - len,
len, &XFS_RMAP_OINFO_SKIP_UPDATE); len, &XFS_RMAP_OINFO_SKIP_UPDATE);
if (error) if (error)
......
...@@ -9,6 +9,142 @@ ...@@ -9,6 +9,142 @@
struct xfs_mount; struct xfs_mount;
struct xfs_trans; struct xfs_trans;
struct xfs_perag;
/*
* Per-ag infrastructure
*/
/* per-AG block reservation data structures*/
struct xfs_ag_resv {
/* number of blocks originally reserved here */
xfs_extlen_t ar_orig_reserved;
/* number of blocks reserved here */
xfs_extlen_t ar_reserved;
/* number of blocks originally asked for */
xfs_extlen_t ar_asked;
};
/*
* Per-ag incore structure, copies of information in agf and agi, to improve the
* performance of allocation group selection.
*/
struct xfs_perag {
struct xfs_mount *pag_mount; /* owner filesystem */
xfs_agnumber_t pag_agno; /* AG this structure belongs to */
atomic_t pag_ref; /* perag reference count */
char pagf_init; /* this agf's entry is initialized */
char pagi_init; /* this agi's entry is initialized */
char pagf_metadata; /* the agf is preferred to be metadata */
char pagi_inodeok; /* The agi is ok for inodes */
uint8_t pagf_levels[XFS_BTNUM_AGF];
/* # of levels in bno & cnt btree */
bool pagf_agflreset; /* agfl requires reset before use */
uint32_t pagf_flcount; /* count of blocks in freelist */
xfs_extlen_t pagf_freeblks; /* total free blocks */
xfs_extlen_t pagf_longest; /* longest free space */
uint32_t pagf_btreeblks; /* # of blocks held in AGF btrees */
xfs_agino_t pagi_freecount; /* number of free inodes */
xfs_agino_t pagi_count; /* number of allocated inodes */
/*
* Inode allocation search lookup optimisation.
* If the pagino matches, the search for new inodes
* doesn't need to search the near ones again straight away
*/
xfs_agino_t pagl_pagino;
xfs_agino_t pagl_leftrec;
xfs_agino_t pagl_rightrec;
int pagb_count; /* pagb slots in use */
uint8_t pagf_refcount_level; /* recount btree height */
/* Blocks reserved for all kinds of metadata. */
struct xfs_ag_resv pag_meta_resv;
/* Blocks reserved for the reverse mapping btree. */
struct xfs_ag_resv pag_rmapbt_resv;
/* -- kernel only structures below this line -- */
/*
* Bitsets of per-ag metadata that have been checked and/or are sick.
* Callers should hold pag_state_lock before accessing this field.
*/
uint16_t pag_checked;
uint16_t pag_sick;
spinlock_t pag_state_lock;
spinlock_t pagb_lock; /* lock for pagb_tree */
struct rb_root pagb_tree; /* ordered tree of busy extents */
unsigned int pagb_gen; /* generation count for pagb_tree */
wait_queue_head_t pagb_wait; /* woken when pagb_gen changes */
atomic_t pagf_fstrms; /* # of filestreams active in this AG */
spinlock_t pag_ici_lock; /* incore inode cache lock */
struct radix_tree_root pag_ici_root; /* incore inode cache root */
int pag_ici_reclaimable; /* reclaimable inodes */
unsigned long pag_ici_reclaim_cursor; /* reclaim restart point */
/* buffer cache index */
spinlock_t pag_buf_lock; /* lock for pag_buf_hash */
struct rhashtable pag_buf_hash;
/* for rcu-safe freeing */
struct rcu_head rcu_head;
/* background prealloc block trimming */
struct delayed_work pag_blockgc_work;
/*
* Unlinked inode information. This incore information reflects
* data stored in the AGI, so callers must hold the AGI buffer lock
* or have some other means to control concurrency.
*/
struct rhashtable pagi_unlinked_hash;
};
int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t agcount,
xfs_agnumber_t *maxagi);
int xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
void xfs_free_perag(struct xfs_mount *mp);
struct xfs_perag *xfs_perag_get(struct xfs_mount *, xfs_agnumber_t);
struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t,
int tag);
void xfs_perag_put(struct xfs_perag *pag);
/*
* Perag iteration APIs
*
* XXX: for_each_perag_range() usage really needs an iterator to clean up when
* we terminate at end_agno because we may have taken a reference to the perag
* beyond end_agno. Right now callers have to be careful to catch and clean that
* up themselves. This is not necessary for the callers of for_each_perag() and
* for_each_perag_from() because they terminate at sb_agcount where there are
* no perag structures in tree beyond end_agno.
*/
#define for_each_perag_range(mp, next_agno, end_agno, pag) \
for ((pag) = xfs_perag_get((mp), (next_agno)); \
(pag) != NULL && (next_agno) <= (end_agno); \
(next_agno) = (pag)->pag_agno + 1, \
xfs_perag_put(pag), \
(pag) = xfs_perag_get((mp), (next_agno)))
#define for_each_perag_from(mp, next_agno, pag) \
for_each_perag_range((mp), (next_agno), (mp)->m_sb.sb_agcount, (pag))
#define for_each_perag(mp, agno, pag) \
(agno) = 0; \
for_each_perag_from((mp), (agno), (pag))
#define for_each_perag_tag(mp, agno, pag, tag) \
for ((agno) = 0, (pag) = xfs_perag_get_tag((mp), 0, (tag)); \
(pag) != NULL; \
(agno) = (pag)->pag_agno + 1, \
xfs_perag_put(pag), \
(pag) = xfs_perag_get_tag((mp), (agno), (tag)))
struct aghdr_init_data { struct aghdr_init_data {
/* per ag data */ /* per ag data */
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include "xfs_btree.h" #include "xfs_btree.h"
#include "xfs_refcount_btree.h" #include "xfs_refcount_btree.h"
#include "xfs_ialloc_btree.h" #include "xfs_ialloc_btree.h"
#include "xfs_sb.h" #include "xfs_ag.h"
#include "xfs_ag_resv.h" #include "xfs_ag_resv.h"
/* /*
...@@ -250,7 +250,6 @@ xfs_ag_resv_init( ...@@ -250,7 +250,6 @@ xfs_ag_resv_init(
struct xfs_trans *tp) struct xfs_trans *tp)
{ {
struct xfs_mount *mp = pag->pag_mount; struct xfs_mount *mp = pag->pag_mount;
xfs_agnumber_t agno = pag->pag_agno;
xfs_extlen_t ask; xfs_extlen_t ask;
xfs_extlen_t used; xfs_extlen_t used;
int error = 0, error2; int error = 0, error2;
...@@ -260,11 +259,11 @@ xfs_ag_resv_init( ...@@ -260,11 +259,11 @@ xfs_ag_resv_init(
if (pag->pag_meta_resv.ar_asked == 0) { if (pag->pag_meta_resv.ar_asked == 0) {
ask = used = 0; ask = used = 0;
error = xfs_refcountbt_calc_reserves(mp, tp, agno, &ask, &used); error = xfs_refcountbt_calc_reserves(mp, tp, pag, &ask, &used);
if (error) if (error)
goto out; goto out;
error = xfs_finobt_calc_reserves(mp, tp, agno, &ask, &used); error = xfs_finobt_calc_reserves(mp, tp, pag, &ask, &used);
if (error) if (error)
goto out; goto out;
...@@ -282,7 +281,7 @@ xfs_ag_resv_init( ...@@ -282,7 +281,7 @@ xfs_ag_resv_init(
mp->m_finobt_nores = true; mp->m_finobt_nores = true;
error = xfs_refcountbt_calc_reserves(mp, tp, agno, &ask, error = xfs_refcountbt_calc_reserves(mp, tp, pag, &ask,
&used); &used);
if (error) if (error)
goto out; goto out;
...@@ -300,7 +299,7 @@ xfs_ag_resv_init( ...@@ -300,7 +299,7 @@ xfs_ag_resv_init(
if (pag->pag_rmapbt_resv.ar_asked == 0) { if (pag->pag_rmapbt_resv.ar_asked == 0) {
ask = used = 0; ask = used = 0;
error = xfs_rmapbt_calc_reserves(mp, tp, agno, &ask, &used); error = xfs_rmapbt_calc_reserves(mp, tp, pag, &ask, &used);
if (error) if (error)
goto out; goto out;
......
...@@ -18,6 +18,21 @@ void xfs_ag_resv_alloc_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type, ...@@ -18,6 +18,21 @@ void xfs_ag_resv_alloc_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type,
void xfs_ag_resv_free_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type, void xfs_ag_resv_free_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type,
struct xfs_trans *tp, xfs_extlen_t len); struct xfs_trans *tp, xfs_extlen_t len);
static inline struct xfs_ag_resv *
xfs_perag_resv(
struct xfs_perag *pag,
enum xfs_ag_resv_type type)
{
switch (type) {
case XFS_AG_RESV_METADATA:
return &pag->pag_meta_resv;
case XFS_AG_RESV_RMAPBT:
return &pag->pag_rmapbt_resv;
default:
return NULL;
}
}
/* /*
* RMAPBT reservation accounting wrappers. Since rmapbt blocks are sourced from * RMAPBT reservation accounting wrappers. Since rmapbt blocks are sourced from
* the AGFL, they are allocated one at a time and the reservation updates don't * the AGFL, they are allocated one at a time and the reservation updates don't
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include "xfs_shared.h" #include "xfs_shared.h"
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_bit.h" #include "xfs_bit.h"
#include "xfs_sb.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_defer.h" #include "xfs_defer.h"
#include "xfs_btree.h" #include "xfs_btree.h"
...@@ -24,6 +23,7 @@ ...@@ -24,6 +23,7 @@
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_buf_item.h" #include "xfs_buf_item.h"
#include "xfs_log.h" #include "xfs_log.h"
#include "xfs_ag.h"
#include "xfs_ag_resv.h" #include "xfs_ag_resv.h"
#include "xfs_bmap.h" #include "xfs_bmap.h"
...@@ -230,7 +230,7 @@ xfs_alloc_get_rec( ...@@ -230,7 +230,7 @@ xfs_alloc_get_rec(
int *stat) /* output: success/failure */ int *stat) /* output: success/failure */
{ {
struct xfs_mount *mp = cur->bc_mp; struct xfs_mount *mp = cur->bc_mp;
xfs_agnumber_t agno = cur->bc_ag.agno; xfs_agnumber_t agno = cur->bc_ag.pag->pag_agno;
union xfs_btree_rec *rec; union xfs_btree_rec *rec;
int error; int error;
...@@ -776,7 +776,7 @@ xfs_alloc_cur_setup( ...@@ -776,7 +776,7 @@ xfs_alloc_cur_setup(
*/ */
if (!acur->cnt) if (!acur->cnt)
acur->cnt = xfs_allocbt_init_cursor(args->mp, args->tp, acur->cnt = xfs_allocbt_init_cursor(args->mp, args->tp,
args->agbp, args->agno, XFS_BTNUM_CNT); args->agbp, args->pag, XFS_BTNUM_CNT);
error = xfs_alloc_lookup_ge(acur->cnt, 0, args->maxlen, &i); error = xfs_alloc_lookup_ge(acur->cnt, 0, args->maxlen, &i);
if (error) if (error)
return error; return error;
...@@ -786,10 +786,10 @@ xfs_alloc_cur_setup( ...@@ -786,10 +786,10 @@ xfs_alloc_cur_setup(
*/ */
if (!acur->bnolt) if (!acur->bnolt)
acur->bnolt = xfs_allocbt_init_cursor(args->mp, args->tp, acur->bnolt = xfs_allocbt_init_cursor(args->mp, args->tp,
args->agbp, args->agno, XFS_BTNUM_BNO); args->agbp, args->pag, XFS_BTNUM_BNO);
if (!acur->bnogt) if (!acur->bnogt)
acur->bnogt = xfs_allocbt_init_cursor(args->mp, args->tp, acur->bnogt = xfs_allocbt_init_cursor(args->mp, args->tp,
args->agbp, args->agno, XFS_BTNUM_BNO); args->agbp, args->pag, XFS_BTNUM_BNO);
return i == 1 ? 0 : -ENOSPC; return i == 1 ? 0 : -ENOSPC;
} }
...@@ -1063,7 +1063,7 @@ xfs_alloc_ag_vextent_small( ...@@ -1063,7 +1063,7 @@ xfs_alloc_ag_vextent_small(
if (fbno == NULLAGBLOCK) if (fbno == NULLAGBLOCK)
goto out; goto out;
xfs_extent_busy_reuse(args->mp, args->agno, fbno, 1, xfs_extent_busy_reuse(args->mp, args->pag, fbno, 1,
(args->datatype & XFS_ALLOC_NOBUSY)); (args->datatype & XFS_ALLOC_NOBUSY));
if (args->datatype & XFS_ALLOC_USERDATA) { if (args->datatype & XFS_ALLOC_USERDATA) {
...@@ -1089,7 +1089,7 @@ xfs_alloc_ag_vextent_small( ...@@ -1089,7 +1089,7 @@ xfs_alloc_ag_vextent_small(
* If we're feeding an AGFL block to something that doesn't live in the * If we're feeding an AGFL block to something that doesn't live in the
* free space, we need to clear out the OWN_AG rmap. * free space, we need to clear out the OWN_AG rmap.
*/ */
error = xfs_rmap_free(args->tp, args->agbp, args->agno, fbno, 1, error = xfs_rmap_free(args->tp, args->agbp, args->pag, fbno, 1,
&XFS_RMAP_OINFO_AG); &XFS_RMAP_OINFO_AG);
if (error) if (error)
goto error; goto error;
...@@ -1166,7 +1166,7 @@ xfs_alloc_ag_vextent( ...@@ -1166,7 +1166,7 @@ xfs_alloc_ag_vextent(
/* if not file data, insert new block into the reverse map btree */ /* if not file data, insert new block into the reverse map btree */
if (!xfs_rmap_should_skip_owner_update(&args->oinfo)) { if (!xfs_rmap_should_skip_owner_update(&args->oinfo)) {
error = xfs_rmap_alloc(args->tp, args->agbp, args->agno, error = xfs_rmap_alloc(args->tp, args->agbp, args->pag,
args->agbno, args->len, &args->oinfo); args->agbno, args->len, &args->oinfo);
if (error) if (error)
return error; return error;
...@@ -1178,7 +1178,7 @@ xfs_alloc_ag_vextent( ...@@ -1178,7 +1178,7 @@ xfs_alloc_ag_vextent(
if (error) if (error)
return error; return error;
ASSERT(!xfs_extent_busy_search(args->mp, args->agno, ASSERT(!xfs_extent_busy_search(args->mp, args->pag,
args->agbno, args->len)); args->agbno, args->len));
} }
...@@ -1217,7 +1217,7 @@ xfs_alloc_ag_vextent_exact( ...@@ -1217,7 +1217,7 @@ xfs_alloc_ag_vextent_exact(
* Allocate/initialize a cursor for the by-number freespace btree. * Allocate/initialize a cursor for the by-number freespace btree.
*/ */
bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_BNO); args->pag, XFS_BTNUM_BNO);
/* /*
* Lookup bno and minlen in the btree (minlen is irrelevant, really). * Lookup bno and minlen in the btree (minlen is irrelevant, really).
...@@ -1277,7 +1277,7 @@ xfs_alloc_ag_vextent_exact( ...@@ -1277,7 +1277,7 @@ xfs_alloc_ag_vextent_exact(
* Allocate/initialize a cursor for the by-size btree. * Allocate/initialize a cursor for the by-size btree.
*/ */
cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_CNT); args->pag, XFS_BTNUM_CNT);
ASSERT(args->agbno + args->len <= be32_to_cpu(agf->agf_length)); ASSERT(args->agbno + args->len <= be32_to_cpu(agf->agf_length));
error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, args->agbno, error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, args->agbno,
args->len, XFSA_FIXUP_BNO_OK); args->len, XFSA_FIXUP_BNO_OK);
...@@ -1674,7 +1674,7 @@ xfs_alloc_ag_vextent_size( ...@@ -1674,7 +1674,7 @@ xfs_alloc_ag_vextent_size(
* Allocate and initialize a cursor for the by-size btree. * Allocate and initialize a cursor for the by-size btree.
*/ */
cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_CNT); args->pag, XFS_BTNUM_CNT);
bno_cur = NULL; bno_cur = NULL;
busy = false; busy = false;
...@@ -1837,7 +1837,7 @@ xfs_alloc_ag_vextent_size( ...@@ -1837,7 +1837,7 @@ xfs_alloc_ag_vextent_size(
* Allocate and initialize a cursor for the by-block tree. * Allocate and initialize a cursor for the by-block tree.
*/ */
bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
args->agno, XFS_BTNUM_BNO); args->pag, XFS_BTNUM_BNO);
if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen,
rbno, rlen, XFSA_FIXUP_CNT_OK))) rbno, rlen, XFSA_FIXUP_CNT_OK)))
goto error0; goto error0;
...@@ -1896,12 +1896,13 @@ xfs_free_ag_extent( ...@@ -1896,12 +1896,13 @@ xfs_free_ag_extent(
int haveright; /* have a right neighbor */ int haveright; /* have a right neighbor */
int i; int i;
int error; int error;
struct xfs_perag *pag = agbp->b_pag;
bno_cur = cnt_cur = NULL; bno_cur = cnt_cur = NULL;
mp = tp->t_mountp; mp = tp->t_mountp;
if (!xfs_rmap_should_skip_owner_update(oinfo)) { if (!xfs_rmap_should_skip_owner_update(oinfo)) {
error = xfs_rmap_free(tp, agbp, agno, bno, len, oinfo); error = xfs_rmap_free(tp, agbp, pag, bno, len, oinfo);
if (error) if (error)
goto error0; goto error0;
} }
...@@ -1909,7 +1910,7 @@ xfs_free_ag_extent( ...@@ -1909,7 +1910,7 @@ xfs_free_ag_extent(
/* /*
* Allocate and initialize a cursor for the by-block btree. * Allocate and initialize a cursor for the by-block btree.
*/ */
bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO); bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_BNO);
/* /*
* Look for a neighboring block on the left (lower block numbers) * Look for a neighboring block on the left (lower block numbers)
* that is contiguous with this space. * that is contiguous with this space.
...@@ -1979,7 +1980,7 @@ xfs_free_ag_extent( ...@@ -1979,7 +1980,7 @@ xfs_free_ag_extent(
/* /*
* Now allocate and initialize a cursor for the by-size tree. * Now allocate and initialize a cursor for the by-size tree.
*/ */
cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT); cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_CNT);
/* /*
* Have both left and right contiguous neighbors. * Have both left and right contiguous neighbors.
* Merge all three into a single free block. * Merge all three into a single free block.
...@@ -2490,7 +2491,7 @@ xfs_exact_minlen_extent_available( ...@@ -2490,7 +2491,7 @@ xfs_exact_minlen_extent_available(
int error = 0; int error = 0;
cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, agbp, cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, agbp,
args->agno, XFS_BTNUM_CNT); args->pag, XFS_BTNUM_CNT);
error = xfs_alloc_lookup_ge(cnt_cur, 0, args->minlen, stat); error = xfs_alloc_lookup_ge(cnt_cur, 0, args->minlen, stat);
if (error) if (error)
goto out; goto out;
...@@ -2693,21 +2694,21 @@ xfs_alloc_fix_freelist( ...@@ -2693,21 +2694,21 @@ xfs_alloc_fix_freelist(
* Get a block from the freelist. * Get a block from the freelist.
* Returns with the buffer for the block gotten. * Returns with the buffer for the block gotten.
*/ */
int /* error */ int
xfs_alloc_get_freelist( xfs_alloc_get_freelist(
xfs_trans_t *tp, /* transaction pointer */ struct xfs_trans *tp,
struct xfs_buf *agbp, /* buffer containing the agf structure */ struct xfs_buf *agbp,
xfs_agblock_t *bnop, /* block address retrieved from freelist */ xfs_agblock_t *bnop,
int btreeblk) /* destination is a AGF btree */ int btreeblk)
{ {
struct xfs_agf *agf = agbp->b_addr; struct xfs_agf *agf = agbp->b_addr;
struct xfs_buf *agflbp;/* buffer for a.g. freelist structure */ struct xfs_buf *agflbp;
xfs_agblock_t bno; /* block number returned */ xfs_agblock_t bno;
__be32 *agfl_bno; __be32 *agfl_bno;
int error; int error;
int logflags; int logflags;
xfs_mount_t *mp = tp->t_mountp; struct xfs_mount *mp = tp->t_mountp;
xfs_perag_t *pag; /* per allocation group data */ struct xfs_perag *pag;
/* /*
* Freelist is empty, give up. * Freelist is empty, give up.
...@@ -2817,20 +2818,20 @@ xfs_alloc_pagf_init( ...@@ -2817,20 +2818,20 @@ xfs_alloc_pagf_init(
/* /*
* Put the block on the freelist for the allocation group. * Put the block on the freelist for the allocation group.
*/ */
int /* error */ int
xfs_alloc_put_freelist( xfs_alloc_put_freelist(
xfs_trans_t *tp, /* transaction pointer */ struct xfs_trans *tp,
struct xfs_buf *agbp, /* buffer for a.g. freelist header */ struct xfs_buf *agbp,
struct xfs_buf *agflbp,/* buffer for a.g. free block array */ struct xfs_buf *agflbp,
xfs_agblock_t bno, /* block being freed */ xfs_agblock_t bno,
int btreeblk) /* block came from a AGF btree */ int btreeblk)
{ {
struct xfs_mount *mp = tp->t_mountp; struct xfs_mount *mp = tp->t_mountp;
struct xfs_agf *agf = agbp->b_addr; struct xfs_agf *agf = agbp->b_addr;
__be32 *blockp;/* pointer to array entry */ struct xfs_perag *pag;
__be32 *blockp;
int error; int error;
int logflags; int logflags;
xfs_perag_t *pag; /* per allocation group data */
__be32 *agfl_bno; __be32 *agfl_bno;
int startoff; int startoff;
...@@ -3292,7 +3293,7 @@ xfs_alloc_vextent( ...@@ -3292,7 +3293,7 @@ xfs_alloc_vextent(
int int
xfs_free_extent_fix_freelist( xfs_free_extent_fix_freelist(
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno, struct xfs_perag *pag,
struct xfs_buf **agbp) struct xfs_buf **agbp)
{ {
struct xfs_alloc_arg args; struct xfs_alloc_arg args;
...@@ -3301,7 +3302,8 @@ xfs_free_extent_fix_freelist( ...@@ -3301,7 +3302,8 @@ xfs_free_extent_fix_freelist(
memset(&args, 0, sizeof(struct xfs_alloc_arg)); memset(&args, 0, sizeof(struct xfs_alloc_arg));
args.tp = tp; args.tp = tp;
args.mp = tp->t_mountp; args.mp = tp->t_mountp;
args.agno = agno; args.agno = pag->pag_agno;
args.pag = pag;
/* /*
* validate that the block number is legal - the enables us to detect * validate that the block number is legal - the enables us to detect
...@@ -3310,17 +3312,12 @@ xfs_free_extent_fix_freelist( ...@@ -3310,17 +3312,12 @@ xfs_free_extent_fix_freelist(
if (args.agno >= args.mp->m_sb.sb_agcount) if (args.agno >= args.mp->m_sb.sb_agcount)
return -EFSCORRUPTED; return -EFSCORRUPTED;
args.pag = xfs_perag_get(args.mp, args.agno);
ASSERT(args.pag);
error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING); error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING);
if (error) if (error)
goto out; return error;
*agbp = args.agbp; *agbp = args.agbp;
out: return 0;
xfs_perag_put(args.pag);
return error;
} }
/* /*
...@@ -3344,6 +3341,7 @@ __xfs_free_extent( ...@@ -3344,6 +3341,7 @@ __xfs_free_extent(
struct xfs_agf *agf; struct xfs_agf *agf;
int error; int error;
unsigned int busy_flags = 0; unsigned int busy_flags = 0;
struct xfs_perag *pag;
ASSERT(len != 0); ASSERT(len != 0);
ASSERT(type != XFS_AG_RESV_AGFL); ASSERT(type != XFS_AG_RESV_AGFL);
...@@ -3352,33 +3350,37 @@ __xfs_free_extent( ...@@ -3352,33 +3350,37 @@ __xfs_free_extent(
XFS_ERRTAG_FREE_EXTENT)) XFS_ERRTAG_FREE_EXTENT))
return -EIO; return -EIO;
error = xfs_free_extent_fix_freelist(tp, agno, &agbp); pag = xfs_perag_get(mp, agno);
error = xfs_free_extent_fix_freelist(tp, pag, &agbp);
if (error) if (error)
return error; goto err;
agf = agbp->b_addr; agf = agbp->b_addr;
if (XFS_IS_CORRUPT(mp, agbno >= mp->m_sb.sb_agblocks)) { if (XFS_IS_CORRUPT(mp, agbno >= mp->m_sb.sb_agblocks)) {
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
goto err; goto err_release;
} }
/* validate the extent size is legal now we have the agf locked */ /* validate the extent size is legal now we have the agf locked */
if (XFS_IS_CORRUPT(mp, agbno + len > be32_to_cpu(agf->agf_length))) { if (XFS_IS_CORRUPT(mp, agbno + len > be32_to_cpu(agf->agf_length))) {
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
goto err; goto err_release;
} }
error = xfs_free_ag_extent(tp, agbp, agno, agbno, len, oinfo, type); error = xfs_free_ag_extent(tp, agbp, agno, agbno, len, oinfo, type);
if (error) if (error)
goto err; goto err_release;
if (skip_discard) if (skip_discard)
busy_flags |= XFS_EXTENT_BUSY_SKIP_DISCARD; busy_flags |= XFS_EXTENT_BUSY_SKIP_DISCARD;
xfs_extent_busy_insert(tp, agno, agbno, len, busy_flags); xfs_extent_busy_insert(tp, pag, agbno, len, busy_flags);
xfs_perag_put(pag);
return 0; return 0;
err: err_release:
xfs_trans_brelse(tp, agbp); xfs_trans_brelse(tp, agbp);
err:
xfs_perag_put(pag);
return error; return error;
} }
......
...@@ -214,7 +214,7 @@ int xfs_alloc_read_agfl(struct xfs_mount *mp, struct xfs_trans *tp, ...@@ -214,7 +214,7 @@ int xfs_alloc_read_agfl(struct xfs_mount *mp, struct xfs_trans *tp,
int xfs_free_agfl_block(struct xfs_trans *, xfs_agnumber_t, xfs_agblock_t, int xfs_free_agfl_block(struct xfs_trans *, xfs_agnumber_t, xfs_agblock_t,
struct xfs_buf *, struct xfs_owner_info *); struct xfs_buf *, struct xfs_owner_info *);
int xfs_alloc_fix_freelist(struct xfs_alloc_arg *args, int flags); int xfs_alloc_fix_freelist(struct xfs_alloc_arg *args, int flags);
int xfs_free_extent_fix_freelist(struct xfs_trans *tp, xfs_agnumber_t agno, int xfs_free_extent_fix_freelist(struct xfs_trans *tp, struct xfs_perag *pag,
struct xfs_buf **agbp); struct xfs_buf **agbp);
xfs_extlen_t xfs_prealloc_blocks(struct xfs_mount *mp); xfs_extlen_t xfs_prealloc_blocks(struct xfs_mount *mp);
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include "xfs_format.h" #include "xfs_format.h"
#include "xfs_log_format.h" #include "xfs_log_format.h"
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_sb.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_btree.h" #include "xfs_btree.h"
#include "xfs_btree_staging.h" #include "xfs_btree_staging.h"
...@@ -19,6 +18,7 @@ ...@@ -19,6 +18,7 @@
#include "xfs_error.h" #include "xfs_error.h"
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_ag.h"
STATIC struct xfs_btree_cur * STATIC struct xfs_btree_cur *
...@@ -26,8 +26,7 @@ xfs_allocbt_dup_cursor( ...@@ -26,8 +26,7 @@ xfs_allocbt_dup_cursor(
struct xfs_btree_cur *cur) struct xfs_btree_cur *cur)
{ {
return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp, return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp,
cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.agbp, cur->bc_ag.pag, cur->bc_btnum);
cur->bc_btnum);
} }
STATIC void STATIC void
...@@ -39,13 +38,12 @@ xfs_allocbt_set_root( ...@@ -39,13 +38,12 @@ xfs_allocbt_set_root(
struct xfs_buf *agbp = cur->bc_ag.agbp; struct xfs_buf *agbp = cur->bc_ag.agbp;
struct xfs_agf *agf = agbp->b_addr; struct xfs_agf *agf = agbp->b_addr;
int btnum = cur->bc_btnum; int btnum = cur->bc_btnum;
struct xfs_perag *pag = agbp->b_pag;
ASSERT(ptr->s != 0); ASSERT(ptr->s != 0);
agf->agf_roots[btnum] = ptr->s; agf->agf_roots[btnum] = ptr->s;
be32_add_cpu(&agf->agf_levels[btnum], inc); be32_add_cpu(&agf->agf_levels[btnum], inc);
pag->pagf_levels[btnum] += inc; cur->bc_ag.pag->pagf_levels[btnum] += inc;
xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
} }
...@@ -72,7 +70,7 @@ xfs_allocbt_alloc_block( ...@@ -72,7 +70,7 @@ xfs_allocbt_alloc_block(
} }
atomic64_inc(&cur->bc_mp->m_allocbt_blks); atomic64_inc(&cur->bc_mp->m_allocbt_blks);
xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.agno, bno, 1, false); xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.agbp->b_pag, bno, 1, false);
new->s = cpu_to_be32(bno); new->s = cpu_to_be32(bno);
...@@ -86,7 +84,6 @@ xfs_allocbt_free_block( ...@@ -86,7 +84,6 @@ xfs_allocbt_free_block(
struct xfs_buf *bp) struct xfs_buf *bp)
{ {
struct xfs_buf *agbp = cur->bc_ag.agbp; struct xfs_buf *agbp = cur->bc_ag.agbp;
struct xfs_agf *agf = agbp->b_addr;
xfs_agblock_t bno; xfs_agblock_t bno;
int error; int error;
...@@ -96,7 +93,7 @@ xfs_allocbt_free_block( ...@@ -96,7 +93,7 @@ xfs_allocbt_free_block(
return error; return error;
atomic64_dec(&cur->bc_mp->m_allocbt_blks); atomic64_dec(&cur->bc_mp->m_allocbt_blks);
xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1, xfs_extent_busy_insert(cur->bc_tp, agbp->b_pag, bno, 1,
XFS_EXTENT_BUSY_SKIP_DISCARD); XFS_EXTENT_BUSY_SKIP_DISCARD);
return 0; return 0;
} }
...@@ -225,7 +222,7 @@ xfs_allocbt_init_ptr_from_cur( ...@@ -225,7 +222,7 @@ xfs_allocbt_init_ptr_from_cur(
{ {
struct xfs_agf *agf = cur->bc_ag.agbp->b_addr; struct xfs_agf *agf = cur->bc_ag.agbp->b_addr;
ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno)); ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno));
ptr->s = agf->agf_roots[cur->bc_btnum]; ptr->s = agf->agf_roots[cur->bc_btnum];
} }
...@@ -473,7 +470,7 @@ STATIC struct xfs_btree_cur * ...@@ -473,7 +470,7 @@ STATIC struct xfs_btree_cur *
xfs_allocbt_init_common( xfs_allocbt_init_common(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_btnum_t btnum) xfs_btnum_t btnum)
{ {
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
...@@ -486,6 +483,7 @@ xfs_allocbt_init_common( ...@@ -486,6 +483,7 @@ xfs_allocbt_init_common(
cur->bc_mp = mp; cur->bc_mp = mp;
cur->bc_btnum = btnum; cur->bc_btnum = btnum;
cur->bc_blocklog = mp->m_sb.sb_blocklog; cur->bc_blocklog = mp->m_sb.sb_blocklog;
cur->bc_ag.abt.active = false;
if (btnum == XFS_BTNUM_CNT) { if (btnum == XFS_BTNUM_CNT) {
cur->bc_ops = &xfs_cntbt_ops; cur->bc_ops = &xfs_cntbt_ops;
...@@ -496,8 +494,9 @@ xfs_allocbt_init_common( ...@@ -496,8 +494,9 @@ xfs_allocbt_init_common(
cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtb_2); cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_abtb_2);
} }
cur->bc_ag.agno = agno; /* take a reference for the cursor */
cur->bc_ag.abt.active = false; atomic_inc(&pag->pag_ref);
cur->bc_ag.pag = pag;
if (xfs_sb_version_hascrc(&mp->m_sb)) if (xfs_sb_version_hascrc(&mp->m_sb))
cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
...@@ -513,13 +512,13 @@ xfs_allocbt_init_cursor( ...@@ -513,13 +512,13 @@ xfs_allocbt_init_cursor(
struct xfs_mount *mp, /* file system mount point */ struct xfs_mount *mp, /* file system mount point */
struct xfs_trans *tp, /* transaction pointer */ struct xfs_trans *tp, /* transaction pointer */
struct xfs_buf *agbp, /* buffer for agf structure */ struct xfs_buf *agbp, /* buffer for agf structure */
xfs_agnumber_t agno, /* allocation group number */ struct xfs_perag *pag,
xfs_btnum_t btnum) /* btree identifier */ xfs_btnum_t btnum) /* btree identifier */
{ {
struct xfs_agf *agf = agbp->b_addr; struct xfs_agf *agf = agbp->b_addr;
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
cur = xfs_allocbt_init_common(mp, tp, agno, btnum); cur = xfs_allocbt_init_common(mp, tp, pag, btnum);
if (btnum == XFS_BTNUM_CNT) if (btnum == XFS_BTNUM_CNT)
cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]); cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]);
else else
...@@ -535,12 +534,12 @@ struct xfs_btree_cur * ...@@ -535,12 +534,12 @@ struct xfs_btree_cur *
xfs_allocbt_stage_cursor( xfs_allocbt_stage_cursor(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xbtree_afakeroot *afake, struct xbtree_afakeroot *afake,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_btnum_t btnum) xfs_btnum_t btnum)
{ {
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
cur = xfs_allocbt_init_common(mp, NULL, agno, btnum); cur = xfs_allocbt_init_common(mp, NULL, pag, btnum);
xfs_btree_stage_afakeroot(cur, afake); xfs_btree_stage_afakeroot(cur, afake);
return cur; return cur;
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
struct xfs_buf; struct xfs_buf;
struct xfs_btree_cur; struct xfs_btree_cur;
struct xfs_mount; struct xfs_mount;
struct xfs_perag;
struct xbtree_afakeroot; struct xbtree_afakeroot;
/* /*
...@@ -46,11 +47,11 @@ struct xbtree_afakeroot; ...@@ -46,11 +47,11 @@ struct xbtree_afakeroot;
(maxrecs) * sizeof(xfs_alloc_key_t) + \ (maxrecs) * sizeof(xfs_alloc_key_t) + \
((index) - 1) * sizeof(xfs_alloc_ptr_t))) ((index) - 1) * sizeof(xfs_alloc_ptr_t)))
extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *, extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *mp,
struct xfs_trans *, struct xfs_buf *, struct xfs_trans *tp, struct xfs_buf *bp,
xfs_agnumber_t, xfs_btnum_t); struct xfs_perag *pag, xfs_btnum_t btnum);
struct xfs_btree_cur *xfs_allocbt_stage_cursor(struct xfs_mount *mp, struct xfs_btree_cur *xfs_allocbt_stage_cursor(struct xfs_mount *mp,
struct xbtree_afakeroot *afake, xfs_agnumber_t agno, struct xbtree_afakeroot *afake, struct xfs_perag *pag,
xfs_btnum_t btnum); xfs_btnum_t btnum);
extern int xfs_allocbt_maxrecs(struct xfs_mount *, int, int); extern int xfs_allocbt_maxrecs(struct xfs_mount *, int, int);
extern xfs_extlen_t xfs_allocbt_calc_size(struct xfs_mount *mp, extern xfs_extlen_t xfs_allocbt_calc_size(struct xfs_mount *mp,
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "xfs_buf_item.h" #include "xfs_buf_item.h"
#include "xfs_dir2.h" #include "xfs_dir2.h"
#include "xfs_log.h" #include "xfs_log.h"
#include "xfs_ag.h"
/* /*
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "xfs_attr_leaf.h" #include "xfs_attr_leaf.h"
#include "xfs_filestream.h" #include "xfs_filestream.h"
#include "xfs_rmap.h" #include "xfs_rmap.h"
#include "xfs_ag.h"
#include "xfs_ag_resv.h" #include "xfs_ag_resv.h"
#include "xfs_refcount.h" #include "xfs_refcount.h"
#include "xfs_icache.h" #include "xfs_icache.h"
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "xfs_alloc.h" #include "xfs_alloc.h"
#include "xfs_log.h" #include "xfs_log.h"
#include "xfs_btree_staging.h" #include "xfs_btree_staging.h"
#include "xfs_ag.h"
/* /*
* Cursor allocation zone. * Cursor allocation zone.
...@@ -215,7 +216,7 @@ xfs_btree_check_sptr( ...@@ -215,7 +216,7 @@ xfs_btree_check_sptr(
{ {
if (level <= 0) if (level <= 0)
return false; return false;
return xfs_verify_agbno(cur->bc_mp, cur->bc_ag.agno, agbno); return xfs_verify_agbno(cur->bc_mp, cur->bc_ag.pag->pag_agno, agbno);
} }
/* /*
...@@ -244,7 +245,7 @@ xfs_btree_check_ptr( ...@@ -244,7 +245,7 @@ xfs_btree_check_ptr(
return 0; return 0;
xfs_err(cur->bc_mp, xfs_err(cur->bc_mp,
"AG %u: Corrupt btree %d pointer at level %d index %d.", "AG %u: Corrupt btree %d pointer at level %d index %d.",
cur->bc_ag.agno, cur->bc_btnum, cur->bc_ag.pag->pag_agno, cur->bc_btnum,
level, index); level, index);
} }
...@@ -376,6 +377,8 @@ xfs_btree_del_cursor( ...@@ -376,6 +377,8 @@ xfs_btree_del_cursor(
XFS_FORCED_SHUTDOWN(cur->bc_mp)); XFS_FORCED_SHUTDOWN(cur->bc_mp));
if (unlikely(cur->bc_flags & XFS_BTREE_STAGING)) if (unlikely(cur->bc_flags & XFS_BTREE_STAGING))
kmem_free(cur->bc_ops); kmem_free(cur->bc_ops);
if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS) && cur->bc_ag.pag)
xfs_perag_put(cur->bc_ag.pag);
kmem_cache_free(xfs_btree_cur_zone, cur); kmem_cache_free(xfs_btree_cur_zone, cur);
} }
...@@ -885,13 +888,13 @@ xfs_btree_readahead_sblock( ...@@ -885,13 +888,13 @@ xfs_btree_readahead_sblock(
if ((lr & XFS_BTCUR_LEFTRA) && left != NULLAGBLOCK) { if ((lr & XFS_BTCUR_LEFTRA) && left != NULLAGBLOCK) {
xfs_btree_reada_bufs(cur->bc_mp, cur->bc_ag.agno, xfs_btree_reada_bufs(cur->bc_mp, cur->bc_ag.pag->pag_agno,
left, 1, cur->bc_ops->buf_ops); left, 1, cur->bc_ops->buf_ops);
rval++; rval++;
} }
if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLAGBLOCK) { if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLAGBLOCK) {
xfs_btree_reada_bufs(cur->bc_mp, cur->bc_ag.agno, xfs_btree_reada_bufs(cur->bc_mp, cur->bc_ag.pag->pag_agno,
right, 1, cur->bc_ops->buf_ops); right, 1, cur->bc_ops->buf_ops);
rval++; rval++;
} }
...@@ -949,7 +952,7 @@ xfs_btree_ptr_to_daddr( ...@@ -949,7 +952,7 @@ xfs_btree_ptr_to_daddr(
*daddr = XFS_FSB_TO_DADDR(cur->bc_mp, fsbno); *daddr = XFS_FSB_TO_DADDR(cur->bc_mp, fsbno);
} else { } else {
agbno = be32_to_cpu(ptr->s); agbno = be32_to_cpu(ptr->s);
*daddr = XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_ag.agno, *daddr = XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_ag.pag->pag_agno,
agbno); agbno);
} }
...@@ -1150,7 +1153,7 @@ xfs_btree_init_block_cur( ...@@ -1150,7 +1153,7 @@ xfs_btree_init_block_cur(
if (cur->bc_flags & XFS_BTREE_LONG_PTRS) if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
owner = cur->bc_ino.ip->i_ino; owner = cur->bc_ino.ip->i_ino;
else else
owner = cur->bc_ag.agno; owner = cur->bc_ag.pag->pag_agno;
xfs_btree_init_block_int(cur->bc_mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn, xfs_btree_init_block_int(cur->bc_mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn,
cur->bc_btnum, level, numrecs, cur->bc_btnum, level, numrecs,
......
...@@ -11,6 +11,7 @@ struct xfs_inode; ...@@ -11,6 +11,7 @@ struct xfs_inode;
struct xfs_mount; struct xfs_mount;
struct xfs_trans; struct xfs_trans;
struct xfs_ifork; struct xfs_ifork;
struct xfs_perag;
extern kmem_zone_t *xfs_btree_cur_zone; extern kmem_zone_t *xfs_btree_cur_zone;
...@@ -180,11 +181,11 @@ union xfs_btree_irec { ...@@ -180,11 +181,11 @@ union xfs_btree_irec {
/* Per-AG btree information. */ /* Per-AG btree information. */
struct xfs_btree_cur_ag { struct xfs_btree_cur_ag {
struct xfs_perag *pag;
union { union {
struct xfs_buf *agbp; struct xfs_buf *agbp;
struct xbtree_afakeroot *afake; /* for staging cursor */ struct xbtree_afakeroot *afake; /* for staging cursor */
}; };
xfs_agnumber_t agno;
union { union {
struct { struct {
unsigned long nr_ops; /* # record updates */ unsigned long nr_ops; /* # record updates */
...@@ -231,6 +232,13 @@ typedef struct xfs_btree_cur ...@@ -231,6 +232,13 @@ typedef struct xfs_btree_cur
uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */ uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */
xfs_btnum_t bc_btnum; /* identifies which btree type */ xfs_btnum_t bc_btnum; /* identifies which btree type */
int bc_statoff; /* offset of btre stats array */ int bc_statoff; /* offset of btre stats array */
/*
* Short btree pointers need an agno to be able to turn the pointers
* into physical addresses for IO, so the btree cursor switches between
* bc_ino and bc_ag based on whether XFS_BTREE_LONG_PTRS is set for the
* cursor.
*/
union { union {
struct xfs_btree_cur_ag bc_ag; struct xfs_btree_cur_ag bc_ag;
struct xfs_btree_cur_ino bc_ino; struct xfs_btree_cur_ino bc_ino;
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include "xfs_log_format.h" #include "xfs_log_format.h"
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_bit.h" #include "xfs_bit.h"
#include "xfs_sb.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_inode.h" #include "xfs_inode.h"
#include "xfs_btree.h" #include "xfs_btree.h"
...@@ -27,6 +26,7 @@ ...@@ -27,6 +26,7 @@
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_log.h" #include "xfs_log.h"
#include "xfs_rmap.h" #include "xfs_rmap.h"
#include "xfs_ag.h"
/* /*
* Lookup a record by ino in the btree given by cur. * Lookup a record by ino in the btree given by cur.
...@@ -105,7 +105,7 @@ xfs_inobt_get_rec( ...@@ -105,7 +105,7 @@ xfs_inobt_get_rec(
int *stat) int *stat)
{ {
struct xfs_mount *mp = cur->bc_mp; struct xfs_mount *mp = cur->bc_mp;
xfs_agnumber_t agno = cur->bc_ag.agno; xfs_agnumber_t agno = cur->bc_ag.pag->pag_agno;
union xfs_btree_rec *rec; union xfs_btree_rec *rec;
int error; int error;
uint64_t realfree; uint64_t realfree;
...@@ -172,18 +172,17 @@ xfs_inobt_insert( ...@@ -172,18 +172,17 @@ xfs_inobt_insert(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_buf *agbp, struct xfs_buf *agbp,
struct xfs_perag *pag,
xfs_agino_t newino, xfs_agino_t newino,
xfs_agino_t newlen, xfs_agino_t newlen,
xfs_btnum_t btnum) xfs_btnum_t btnum)
{ {
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
struct xfs_agi *agi = agbp->b_addr;
xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno);
xfs_agino_t thisino; xfs_agino_t thisino;
int i; int i;
int error; int error;
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum); cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, btnum);
for (thisino = newino; for (thisino = newino;
thisino < newino + newlen; thisino < newino + newlen;
...@@ -520,18 +519,17 @@ xfs_inobt_insert_sprec( ...@@ -520,18 +519,17 @@ xfs_inobt_insert_sprec(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_buf *agbp, struct xfs_buf *agbp,
struct xfs_perag *pag,
int btnum, int btnum,
struct xfs_inobt_rec_incore *nrec, /* in/out: new/merged rec. */ struct xfs_inobt_rec_incore *nrec, /* in/out: new/merged rec. */
bool merge) /* merge or replace */ bool merge) /* merge or replace */
{ {
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
struct xfs_agi *agi = agbp->b_addr;
xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno);
int error; int error;
int i; int i;
struct xfs_inobt_rec_incore rec; struct xfs_inobt_rec_incore rec;
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum); cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, btnum);
/* the new record is pre-aligned so we know where to look */ /* the new record is pre-aligned so we know where to look */
error = xfs_inobt_lookup(cur, nrec->ir_startino, XFS_LOOKUP_EQ, &i); error = xfs_inobt_lookup(cur, nrec->ir_startino, XFS_LOOKUP_EQ, &i);
...@@ -578,14 +576,14 @@ xfs_inobt_insert_sprec( ...@@ -578,14 +576,14 @@ xfs_inobt_insert_sprec(
goto error; goto error;
} }
trace_xfs_irec_merge_pre(mp, agno, rec.ir_startino, trace_xfs_irec_merge_pre(mp, pag->pag_agno, rec.ir_startino,
rec.ir_holemask, nrec->ir_startino, rec.ir_holemask, nrec->ir_startino,
nrec->ir_holemask); nrec->ir_holemask);
/* merge to nrec to output the updated record */ /* merge to nrec to output the updated record */
__xfs_inobt_rec_merge(nrec, &rec); __xfs_inobt_rec_merge(nrec, &rec);
trace_xfs_irec_merge_post(mp, agno, nrec->ir_startino, trace_xfs_irec_merge_post(mp, pag->pag_agno, nrec->ir_startino,
nrec->ir_holemask); nrec->ir_holemask);
error = xfs_inobt_rec_check_count(mp, nrec); error = xfs_inobt_rec_check_count(mp, nrec);
...@@ -606,28 +604,28 @@ xfs_inobt_insert_sprec( ...@@ -606,28 +604,28 @@ xfs_inobt_insert_sprec(
} }
/* /*
* Allocate new inodes in the allocation group specified by agbp. * Allocate new inodes in the allocation group specified by agbp. Returns 0 if
* Returns 0 if inodes were allocated in this AG; 1 if there was no space * inodes were allocated in this AG; -EAGAIN if there was no space in this AG so
* in this AG; or the usual negative error code. * the caller knows it can try another AG, a hard -ENOSPC when over the maximum
* inode count threshold, or the usual negative error code for other errors.
*/ */
STATIC int STATIC int
xfs_ialloc_ag_alloc( xfs_ialloc_ag_alloc(
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_buf *agbp) struct xfs_buf *agbp,
struct xfs_perag *pag)
{ {
struct xfs_agi *agi; struct xfs_agi *agi;
struct xfs_alloc_arg args; struct xfs_alloc_arg args;
xfs_agnumber_t agno;
int error; int error;
xfs_agino_t newino; /* new first inode's number */ xfs_agino_t newino; /* new first inode's number */
xfs_agino_t newlen; /* new number of inodes */ xfs_agino_t newlen; /* new number of inodes */
int isaligned = 0; /* inode allocation at stripe */ int isaligned = 0; /* inode allocation at stripe */
/* unit boundary */ /* unit boundary */
/* init. to full chunk */ /* init. to full chunk */
uint16_t allocmask = (uint16_t) -1;
struct xfs_inobt_rec_incore rec; struct xfs_inobt_rec_incore rec;
struct xfs_perag *pag;
struct xfs_ino_geometry *igeo = M_IGEO(tp->t_mountp); struct xfs_ino_geometry *igeo = M_IGEO(tp->t_mountp);
uint16_t allocmask = (uint16_t) -1;
int do_sparse = 0; int do_sparse = 0;
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
...@@ -660,14 +658,13 @@ xfs_ialloc_ag_alloc( ...@@ -660,14 +658,13 @@ xfs_ialloc_ag_alloc(
*/ */
agi = agbp->b_addr; agi = agbp->b_addr;
newino = be32_to_cpu(agi->agi_newino); newino = be32_to_cpu(agi->agi_newino);
agno = be32_to_cpu(agi->agi_seqno);
args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) + args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) +
igeo->ialloc_blks; igeo->ialloc_blks;
if (do_sparse) if (do_sparse)
goto sparse_alloc; goto sparse_alloc;
if (likely(newino != NULLAGINO && if (likely(newino != NULLAGINO &&
(args.agbno < be32_to_cpu(agi->agi_length)))) { (args.agbno < be32_to_cpu(agi->agi_length)))) {
args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
args.type = XFS_ALLOCTYPE_THIS_BNO; args.type = XFS_ALLOCTYPE_THIS_BNO;
args.prod = 1; args.prod = 1;
...@@ -727,7 +724,7 @@ xfs_ialloc_ag_alloc( ...@@ -727,7 +724,7 @@ xfs_ialloc_ag_alloc(
* For now, just allocate blocks up front. * For now, just allocate blocks up front.
*/ */
args.agbno = be32_to_cpu(agi->agi_root); args.agbno = be32_to_cpu(agi->agi_root);
args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
/* /*
* Allocate a fixed-size extent of inodes. * Allocate a fixed-size extent of inodes.
*/ */
...@@ -748,7 +745,7 @@ xfs_ialloc_ag_alloc( ...@@ -748,7 +745,7 @@ xfs_ialloc_ag_alloc(
if (isaligned && args.fsbno == NULLFSBLOCK) { if (isaligned && args.fsbno == NULLFSBLOCK) {
args.type = XFS_ALLOCTYPE_NEAR_BNO; args.type = XFS_ALLOCTYPE_NEAR_BNO;
args.agbno = be32_to_cpu(agi->agi_root); args.agbno = be32_to_cpu(agi->agi_root);
args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
args.alignment = igeo->cluster_align; args.alignment = igeo->cluster_align;
if ((error = xfs_alloc_vextent(&args))) if ((error = xfs_alloc_vextent(&args)))
return error; return error;
...@@ -764,7 +761,7 @@ xfs_ialloc_ag_alloc( ...@@ -764,7 +761,7 @@ xfs_ialloc_ag_alloc(
sparse_alloc: sparse_alloc:
args.type = XFS_ALLOCTYPE_NEAR_BNO; args.type = XFS_ALLOCTYPE_NEAR_BNO;
args.agbno = be32_to_cpu(agi->agi_root); args.agbno = be32_to_cpu(agi->agi_root);
args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); args.fsbno = XFS_AGB_TO_FSB(args.mp, pag->pag_agno, args.agbno);
args.alignment = args.mp->m_sb.sb_spino_align; args.alignment = args.mp->m_sb.sb_spino_align;
args.prod = 1; args.prod = 1;
...@@ -796,7 +793,7 @@ xfs_ialloc_ag_alloc( ...@@ -796,7 +793,7 @@ xfs_ialloc_ag_alloc(
} }
if (args.fsbno == NULLFSBLOCK) if (args.fsbno == NULLFSBLOCK)
return 1; return -EAGAIN;
ASSERT(args.len == args.minlen); ASSERT(args.len == args.minlen);
...@@ -809,7 +806,7 @@ xfs_ialloc_ag_alloc( ...@@ -809,7 +806,7 @@ xfs_ialloc_ag_alloc(
* rather than a linear progression to prevent the next generation * rather than a linear progression to prevent the next generation
* number from being easily guessable. * number from being easily guessable.
*/ */
error = xfs_ialloc_inode_init(args.mp, tp, NULL, newlen, agno, error = xfs_ialloc_inode_init(args.mp, tp, NULL, newlen, pag->pag_agno,
args.agbno, args.len, prandom_u32()); args.agbno, args.len, prandom_u32());
if (error) if (error)
...@@ -836,12 +833,12 @@ xfs_ialloc_ag_alloc( ...@@ -836,12 +833,12 @@ xfs_ialloc_ag_alloc(
* if necessary. If a merge does occur, rec is updated to the * if necessary. If a merge does occur, rec is updated to the
* merged record. * merged record.
*/ */
error = xfs_inobt_insert_sprec(args.mp, tp, agbp, XFS_BTNUM_INO, error = xfs_inobt_insert_sprec(args.mp, tp, agbp, pag,
&rec, true); XFS_BTNUM_INO, &rec, true);
if (error == -EFSCORRUPTED) { if (error == -EFSCORRUPTED) {
xfs_alert(args.mp, xfs_alert(args.mp,
"invalid sparse inode record: ino 0x%llx holemask 0x%x count %u", "invalid sparse inode record: ino 0x%llx holemask 0x%x count %u",
XFS_AGINO_TO_INO(args.mp, agno, XFS_AGINO_TO_INO(args.mp, pag->pag_agno,
rec.ir_startino), rec.ir_startino),
rec.ir_holemask, rec.ir_count); rec.ir_holemask, rec.ir_count);
xfs_force_shutdown(args.mp, SHUTDOWN_CORRUPT_INCORE); xfs_force_shutdown(args.mp, SHUTDOWN_CORRUPT_INCORE);
...@@ -861,21 +858,20 @@ xfs_ialloc_ag_alloc( ...@@ -861,21 +858,20 @@ xfs_ialloc_ag_alloc(
* existing record with this one. * existing record with this one.
*/ */
if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) { if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) {
error = xfs_inobt_insert_sprec(args.mp, tp, agbp, error = xfs_inobt_insert_sprec(args.mp, tp, agbp, pag,
XFS_BTNUM_FINO, &rec, XFS_BTNUM_FINO, &rec, false);
false);
if (error) if (error)
return error; return error;
} }
} else { } else {
/* full chunk - insert new records to both btrees */ /* full chunk - insert new records to both btrees */
error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen, error = xfs_inobt_insert(args.mp, tp, agbp, pag, newino, newlen,
XFS_BTNUM_INO); XFS_BTNUM_INO);
if (error) if (error)
return error; return error;
if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) { if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) {
error = xfs_inobt_insert(args.mp, tp, agbp, newino, error = xfs_inobt_insert(args.mp, tp, agbp, pag, newino,
newlen, XFS_BTNUM_FINO); newlen, XFS_BTNUM_FINO);
if (error) if (error)
return error; return error;
...@@ -887,7 +883,6 @@ xfs_ialloc_ag_alloc( ...@@ -887,7 +883,6 @@ xfs_ialloc_ag_alloc(
*/ */
be32_add_cpu(&agi->agi_count, newlen); be32_add_cpu(&agi->agi_count, newlen);
be32_add_cpu(&agi->agi_freecount, newlen); be32_add_cpu(&agi->agi_freecount, newlen);
pag = agbp->b_pag;
pag->pagi_freecount += newlen; pag->pagi_freecount += newlen;
pag->pagi_count += newlen; pag->pagi_count += newlen;
agi->agi_newino = cpu_to_be32(newino); agi->agi_newino = cpu_to_be32(newino);
...@@ -905,139 +900,6 @@ xfs_ialloc_ag_alloc( ...@@ -905,139 +900,6 @@ xfs_ialloc_ag_alloc(
return 0; return 0;
} }
STATIC xfs_agnumber_t
xfs_ialloc_next_ag(
xfs_mount_t *mp)
{
xfs_agnumber_t agno;
spin_lock(&mp->m_agirotor_lock);
agno = mp->m_agirotor;
if (++mp->m_agirotor >= mp->m_maxagi)
mp->m_agirotor = 0;
spin_unlock(&mp->m_agirotor_lock);
return agno;
}
/*
* Select an allocation group to look for a free inode in, based on the parent
* inode and the mode. Return the allocation group buffer.
*/
STATIC xfs_agnumber_t
xfs_ialloc_ag_select(
xfs_trans_t *tp, /* transaction pointer */
xfs_ino_t parent, /* parent directory inode number */
umode_t mode) /* bits set to indicate file type */
{
xfs_agnumber_t agcount; /* number of ag's in the filesystem */
xfs_agnumber_t agno; /* current ag number */
int flags; /* alloc buffer locking flags */
xfs_extlen_t ineed; /* blocks needed for inode allocation */
xfs_extlen_t longest = 0; /* longest extent available */
xfs_mount_t *mp; /* mount point structure */
int needspace; /* file mode implies space allocated */
xfs_perag_t *pag; /* per allocation group data */
xfs_agnumber_t pagno; /* parent (starting) ag number */
int error;
/*
* Files of these types need at least one block if length > 0
* (and they won't fit in the inode, but that's hard to figure out).
*/
needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode);
mp = tp->t_mountp;
agcount = mp->m_maxagi;
if (S_ISDIR(mode))
pagno = xfs_ialloc_next_ag(mp);
else {
pagno = XFS_INO_TO_AGNO(mp, parent);
if (pagno >= agcount)
pagno = 0;
}
ASSERT(pagno < agcount);
/*
* Loop through allocation groups, looking for one with a little
* free space in it. Note we don't look for free inodes, exactly.
* Instead, we include whether there is a need to allocate inodes
* to mean that blocks must be allocated for them,
* if none are currently free.
*/
agno = pagno;
flags = XFS_ALLOC_FLAG_TRYLOCK;
for (;;) {
pag = xfs_perag_get(mp, agno);
if (!pag->pagi_inodeok) {
xfs_ialloc_next_ag(mp);
goto nextag;
}
if (!pag->pagi_init) {
error = xfs_ialloc_pagi_init(mp, tp, agno);
if (error)
goto nextag;
}
if (pag->pagi_freecount) {
xfs_perag_put(pag);
return agno;
}
if (!pag->pagf_init) {
error = xfs_alloc_pagf_init(mp, tp, agno, flags);
if (error)
goto nextag;
}
/*
* Check that there is enough free space for the file plus a
* chunk of inodes if we need to allocate some. If this is the
* first pass across the AGs, take into account the potential
* space needed for alignment of inode chunks when checking the
* longest contiguous free space in the AG - this prevents us
* from getting ENOSPC because we have free space larger than
* ialloc_blks but alignment constraints prevent us from using
* it.
*
* If we can't find an AG with space for full alignment slack to
* be taken into account, we must be near ENOSPC in all AGs.
* Hence we don't include alignment for the second pass and so
* if we fail allocation due to alignment issues then it is most
* likely a real ENOSPC condition.
*/
ineed = M_IGEO(mp)->ialloc_min_blks;
if (flags && ineed > 1)
ineed += M_IGEO(mp)->cluster_align;
longest = pag->pagf_longest;
if (!longest)
longest = pag->pagf_flcount > 0;
if (pag->pagf_freeblks >= needspace + ineed &&
longest >= ineed) {
xfs_perag_put(pag);
return agno;
}
nextag:
xfs_perag_put(pag);
/*
* No point in iterating over the rest, if we're shutting
* down.
*/
if (XFS_FORCED_SHUTDOWN(mp))
return NULLAGNUMBER;
agno++;
if (agno >= agcount)
agno = 0;
if (agno == pagno) {
if (flags == 0)
return NULLAGNUMBER;
flags = 0;
}
}
}
/* /*
* Try to retrieve the next record to the left/right from the current one. * Try to retrieve the next record to the left/right from the current one.
*/ */
...@@ -1123,15 +985,14 @@ STATIC int ...@@ -1123,15 +985,14 @@ STATIC int
xfs_dialloc_ag_inobt( xfs_dialloc_ag_inobt(
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_buf *agbp, struct xfs_buf *agbp,
struct xfs_perag *pag,
xfs_ino_t parent, xfs_ino_t parent,
xfs_ino_t *inop) xfs_ino_t *inop)
{ {
struct xfs_mount *mp = tp->t_mountp; struct xfs_mount *mp = tp->t_mountp;
struct xfs_agi *agi = agbp->b_addr; struct xfs_agi *agi = agbp->b_addr;
xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno);
xfs_agnumber_t pagno = XFS_INO_TO_AGNO(mp, parent); xfs_agnumber_t pagno = XFS_INO_TO_AGNO(mp, parent);
xfs_agino_t pagino = XFS_INO_TO_AGINO(mp, parent); xfs_agino_t pagino = XFS_INO_TO_AGINO(mp, parent);
struct xfs_perag *pag = agbp->b_pag;
struct xfs_btree_cur *cur, *tcur; struct xfs_btree_cur *cur, *tcur;
struct xfs_inobt_rec_incore rec, trec; struct xfs_inobt_rec_incore rec, trec;
xfs_ino_t ino; xfs_ino_t ino;
...@@ -1145,7 +1006,7 @@ xfs_dialloc_ag_inobt( ...@@ -1145,7 +1006,7 @@ xfs_dialloc_ag_inobt(
ASSERT(pag->pagi_freecount > 0); ASSERT(pag->pagi_freecount > 0);
restart_pagno: restart_pagno:
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
/* /*
* If pagino is 0 (this is the root inode allocation) use newino. * If pagino is 0 (this is the root inode allocation) use newino.
* This must work because we've just allocated some. * This must work because we've just allocated some.
...@@ -1160,7 +1021,7 @@ xfs_dialloc_ag_inobt( ...@@ -1160,7 +1021,7 @@ xfs_dialloc_ag_inobt(
/* /*
* If in the same AG as the parent, try to get near the parent. * If in the same AG as the parent, try to get near the parent.
*/ */
if (pagno == agno) { if (pagno == pag->pag_agno) {
int doneleft; /* done, to the left */ int doneleft; /* done, to the left */
int doneright; /* done, to the right */ int doneright; /* done, to the right */
...@@ -1363,7 +1224,7 @@ xfs_dialloc_ag_inobt( ...@@ -1363,7 +1224,7 @@ xfs_dialloc_ag_inobt(
ASSERT(offset < XFS_INODES_PER_CHUNK); ASSERT(offset < XFS_INODES_PER_CHUNK);
ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) % ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %
XFS_INODES_PER_CHUNK) == 0); XFS_INODES_PER_CHUNK) == 0);
ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset); ino = XFS_AGINO_TO_INO(mp, pag->pag_agno, rec.ir_startino + offset);
rec.ir_free &= ~XFS_INOBT_MASK(offset); rec.ir_free &= ~XFS_INOBT_MASK(offset);
rec.ir_freecount--; rec.ir_freecount--;
error = xfs_inobt_update(cur, &rec); error = xfs_inobt_update(cur, &rec);
...@@ -1568,16 +1429,16 @@ xfs_dialloc_ag_update_inobt( ...@@ -1568,16 +1429,16 @@ xfs_dialloc_ag_update_inobt(
* The caller selected an AG for us, and made sure that free inodes are * The caller selected an AG for us, and made sure that free inodes are
* available. * available.
*/ */
int static int
xfs_dialloc_ag( xfs_dialloc_ag(
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_buf *agbp, struct xfs_buf *agbp,
struct xfs_perag *pag,
xfs_ino_t parent, xfs_ino_t parent,
xfs_ino_t *inop) xfs_ino_t *inop)
{ {
struct xfs_mount *mp = tp->t_mountp; struct xfs_mount *mp = tp->t_mountp;
struct xfs_agi *agi = agbp->b_addr; struct xfs_agi *agi = agbp->b_addr;
xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno);
xfs_agnumber_t pagno = XFS_INO_TO_AGNO(mp, parent); xfs_agnumber_t pagno = XFS_INO_TO_AGNO(mp, parent);
xfs_agino_t pagino = XFS_INO_TO_AGINO(mp, parent); xfs_agino_t pagino = XFS_INO_TO_AGINO(mp, parent);
struct xfs_btree_cur *cur; /* finobt cursor */ struct xfs_btree_cur *cur; /* finobt cursor */
...@@ -1589,7 +1450,7 @@ xfs_dialloc_ag( ...@@ -1589,7 +1450,7 @@ xfs_dialloc_ag(
int i; int i;
if (!xfs_sb_version_hasfinobt(&mp->m_sb)) if (!xfs_sb_version_hasfinobt(&mp->m_sb))
return xfs_dialloc_ag_inobt(tp, agbp, parent, inop); return xfs_dialloc_ag_inobt(tp, agbp, pag, parent, inop);
/* /*
* If pagino is 0 (this is the root inode allocation) use newino. * If pagino is 0 (this is the root inode allocation) use newino.
...@@ -1598,7 +1459,7 @@ xfs_dialloc_ag( ...@@ -1598,7 +1459,7 @@ xfs_dialloc_ag(
if (!pagino) if (!pagino)
pagino = be32_to_cpu(agi->agi_newino); pagino = be32_to_cpu(agi->agi_newino);
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO); cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_FINO);
error = xfs_check_agi_freecount(cur, agi); error = xfs_check_agi_freecount(cur, agi);
if (error) if (error)
...@@ -1609,7 +1470,7 @@ xfs_dialloc_ag( ...@@ -1609,7 +1470,7 @@ xfs_dialloc_ag(
* parent. If so, find the closest available inode to the parent. If * parent. If so, find the closest available inode to the parent. If
* not, consider the agi hint or find the first free inode in the AG. * not, consider the agi hint or find the first free inode in the AG.
*/ */
if (agno == pagno) if (pag->pag_agno == pagno)
error = xfs_dialloc_ag_finobt_near(pagino, &cur, &rec); error = xfs_dialloc_ag_finobt_near(pagino, &cur, &rec);
else else
error = xfs_dialloc_ag_finobt_newino(agi, cur, &rec); error = xfs_dialloc_ag_finobt_newino(agi, cur, &rec);
...@@ -1621,7 +1482,7 @@ xfs_dialloc_ag( ...@@ -1621,7 +1482,7 @@ xfs_dialloc_ag(
ASSERT(offset < XFS_INODES_PER_CHUNK); ASSERT(offset < XFS_INODES_PER_CHUNK);
ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) % ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %
XFS_INODES_PER_CHUNK) == 0); XFS_INODES_PER_CHUNK) == 0);
ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset); ino = XFS_AGINO_TO_INO(mp, pag->pag_agno, rec.ir_startino + offset);
/* /*
* Modify or remove the finobt record. * Modify or remove the finobt record.
...@@ -1641,7 +1502,7 @@ xfs_dialloc_ag( ...@@ -1641,7 +1502,7 @@ xfs_dialloc_ag(
* the original freecount. If all is well, make the equivalent update to * the original freecount. If all is well, make the equivalent update to
* the inobt using the finobt record and offset information. * the inobt using the finobt record and offset information.
*/ */
icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); icur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
error = xfs_check_agi_freecount(icur, agi); error = xfs_check_agi_freecount(icur, agi);
if (error) if (error)
...@@ -1657,7 +1518,7 @@ xfs_dialloc_ag( ...@@ -1657,7 +1518,7 @@ xfs_dialloc_ag(
*/ */
be32_add_cpu(&agi->agi_freecount, -1); be32_add_cpu(&agi->agi_freecount, -1);
xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
agbp->b_pag->pagi_freecount--; pag->pagi_freecount--;
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1);
...@@ -1708,54 +1569,195 @@ xfs_dialloc_roll( ...@@ -1708,54 +1569,195 @@ xfs_dialloc_roll(
/* Re-attach the quota info that we detached from prev trx. */ /* Re-attach the quota info that we detached from prev trx. */
tp->t_dqinfo = dqinfo; tp->t_dqinfo = dqinfo;
/*
* Join the buffer even on commit error so that the buffer is released
* when the caller cancels the transaction and doesn't have to handle
* this error case specially.
*/
xfs_trans_bjoin(tp, agibp);
*tpp = tp; *tpp = tp;
return error;
}
static xfs_agnumber_t
xfs_ialloc_next_ag(
xfs_mount_t *mp)
{
xfs_agnumber_t agno;
spin_lock(&mp->m_agirotor_lock);
agno = mp->m_agirotor;
if (++mp->m_agirotor >= mp->m_maxagi)
mp->m_agirotor = 0;
spin_unlock(&mp->m_agirotor_lock);
return agno;
}
static bool
xfs_dialloc_good_ag(
struct xfs_trans *tp,
struct xfs_perag *pag,
umode_t mode,
int flags,
bool ok_alloc)
{
struct xfs_mount *mp = tp->t_mountp;
xfs_extlen_t ineed;
xfs_extlen_t longest = 0;
int needspace;
int error;
if (!pag->pagi_inodeok)
return false;
if (!pag->pagi_init) {
error = xfs_ialloc_pagi_init(mp, tp, pag->pag_agno);
if (error)
return false;
}
if (pag->pagi_freecount)
return true;
if (!ok_alloc)
return false;
if (!pag->pagf_init) {
error = xfs_alloc_pagf_init(mp, tp, pag->pag_agno, flags);
if (error)
return false;
}
/*
* Check that there is enough free space for the file plus a chunk of
* inodes if we need to allocate some. If this is the first pass across
* the AGs, take into account the potential space needed for alignment
* of inode chunks when checking the longest contiguous free space in
* the AG - this prevents us from getting ENOSPC because we have free
* space larger than ialloc_blks but alignment constraints prevent us
* from using it.
*
* If we can't find an AG with space for full alignment slack to be
* taken into account, we must be near ENOSPC in all AGs. Hence we
* don't include alignment for the second pass and so if we fail
* allocation due to alignment issues then it is most likely a real
* ENOSPC condition.
*
* XXX(dgc): this calculation is now bogus thanks to the per-ag
* reservations that xfs_alloc_fix_freelist() now does via
* xfs_alloc_space_available(). When the AG fills up, pagf_freeblks will
* be more than large enough for the check below to succeed, but
* xfs_alloc_space_available() will fail because of the non-zero
* metadata reservation and hence we won't actually be able to allocate
* more inodes in this AG. We do soooo much unnecessary work near ENOSPC
* because of this.
*/
ineed = M_IGEO(mp)->ialloc_min_blks;
if (flags && ineed > 1)
ineed += M_IGEO(mp)->cluster_align;
longest = pag->pagf_longest;
if (!longest)
longest = pag->pagf_flcount > 0;
needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode);
if (pag->pagf_freeblks < needspace + ineed || longest < ineed)
return false;
return true;
}
static int
xfs_dialloc_try_ag(
struct xfs_trans **tpp,
struct xfs_perag *pag,
xfs_ino_t parent,
xfs_ino_t *new_ino,
bool ok_alloc)
{
struct xfs_buf *agbp;
xfs_ino_t ino;
int error;
/*
* Then read in the AGI buffer and recheck with the AGI buffer
* lock held.
*/
error = xfs_ialloc_read_agi(pag->pag_mount, *tpp, pag->pag_agno, &agbp);
if (error) if (error)
return error; return error;
xfs_trans_bjoin(tp, agibp);
return 0; if (!pag->pagi_freecount) {
if (!ok_alloc) {
error = -EAGAIN;
goto out_release;
}
error = xfs_ialloc_ag_alloc(*tpp, agbp, pag);
if (error < 0)
goto out_release;
/*
* We successfully allocated space for an inode cluster in this
* AG. Roll the transaction so that we can allocate one of the
* new inodes.
*/
ASSERT(pag->pagi_freecount > 0);
error = xfs_dialloc_roll(tpp, agbp);
if (error)
goto out_release;
}
/* Allocate an inode in the found AG */
error = xfs_dialloc_ag(*tpp, agbp, pag, parent, &ino);
if (!error)
*new_ino = ino;
return error;
out_release:
xfs_trans_brelse(*tpp, agbp);
return error;
} }
/* /*
* Select and prepare an AG for inode allocation. * Allocate an on-disk inode.
* *
* Mode is used to tell whether the new inode is a directory and hence where to * Mode is used to tell whether the new inode is a directory and hence where to
* locate it. * locate it. The on-disk inode that is allocated will be returned in @new_ino
* * on success, otherwise an error will be set to indicate the failure (e.g.
* This function will ensure that the selected AG has free inodes available to * -ENOSPC).
* allocate from. The selected AGI will be returned locked to the caller, and it
* will allocate more free inodes if required. If no free inodes are found or
* can be allocated, no AGI will be returned.
*/ */
int int
xfs_dialloc_select_ag( xfs_dialloc(
struct xfs_trans **tpp, struct xfs_trans **tpp,
xfs_ino_t parent, xfs_ino_t parent,
umode_t mode, umode_t mode,
struct xfs_buf **IO_agbp) xfs_ino_t *new_ino)
{ {
struct xfs_mount *mp = (*tpp)->t_mountp; struct xfs_mount *mp = (*tpp)->t_mountp;
struct xfs_buf *agbp;
xfs_agnumber_t agno; xfs_agnumber_t agno;
int error; int error = 0;
bool noroom = false;
xfs_agnumber_t start_agno; xfs_agnumber_t start_agno;
struct xfs_perag *pag; struct xfs_perag *pag;
struct xfs_ino_geometry *igeo = M_IGEO(mp); struct xfs_ino_geometry *igeo = M_IGEO(mp);
bool okalloc = true; bool ok_alloc = true;
int flags;
*IO_agbp = NULL; xfs_ino_t ino;
/* /*
* We do not have an agbp, so select an initial allocation * Directories, symlinks, and regular files frequently allocate at least
* group for inode allocation. * one block, so factor that potential expansion when we examine whether
* an AG has enough space for file creation.
*/ */
start_agno = xfs_ialloc_ag_select(*tpp, parent, mode); if (S_ISDIR(mode))
if (start_agno == NULLAGNUMBER) start_agno = xfs_ialloc_next_ag(mp);
return 0; else {
start_agno = XFS_INO_TO_AGNO(mp, parent);
if (start_agno >= mp->m_maxagi)
start_agno = 0;
}
/* /*
* If we have already hit the ceiling of inode blocks then clear * If we have already hit the ceiling of inode blocks then clear
* okalloc so we scan all available agi structures for a free * ok_alloc so we scan all available agi structures for a free
* inode. * inode.
* *
* Read rough value of mp->m_icount by percpu_counter_read_positive, * Read rough value of mp->m_icount by percpu_counter_read_positive,
...@@ -1764,8 +1766,7 @@ xfs_dialloc_select_ag( ...@@ -1764,8 +1766,7 @@ xfs_dialloc_select_ag(
if (igeo->maxicount && if (igeo->maxicount &&
percpu_counter_read_positive(&mp->m_icount) + igeo->ialloc_inos percpu_counter_read_positive(&mp->m_icount) + igeo->ialloc_inos
> igeo->maxicount) { > igeo->maxicount) {
noroom = true; ok_alloc = false;
okalloc = false;
} }
/* /*
...@@ -1774,82 +1775,36 @@ xfs_dialloc_select_ag( ...@@ -1774,82 +1775,36 @@ xfs_dialloc_select_ag(
* allocation groups upward, wrapping at the end. * allocation groups upward, wrapping at the end.
*/ */
agno = start_agno; agno = start_agno;
flags = XFS_ALLOC_FLAG_TRYLOCK;
for (;;) { for (;;) {
pag = xfs_perag_get(mp, agno); pag = xfs_perag_get(mp, agno);
if (!pag->pagi_inodeok) { if (xfs_dialloc_good_ag(*tpp, pag, mode, flags, ok_alloc)) {
xfs_ialloc_next_ag(mp); error = xfs_dialloc_try_ag(tpp, pag, parent,
goto nextag; &ino, ok_alloc);
} if (error != -EAGAIN)
if (!pag->pagi_init) {
error = xfs_ialloc_pagi_init(mp, *tpp, agno);
if (error)
break; break;
} }
/* if (XFS_FORCED_SHUTDOWN(mp)) {
* Do a first racy fast path check if this AG is usable. error = -EFSCORRUPTED;
*/
if (!pag->pagi_freecount && !okalloc)
goto nextag;
/*
* Then read in the AGI buffer and recheck with the AGI buffer
* lock held.
*/
error = xfs_ialloc_read_agi(mp, *tpp, agno, &agbp);
if (error)
break;
if (pag->pagi_freecount) {
xfs_perag_put(pag);
goto found_ag;
}
if (!okalloc)
goto nextag_relse_buffer;
error = xfs_ialloc_ag_alloc(*tpp, agbp);
if (error < 0) {
xfs_trans_brelse(*tpp, agbp);
if (error == -ENOSPC)
error = 0;
break; break;
} }
if (++agno == mp->m_maxagi)
if (error == 0) { agno = 0;
/* if (agno == start_agno) {
* We successfully allocated space for an inode cluster if (!flags) {
* in this AG. Roll the transaction so that we can error = -ENOSPC;
* allocate one of the new inodes. break;
*/
ASSERT(pag->pagi_freecount > 0);
xfs_perag_put(pag);
error = xfs_dialloc_roll(tpp, agbp);
if (error) {
xfs_buf_relse(agbp);
return error;
} }
goto found_ag; flags = 0;
} }
nextag_relse_buffer:
xfs_trans_brelse(*tpp, agbp);
nextag:
xfs_perag_put(pag); xfs_perag_put(pag);
if (++agno == mp->m_sb.sb_agcount)
agno = 0;
if (agno == start_agno)
return noroom ? -ENOSPC : 0;
} }
if (!error)
*new_ino = ino;
xfs_perag_put(pag); xfs_perag_put(pag);
return error; return error;
found_ag:
*IO_agbp = agbp;
return 0;
} }
/* /*
...@@ -1935,12 +1890,12 @@ xfs_difree_inobt( ...@@ -1935,12 +1890,12 @@ xfs_difree_inobt(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_buf *agbp, struct xfs_buf *agbp,
struct xfs_perag *pag,
xfs_agino_t agino, xfs_agino_t agino,
struct xfs_icluster *xic, struct xfs_icluster *xic,
struct xfs_inobt_rec_incore *orec) struct xfs_inobt_rec_incore *orec)
{ {
struct xfs_agi *agi = agbp->b_addr; struct xfs_agi *agi = agbp->b_addr;
xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno);
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
struct xfs_inobt_rec_incore rec; struct xfs_inobt_rec_incore rec;
int ilen; int ilen;
...@@ -1954,7 +1909,7 @@ xfs_difree_inobt( ...@@ -1954,7 +1909,7 @@ xfs_difree_inobt(
/* /*
* Initialize the cursor. * Initialize the cursor.
*/ */
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
error = xfs_check_agi_freecount(cur, agi); error = xfs_check_agi_freecount(cur, agi);
if (error) if (error)
...@@ -2005,7 +1960,8 @@ xfs_difree_inobt( ...@@ -2005,7 +1960,8 @@ xfs_difree_inobt(
struct xfs_perag *pag = agbp->b_pag; struct xfs_perag *pag = agbp->b_pag;
xic->deleted = true; xic->deleted = true;
xic->first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino); xic->first_ino = XFS_AGINO_TO_INO(mp, pag->pag_agno,
rec.ir_startino);
xic->alloc = xfs_inobt_irec_to_allocmask(&rec); xic->alloc = xfs_inobt_irec_to_allocmask(&rec);
/* /*
...@@ -2028,7 +1984,7 @@ xfs_difree_inobt( ...@@ -2028,7 +1984,7 @@ xfs_difree_inobt(
goto error0; goto error0;
} }
xfs_difree_inode_chunk(tp, agno, &rec); xfs_difree_inode_chunk(tp, pag->pag_agno, &rec);
} else { } else {
xic->deleted = false; xic->deleted = false;
...@@ -2044,7 +2000,7 @@ xfs_difree_inobt( ...@@ -2044,7 +2000,7 @@ xfs_difree_inobt(
*/ */
be32_add_cpu(&agi->agi_freecount, 1); be32_add_cpu(&agi->agi_freecount, 1);
xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
agbp->b_pag->pagi_freecount++; pag->pagi_freecount++;
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1); xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1);
} }
...@@ -2069,18 +2025,18 @@ xfs_difree_finobt( ...@@ -2069,18 +2025,18 @@ xfs_difree_finobt(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_buf *agbp, struct xfs_buf *agbp,
struct xfs_perag *pag,
xfs_agino_t agino, xfs_agino_t agino,
struct xfs_inobt_rec_incore *ibtrec) /* inobt record */ struct xfs_inobt_rec_incore *ibtrec) /* inobt record */
{ {
struct xfs_agi *agi = agbp->b_addr; struct xfs_agi *agi = agbp->b_addr;
xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno);
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
struct xfs_inobt_rec_incore rec; struct xfs_inobt_rec_incore rec;
int offset = agino - ibtrec->ir_startino; int offset = agino - ibtrec->ir_startino;
int error; int error;
int i; int i;
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO); cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_FINO);
error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i); error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i);
if (error) if (error)
...@@ -2178,36 +2134,33 @@ xfs_difree_finobt( ...@@ -2178,36 +2134,33 @@ xfs_difree_finobt(
*/ */
int int
xfs_difree( xfs_difree(
struct xfs_trans *tp, /* transaction pointer */ struct xfs_trans *tp,
xfs_ino_t inode, /* inode to be freed */ struct xfs_perag *pag,
struct xfs_icluster *xic) /* cluster info if deleted */ xfs_ino_t inode,
struct xfs_icluster *xic)
{ {
/* REFERENCED */ /* REFERENCED */
xfs_agblock_t agbno; /* block number containing inode */ xfs_agblock_t agbno; /* block number containing inode */
struct xfs_buf *agbp; /* buffer for allocation group header */ struct xfs_buf *agbp; /* buffer for allocation group header */
xfs_agino_t agino; /* allocation group inode number */ xfs_agino_t agino; /* allocation group inode number */
xfs_agnumber_t agno; /* allocation group number */
int error; /* error return value */ int error; /* error return value */
struct xfs_mount *mp; /* mount structure for filesystem */ struct xfs_mount *mp = tp->t_mountp;
struct xfs_inobt_rec_incore rec;/* btree record */ struct xfs_inobt_rec_incore rec;/* btree record */
mp = tp->t_mountp;
/* /*
* Break up inode number into its components. * Break up inode number into its components.
*/ */
agno = XFS_INO_TO_AGNO(mp, inode); if (pag->pag_agno != XFS_INO_TO_AGNO(mp, inode)) {
if (agno >= mp->m_sb.sb_agcount) { xfs_warn(mp, "%s: agno != pag->pag_agno (%d != %d).",
xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).", __func__, XFS_INO_TO_AGNO(mp, inode), pag->pag_agno);
__func__, agno, mp->m_sb.sb_agcount);
ASSERT(0); ASSERT(0);
return -EINVAL; return -EINVAL;
} }
agino = XFS_INO_TO_AGINO(mp, inode); agino = XFS_INO_TO_AGINO(mp, inode);
if (inode != XFS_AGINO_TO_INO(mp, agno, agino)) { if (inode != XFS_AGINO_TO_INO(mp, pag->pag_agno, agino)) {
xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).", xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).",
__func__, (unsigned long long)inode, __func__, (unsigned long long)inode,
(unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino)); (unsigned long long)XFS_AGINO_TO_INO(mp, pag->pag_agno, agino));
ASSERT(0); ASSERT(0);
return -EINVAL; return -EINVAL;
} }
...@@ -2221,7 +2174,7 @@ xfs_difree( ...@@ -2221,7 +2174,7 @@ xfs_difree(
/* /*
* Get the allocation group header. * Get the allocation group header.
*/ */
error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, &agbp);
if (error) { if (error) {
xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.", xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.",
__func__, error); __func__, error);
...@@ -2231,7 +2184,7 @@ xfs_difree( ...@@ -2231,7 +2184,7 @@ xfs_difree(
/* /*
* Fix up the inode allocation btree. * Fix up the inode allocation btree.
*/ */
error = xfs_difree_inobt(mp, tp, agbp, agino, xic, &rec); error = xfs_difree_inobt(mp, tp, agbp, pag, agino, xic, &rec);
if (error) if (error)
goto error0; goto error0;
...@@ -2239,7 +2192,7 @@ xfs_difree( ...@@ -2239,7 +2192,7 @@ xfs_difree(
* Fix up the free inode btree. * Fix up the free inode btree.
*/ */
if (xfs_sb_version_hasfinobt(&mp->m_sb)) { if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
error = xfs_difree_finobt(mp, tp, agbp, agino, &rec); error = xfs_difree_finobt(mp, tp, agbp, pag, agino, &rec);
if (error) if (error)
goto error0; goto error0;
} }
...@@ -2254,7 +2207,7 @@ STATIC int ...@@ -2254,7 +2207,7 @@ STATIC int
xfs_imap_lookup( xfs_imap_lookup(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_agino_t agino, xfs_agino_t agino,
xfs_agblock_t agbno, xfs_agblock_t agbno,
xfs_agblock_t *chunk_agbno, xfs_agblock_t *chunk_agbno,
...@@ -2267,11 +2220,11 @@ xfs_imap_lookup( ...@@ -2267,11 +2220,11 @@ xfs_imap_lookup(
int error; int error;
int i; int i;
error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, &agbp);
if (error) { if (error) {
xfs_alert(mp, xfs_alert(mp,
"%s: xfs_ialloc_read_agi() returned error %d, agno %d", "%s: xfs_ialloc_read_agi() returned error %d, agno %d",
__func__, error, agno); __func__, error, pag->pag_agno);
return error; return error;
} }
...@@ -2281,7 +2234,7 @@ xfs_imap_lookup( ...@@ -2281,7 +2234,7 @@ xfs_imap_lookup(
* we have a record, we need to ensure it contains the inode number * we have a record, we need to ensure it contains the inode number
* we are looking up. * we are looking up.
*/ */
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); cur = xfs_inobt_init_cursor(mp, tp, agbp, pag, XFS_BTNUM_INO);
error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i); error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
if (!error) { if (!error) {
if (i) if (i)
...@@ -2315,42 +2268,44 @@ xfs_imap_lookup( ...@@ -2315,42 +2268,44 @@ xfs_imap_lookup(
*/ */
int int
xfs_imap( xfs_imap(
xfs_mount_t *mp, /* file system mount structure */ struct xfs_mount *mp, /* file system mount structure */
xfs_trans_t *tp, /* transaction pointer */ struct xfs_trans *tp, /* transaction pointer */
xfs_ino_t ino, /* inode to locate */ xfs_ino_t ino, /* inode to locate */
struct xfs_imap *imap, /* location map structure */ struct xfs_imap *imap, /* location map structure */
uint flags) /* flags for inode btree lookup */ uint flags) /* flags for inode btree lookup */
{ {
xfs_agblock_t agbno; /* block number of inode in the alloc group */ xfs_agblock_t agbno; /* block number of inode in the alloc group */
xfs_agino_t agino; /* inode number within alloc group */ xfs_agino_t agino; /* inode number within alloc group */
xfs_agnumber_t agno; /* allocation group number */ xfs_agblock_t chunk_agbno; /* first block in inode chunk */
xfs_agblock_t chunk_agbno; /* first block in inode chunk */ xfs_agblock_t cluster_agbno; /* first block in inode cluster */
xfs_agblock_t cluster_agbno; /* first block in inode cluster */ int error; /* error code */
int error; /* error code */ int offset; /* index of inode in its buffer */
int offset; /* index of inode in its buffer */ xfs_agblock_t offset_agbno; /* blks from chunk start to inode */
xfs_agblock_t offset_agbno; /* blks from chunk start to inode */ struct xfs_perag *pag;
ASSERT(ino != NULLFSINO); ASSERT(ino != NULLFSINO);
/* /*
* Split up the inode number into its parts. * Split up the inode number into its parts.
*/ */
agno = XFS_INO_TO_AGNO(mp, ino); pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ino));
agino = XFS_INO_TO_AGINO(mp, ino); agino = XFS_INO_TO_AGINO(mp, ino);
agbno = XFS_AGINO_TO_AGBNO(mp, agino); agbno = XFS_AGINO_TO_AGBNO(mp, agino);
if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || if (!pag || agbno >= mp->m_sb.sb_agblocks ||
ino != XFS_AGINO_TO_INO(mp, agno, agino)) { ino != XFS_AGINO_TO_INO(mp, pag->pag_agno, agino)) {
error = -EINVAL;
#ifdef DEBUG #ifdef DEBUG
/* /*
* Don't output diagnostic information for untrusted inodes * Don't output diagnostic information for untrusted inodes
* as they can be invalid without implying corruption. * as they can be invalid without implying corruption.
*/ */
if (flags & XFS_IGET_UNTRUSTED) if (flags & XFS_IGET_UNTRUSTED)
return -EINVAL; goto out_drop;
if (agno >= mp->m_sb.sb_agcount) { if (!pag) {
xfs_alert(mp, xfs_alert(mp,
"%s: agno (%d) >= mp->m_sb.sb_agcount (%d)", "%s: agno (%d) >= mp->m_sb.sb_agcount (%d)",
__func__, agno, mp->m_sb.sb_agcount); __func__, XFS_INO_TO_AGNO(mp, ino),
mp->m_sb.sb_agcount);
} }
if (agbno >= mp->m_sb.sb_agblocks) { if (agbno >= mp->m_sb.sb_agblocks) {
xfs_alert(mp, xfs_alert(mp,
...@@ -2358,15 +2313,15 @@ xfs_imap( ...@@ -2358,15 +2313,15 @@ xfs_imap(
__func__, (unsigned long long)agbno, __func__, (unsigned long long)agbno,
(unsigned long)mp->m_sb.sb_agblocks); (unsigned long)mp->m_sb.sb_agblocks);
} }
if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) { if (pag && ino != XFS_AGINO_TO_INO(mp, pag->pag_agno, agino)) {
xfs_alert(mp, xfs_alert(mp,
"%s: ino (0x%llx) != XFS_AGINO_TO_INO() (0x%llx)", "%s: ino (0x%llx) != XFS_AGINO_TO_INO() (0x%llx)",
__func__, ino, __func__, ino,
XFS_AGINO_TO_INO(mp, agno, agino)); XFS_AGINO_TO_INO(mp, pag->pag_agno, agino));
} }
xfs_stack_trace(); xfs_stack_trace();
#endif /* DEBUG */ #endif /* DEBUG */
return -EINVAL; goto out_drop;
} }
/* /*
...@@ -2377,10 +2332,10 @@ xfs_imap( ...@@ -2377,10 +2332,10 @@ xfs_imap(
* in all cases where an untrusted inode number is passed. * in all cases where an untrusted inode number is passed.
*/ */
if (flags & XFS_IGET_UNTRUSTED) { if (flags & XFS_IGET_UNTRUSTED) {
error = xfs_imap_lookup(mp, tp, agno, agino, agbno, error = xfs_imap_lookup(mp, tp, pag, agino, agbno,
&chunk_agbno, &offset_agbno, flags); &chunk_agbno, &offset_agbno, flags);
if (error) if (error)
return error; goto out_drop;
goto out_map; goto out_map;
} }
...@@ -2392,11 +2347,12 @@ xfs_imap( ...@@ -2392,11 +2347,12 @@ xfs_imap(
offset = XFS_INO_TO_OFFSET(mp, ino); offset = XFS_INO_TO_OFFSET(mp, ino);
ASSERT(offset < mp->m_sb.sb_inopblock); ASSERT(offset < mp->m_sb.sb_inopblock);
imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno); imap->im_blkno = XFS_AGB_TO_DADDR(mp, pag->pag_agno, agbno);
imap->im_len = XFS_FSB_TO_BB(mp, 1); imap->im_len = XFS_FSB_TO_BB(mp, 1);
imap->im_boffset = (unsigned short)(offset << imap->im_boffset = (unsigned short)(offset <<
mp->m_sb.sb_inodelog); mp->m_sb.sb_inodelog);
return 0; error = 0;
goto out_drop;
} }
/* /*
...@@ -2408,10 +2364,10 @@ xfs_imap( ...@@ -2408,10 +2364,10 @@ xfs_imap(
offset_agbno = agbno & M_IGEO(mp)->inoalign_mask; offset_agbno = agbno & M_IGEO(mp)->inoalign_mask;
chunk_agbno = agbno - offset_agbno; chunk_agbno = agbno - offset_agbno;
} else { } else {
error = xfs_imap_lookup(mp, tp, agno, agino, agbno, error = xfs_imap_lookup(mp, tp, pag, agino, agbno,
&chunk_agbno, &offset_agbno, flags); &chunk_agbno, &offset_agbno, flags);
if (error) if (error)
return error; goto out_drop;
} }
out_map: out_map:
...@@ -2422,7 +2378,7 @@ xfs_imap( ...@@ -2422,7 +2378,7 @@ xfs_imap(
offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) +
XFS_INO_TO_OFFSET(mp, ino); XFS_INO_TO_OFFSET(mp, ino);
imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, cluster_agbno); imap->im_blkno = XFS_AGB_TO_DADDR(mp, pag->pag_agno, cluster_agbno);
imap->im_len = XFS_FSB_TO_BB(mp, M_IGEO(mp)->blocks_per_cluster); imap->im_len = XFS_FSB_TO_BB(mp, M_IGEO(mp)->blocks_per_cluster);
imap->im_boffset = (unsigned short)(offset << mp->m_sb.sb_inodelog); imap->im_boffset = (unsigned short)(offset << mp->m_sb.sb_inodelog);
...@@ -2439,9 +2395,13 @@ xfs_imap( ...@@ -2439,9 +2395,13 @@ xfs_imap(
__func__, (unsigned long long) imap->im_blkno, __func__, (unsigned long long) imap->im_blkno,
(unsigned long long) imap->im_len, (unsigned long long) imap->im_len,
XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)); XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks));
return -EINVAL; error = -EINVAL;
goto out_drop;
} }
return 0; error = 0;
out_drop:
xfs_perag_put(pag);
return error;
} }
/* /*
......
...@@ -33,42 +33,14 @@ xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o) ...@@ -33,42 +33,14 @@ xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o)
} }
/* /*
* Allocate an inode on disk. * Allocate an inode on disk. Mode is used to tell whether the new inode will
* Mode is used to tell whether the new inode will need space, and whether * need space, and whether it is a directory.
* it is a directory.
*
* There are two phases to inode allocation: selecting an AG and ensuring
* that it contains free inodes, followed by allocating one of the free
* inodes. xfs_dialloc_select_ag() does the former and returns a locked AGI
* to the caller, ensuring that followup call to xfs_dialloc_ag() will
* have free inodes to allocate from. xfs_dialloc_ag() will return the inode
* number of the free inode we allocated.
*/ */
int /* error */ int xfs_dialloc(struct xfs_trans **tpp, xfs_ino_t parent, umode_t mode,
xfs_dialloc_select_ag( xfs_ino_t *new_ino);
struct xfs_trans **tpp, /* double pointer of transaction */
xfs_ino_t parent, /* parent inode (directory) */
umode_t mode, /* mode bits for new inode */
struct xfs_buf **IO_agbp);
int
xfs_dialloc_ag(
struct xfs_trans *tp,
struct xfs_buf *agbp,
xfs_ino_t parent,
xfs_ino_t *inop);
/* int xfs_difree(struct xfs_trans *tp, struct xfs_perag *pag,
* Free disk inode. Carefully avoids touching the incore inode, all xfs_ino_t ino, struct xfs_icluster *ifree);
* manipulations incore are the caller's responsibility.
* The on-disk inode is not changed by this operation, only the
* btree (free inode mask) is changed.
*/
int /* error */
xfs_difree(
struct xfs_trans *tp, /* transaction pointer */
xfs_ino_t inode, /* inode to be freed */
struct xfs_icluster *ifree); /* cluster info if deleted */
/* /*
* Return the location of the inode in imap, for mapping it into a buffer. * Return the location of the inode in imap, for mapping it into a buffer.
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_rmap.h" #include "xfs_rmap.h"
#include "xfs_ag.h"
STATIC int STATIC int
xfs_inobt_get_minrecs( xfs_inobt_get_minrecs(
...@@ -34,8 +35,7 @@ xfs_inobt_dup_cursor( ...@@ -34,8 +35,7 @@ xfs_inobt_dup_cursor(
struct xfs_btree_cur *cur) struct xfs_btree_cur *cur)
{ {
return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp, return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
cur->bc_ag.agbp, cur->bc_ag.agno, cur->bc_ag.agbp, cur->bc_ag.pag, cur->bc_btnum);
cur->bc_btnum);
} }
STATIC void STATIC void
...@@ -102,7 +102,7 @@ __xfs_inobt_alloc_block( ...@@ -102,7 +102,7 @@ __xfs_inobt_alloc_block(
args.tp = cur->bc_tp; args.tp = cur->bc_tp;
args.mp = cur->bc_mp; args.mp = cur->bc_mp;
args.oinfo = XFS_RMAP_OINFO_INOBT; args.oinfo = XFS_RMAP_OINFO_INOBT;
args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_ag.agno, sbno); args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_ag.pag->pag_agno, sbno);
args.minlen = 1; args.minlen = 1;
args.maxlen = 1; args.maxlen = 1;
args.prod = 1; args.prod = 1;
...@@ -235,7 +235,7 @@ xfs_inobt_init_ptr_from_cur( ...@@ -235,7 +235,7 @@ xfs_inobt_init_ptr_from_cur(
{ {
struct xfs_agi *agi = cur->bc_ag.agbp->b_addr; struct xfs_agi *agi = cur->bc_ag.agbp->b_addr;
ASSERT(cur->bc_ag.agno == be32_to_cpu(agi->agi_seqno)); ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agi->agi_seqno));
ptr->s = agi->agi_root; ptr->s = agi->agi_root;
} }
...@@ -247,7 +247,7 @@ xfs_finobt_init_ptr_from_cur( ...@@ -247,7 +247,7 @@ xfs_finobt_init_ptr_from_cur(
{ {
struct xfs_agi *agi = cur->bc_ag.agbp->b_addr; struct xfs_agi *agi = cur->bc_ag.agbp->b_addr;
ASSERT(cur->bc_ag.agno == be32_to_cpu(agi->agi_seqno)); ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agi->agi_seqno));
ptr->s = agi->agi_free_root; ptr->s = agi->agi_free_root;
} }
...@@ -427,7 +427,7 @@ static struct xfs_btree_cur * ...@@ -427,7 +427,7 @@ static struct xfs_btree_cur *
xfs_inobt_init_common( xfs_inobt_init_common(
struct xfs_mount *mp, /* file system mount point */ struct xfs_mount *mp, /* file system mount point */
struct xfs_trans *tp, /* transaction pointer */ struct xfs_trans *tp, /* transaction pointer */
xfs_agnumber_t agno, /* allocation group number */ struct xfs_perag *pag,
xfs_btnum_t btnum) /* ialloc or free ino btree */ xfs_btnum_t btnum) /* ialloc or free ino btree */
{ {
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
...@@ -449,7 +449,9 @@ xfs_inobt_init_common( ...@@ -449,7 +449,9 @@ xfs_inobt_init_common(
if (xfs_sb_version_hascrc(&mp->m_sb)) if (xfs_sb_version_hascrc(&mp->m_sb))
cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
cur->bc_ag.agno = agno; /* take a reference for the cursor */
atomic_inc(&pag->pag_ref);
cur->bc_ag.pag = pag;
return cur; return cur;
} }
...@@ -459,13 +461,13 @@ xfs_inobt_init_cursor( ...@@ -459,13 +461,13 @@ xfs_inobt_init_cursor(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_buf *agbp, struct xfs_buf *agbp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_btnum_t btnum) xfs_btnum_t btnum)
{ {
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
struct xfs_agi *agi = agbp->b_addr; struct xfs_agi *agi = agbp->b_addr;
cur = xfs_inobt_init_common(mp, tp, agno, btnum); cur = xfs_inobt_init_common(mp, tp, pag, btnum);
if (btnum == XFS_BTNUM_INO) if (btnum == XFS_BTNUM_INO)
cur->bc_nlevels = be32_to_cpu(agi->agi_level); cur->bc_nlevels = be32_to_cpu(agi->agi_level);
else else
...@@ -479,12 +481,12 @@ struct xfs_btree_cur * ...@@ -479,12 +481,12 @@ struct xfs_btree_cur *
xfs_inobt_stage_cursor( xfs_inobt_stage_cursor(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xbtree_afakeroot *afake, struct xbtree_afakeroot *afake,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_btnum_t btnum) xfs_btnum_t btnum)
{ {
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
cur = xfs_inobt_init_common(mp, NULL, agno, btnum); cur = xfs_inobt_init_common(mp, NULL, pag, btnum);
xfs_btree_stage_afakeroot(cur, afake); xfs_btree_stage_afakeroot(cur, afake);
return cur; return cur;
} }
...@@ -656,7 +658,7 @@ int ...@@ -656,7 +658,7 @@ int
xfs_inobt_cur( xfs_inobt_cur(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_btnum_t which, xfs_btnum_t which,
struct xfs_btree_cur **curpp, struct xfs_btree_cur **curpp,
struct xfs_buf **agi_bpp) struct xfs_buf **agi_bpp)
...@@ -667,11 +669,11 @@ xfs_inobt_cur( ...@@ -667,11 +669,11 @@ xfs_inobt_cur(
ASSERT(*agi_bpp == NULL); ASSERT(*agi_bpp == NULL);
ASSERT(*curpp == NULL); ASSERT(*curpp == NULL);
error = xfs_ialloc_read_agi(mp, tp, agno, agi_bpp); error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, agi_bpp);
if (error) if (error)
return error; return error;
cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, agno, which); cur = xfs_inobt_init_cursor(mp, tp, *agi_bpp, pag, which);
*curpp = cur; *curpp = cur;
return 0; return 0;
} }
...@@ -680,7 +682,7 @@ static int ...@@ -680,7 +682,7 @@ static int
xfs_inobt_count_blocks( xfs_inobt_count_blocks(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_btnum_t btnum, xfs_btnum_t btnum,
xfs_extlen_t *tree_blocks) xfs_extlen_t *tree_blocks)
{ {
...@@ -688,7 +690,7 @@ xfs_inobt_count_blocks( ...@@ -688,7 +690,7 @@ xfs_inobt_count_blocks(
struct xfs_btree_cur *cur = NULL; struct xfs_btree_cur *cur = NULL;
int error; int error;
error = xfs_inobt_cur(mp, tp, agno, btnum, &cur, &agbp); error = xfs_inobt_cur(mp, tp, pag, btnum, &cur, &agbp);
if (error) if (error)
return error; return error;
...@@ -704,14 +706,14 @@ static int ...@@ -704,14 +706,14 @@ static int
xfs_finobt_read_blocks( xfs_finobt_read_blocks(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_extlen_t *tree_blocks) xfs_extlen_t *tree_blocks)
{ {
struct xfs_buf *agbp; struct xfs_buf *agbp;
struct xfs_agi *agi; struct xfs_agi *agi;
int error; int error;
error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); error = xfs_ialloc_read_agi(mp, tp, pag->pag_agno, &agbp);
if (error) if (error)
return error; return error;
...@@ -728,7 +730,7 @@ int ...@@ -728,7 +730,7 @@ int
xfs_finobt_calc_reserves( xfs_finobt_calc_reserves(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_extlen_t *ask, xfs_extlen_t *ask,
xfs_extlen_t *used) xfs_extlen_t *used)
{ {
...@@ -739,14 +741,14 @@ xfs_finobt_calc_reserves( ...@@ -739,14 +741,14 @@ xfs_finobt_calc_reserves(
return 0; return 0;
if (xfs_sb_version_hasinobtcounts(&mp->m_sb)) if (xfs_sb_version_hasinobtcounts(&mp->m_sb))
error = xfs_finobt_read_blocks(mp, tp, agno, &tree_len); error = xfs_finobt_read_blocks(mp, tp, pag, &tree_len);
else else
error = xfs_inobt_count_blocks(mp, tp, agno, XFS_BTNUM_FINO, error = xfs_inobt_count_blocks(mp, tp, pag, XFS_BTNUM_FINO,
&tree_len); &tree_len);
if (error) if (error)
return error; return error;
*ask += xfs_inobt_max_size(mp, agno); *ask += xfs_inobt_max_size(mp, pag->pag_agno);
*used += tree_len; *used += tree_len;
return 0; return 0;
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
struct xfs_buf; struct xfs_buf;
struct xfs_btree_cur; struct xfs_btree_cur;
struct xfs_mount; struct xfs_mount;
struct xfs_perag;
/* /*
* Btree block header size depends on a superblock flag. * Btree block header size depends on a superblock flag.
...@@ -45,11 +46,11 @@ struct xfs_mount; ...@@ -45,11 +46,11 @@ struct xfs_mount;
(maxrecs) * sizeof(xfs_inobt_key_t) + \ (maxrecs) * sizeof(xfs_inobt_key_t) + \
((index) - 1) * sizeof(xfs_inobt_ptr_t))) ((index) - 1) * sizeof(xfs_inobt_ptr_t)))
extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *, extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *mp,
struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t, struct xfs_trans *tp, struct xfs_buf *agbp,
xfs_btnum_t); struct xfs_perag *pag, xfs_btnum_t btnum);
struct xfs_btree_cur *xfs_inobt_stage_cursor(struct xfs_mount *mp, struct xfs_btree_cur *xfs_inobt_stage_cursor(struct xfs_mount *mp,
struct xbtree_afakeroot *afake, xfs_agnumber_t agno, struct xbtree_afakeroot *afake, struct xfs_perag *pag,
xfs_btnum_t btnum); xfs_btnum_t btnum);
extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int); extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int);
...@@ -64,11 +65,11 @@ int xfs_inobt_rec_check_count(struct xfs_mount *, ...@@ -64,11 +65,11 @@ int xfs_inobt_rec_check_count(struct xfs_mount *,
#endif /* DEBUG */ #endif /* DEBUG */
int xfs_finobt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp, int xfs_finobt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used); struct xfs_perag *pag, xfs_extlen_t *ask, xfs_extlen_t *used);
extern xfs_extlen_t xfs_iallocbt_calc_size(struct xfs_mount *mp, extern xfs_extlen_t xfs_iallocbt_calc_size(struct xfs_mount *mp,
unsigned long long len); unsigned long long len);
int xfs_inobt_cur(struct xfs_mount *mp, struct xfs_trans *tp, int xfs_inobt_cur(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_agnumber_t agno, xfs_btnum_t btnum, struct xfs_perag *pag, xfs_btnum_t btnum,
struct xfs_btree_cur **curpp, struct xfs_buf **agi_bpp); struct xfs_btree_cur **curpp, struct xfs_buf **agi_bpp);
void xfs_inobt_commit_staged_btree(struct xfs_btree_cur *cur, void xfs_inobt_commit_staged_btree(struct xfs_btree_cur *cur,
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "xfs_bit.h" #include "xfs_bit.h"
#include "xfs_refcount.h" #include "xfs_refcount.h"
#include "xfs_rmap.h" #include "xfs_rmap.h"
#include "xfs_ag.h"
/* Allowable refcount adjustment amounts. */ /* Allowable refcount adjustment amounts. */
enum xfs_refc_adjust_op { enum xfs_refc_adjust_op {
...@@ -46,7 +47,7 @@ xfs_refcount_lookup_le( ...@@ -46,7 +47,7 @@ xfs_refcount_lookup_le(
xfs_agblock_t bno, xfs_agblock_t bno,
int *stat) int *stat)
{ {
trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.agno, bno, trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno,
XFS_LOOKUP_LE); XFS_LOOKUP_LE);
cur->bc_rec.rc.rc_startblock = bno; cur->bc_rec.rc.rc_startblock = bno;
cur->bc_rec.rc.rc_blockcount = 0; cur->bc_rec.rc.rc_blockcount = 0;
...@@ -63,7 +64,7 @@ xfs_refcount_lookup_ge( ...@@ -63,7 +64,7 @@ xfs_refcount_lookup_ge(
xfs_agblock_t bno, xfs_agblock_t bno,
int *stat) int *stat)
{ {
trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.agno, bno, trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno,
XFS_LOOKUP_GE); XFS_LOOKUP_GE);
cur->bc_rec.rc.rc_startblock = bno; cur->bc_rec.rc.rc_startblock = bno;
cur->bc_rec.rc.rc_blockcount = 0; cur->bc_rec.rc.rc_blockcount = 0;
...@@ -80,7 +81,7 @@ xfs_refcount_lookup_eq( ...@@ -80,7 +81,7 @@ xfs_refcount_lookup_eq(
xfs_agblock_t bno, xfs_agblock_t bno,
int *stat) int *stat)
{ {
trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.agno, bno, trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_ag.pag->pag_agno, bno,
XFS_LOOKUP_LE); XFS_LOOKUP_LE);
cur->bc_rec.rc.rc_startblock = bno; cur->bc_rec.rc.rc_startblock = bno;
cur->bc_rec.rc.rc_blockcount = 0; cur->bc_rec.rc.rc_blockcount = 0;
...@@ -108,7 +109,7 @@ xfs_refcount_get_rec( ...@@ -108,7 +109,7 @@ xfs_refcount_get_rec(
int *stat) int *stat)
{ {
struct xfs_mount *mp = cur->bc_mp; struct xfs_mount *mp = cur->bc_mp;
xfs_agnumber_t agno = cur->bc_ag.agno; xfs_agnumber_t agno = cur->bc_ag.pag->pag_agno;
union xfs_btree_rec *rec; union xfs_btree_rec *rec;
int error; int error;
xfs_agblock_t realstart; xfs_agblock_t realstart;
...@@ -119,7 +120,7 @@ xfs_refcount_get_rec( ...@@ -119,7 +120,7 @@ xfs_refcount_get_rec(
xfs_refcount_btrec_to_irec(rec, irec); xfs_refcount_btrec_to_irec(rec, irec);
agno = cur->bc_ag.agno; agno = cur->bc_ag.pag->pag_agno;
if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN) if (irec->rc_blockcount == 0 || irec->rc_blockcount > MAXREFCEXTLEN)
goto out_bad_rec; goto out_bad_rec;
...@@ -144,7 +145,7 @@ xfs_refcount_get_rec( ...@@ -144,7 +145,7 @@ xfs_refcount_get_rec(
if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT) if (irec->rc_refcount == 0 || irec->rc_refcount > MAXREFCOUNT)
goto out_bad_rec; goto out_bad_rec;
trace_xfs_refcount_get(cur->bc_mp, cur->bc_ag.agno, irec); trace_xfs_refcount_get(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
return 0; return 0;
out_bad_rec: out_bad_rec:
...@@ -169,14 +170,14 @@ xfs_refcount_update( ...@@ -169,14 +170,14 @@ xfs_refcount_update(
union xfs_btree_rec rec; union xfs_btree_rec rec;
int error; int error;
trace_xfs_refcount_update(cur->bc_mp, cur->bc_ag.agno, irec); trace_xfs_refcount_update(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
rec.refc.rc_startblock = cpu_to_be32(irec->rc_startblock); rec.refc.rc_startblock = cpu_to_be32(irec->rc_startblock);
rec.refc.rc_blockcount = cpu_to_be32(irec->rc_blockcount); rec.refc.rc_blockcount = cpu_to_be32(irec->rc_blockcount);
rec.refc.rc_refcount = cpu_to_be32(irec->rc_refcount); rec.refc.rc_refcount = cpu_to_be32(irec->rc_refcount);
error = xfs_btree_update(cur, &rec); error = xfs_btree_update(cur, &rec);
if (error) if (error)
trace_xfs_refcount_update_error(cur->bc_mp, trace_xfs_refcount_update_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -193,7 +194,7 @@ xfs_refcount_insert( ...@@ -193,7 +194,7 @@ xfs_refcount_insert(
{ {
int error; int error;
trace_xfs_refcount_insert(cur->bc_mp, cur->bc_ag.agno, irec); trace_xfs_refcount_insert(cur->bc_mp, cur->bc_ag.pag->pag_agno, irec);
cur->bc_rec.rc.rc_startblock = irec->rc_startblock; cur->bc_rec.rc.rc_startblock = irec->rc_startblock;
cur->bc_rec.rc.rc_blockcount = irec->rc_blockcount; cur->bc_rec.rc.rc_blockcount = irec->rc_blockcount;
cur->bc_rec.rc.rc_refcount = irec->rc_refcount; cur->bc_rec.rc.rc_refcount = irec->rc_refcount;
...@@ -208,7 +209,7 @@ xfs_refcount_insert( ...@@ -208,7 +209,7 @@ xfs_refcount_insert(
out_error: out_error:
if (error) if (error)
trace_xfs_refcount_insert_error(cur->bc_mp, trace_xfs_refcount_insert_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -234,7 +235,7 @@ xfs_refcount_delete( ...@@ -234,7 +235,7 @@ xfs_refcount_delete(
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
goto out_error; goto out_error;
} }
trace_xfs_refcount_delete(cur->bc_mp, cur->bc_ag.agno, &irec); trace_xfs_refcount_delete(cur->bc_mp, cur->bc_ag.pag->pag_agno, &irec);
error = xfs_btree_delete(cur, i); error = xfs_btree_delete(cur, i);
if (XFS_IS_CORRUPT(cur->bc_mp, *i != 1)) { if (XFS_IS_CORRUPT(cur->bc_mp, *i != 1)) {
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
...@@ -246,7 +247,7 @@ xfs_refcount_delete( ...@@ -246,7 +247,7 @@ xfs_refcount_delete(
out_error: out_error:
if (error) if (error)
trace_xfs_refcount_delete_error(cur->bc_mp, trace_xfs_refcount_delete_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -366,7 +367,7 @@ xfs_refcount_split_extent( ...@@ -366,7 +367,7 @@ xfs_refcount_split_extent(
return 0; return 0;
*shape_changed = true; *shape_changed = true;
trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_ag.agno, trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno,
&rcext, agbno); &rcext, agbno);
/* Establish the right extent. */ /* Establish the right extent. */
...@@ -391,7 +392,7 @@ xfs_refcount_split_extent( ...@@ -391,7 +392,7 @@ xfs_refcount_split_extent(
out_error: out_error:
trace_xfs_refcount_split_extent_error(cur->bc_mp, trace_xfs_refcount_split_extent_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -411,7 +412,7 @@ xfs_refcount_merge_center_extents( ...@@ -411,7 +412,7 @@ xfs_refcount_merge_center_extents(
int found_rec; int found_rec;
trace_xfs_refcount_merge_center_extents(cur->bc_mp, trace_xfs_refcount_merge_center_extents(cur->bc_mp,
cur->bc_ag.agno, left, center, right); cur->bc_ag.pag->pag_agno, left, center, right);
/* /*
* Make sure the center and right extents are not in the btree. * Make sure the center and right extents are not in the btree.
...@@ -468,7 +469,7 @@ xfs_refcount_merge_center_extents( ...@@ -468,7 +469,7 @@ xfs_refcount_merge_center_extents(
out_error: out_error:
trace_xfs_refcount_merge_center_extents_error(cur->bc_mp, trace_xfs_refcount_merge_center_extents_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -487,7 +488,7 @@ xfs_refcount_merge_left_extent( ...@@ -487,7 +488,7 @@ xfs_refcount_merge_left_extent(
int found_rec; int found_rec;
trace_xfs_refcount_merge_left_extent(cur->bc_mp, trace_xfs_refcount_merge_left_extent(cur->bc_mp,
cur->bc_ag.agno, left, cleft); cur->bc_ag.pag->pag_agno, left, cleft);
/* If the extent at agbno (cleft) wasn't synthesized, remove it. */ /* If the extent at agbno (cleft) wasn't synthesized, remove it. */
if (cleft->rc_refcount > 1) { if (cleft->rc_refcount > 1) {
...@@ -530,7 +531,7 @@ xfs_refcount_merge_left_extent( ...@@ -530,7 +531,7 @@ xfs_refcount_merge_left_extent(
out_error: out_error:
trace_xfs_refcount_merge_left_extent_error(cur->bc_mp, trace_xfs_refcount_merge_left_extent_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -548,7 +549,7 @@ xfs_refcount_merge_right_extent( ...@@ -548,7 +549,7 @@ xfs_refcount_merge_right_extent(
int found_rec; int found_rec;
trace_xfs_refcount_merge_right_extent(cur->bc_mp, trace_xfs_refcount_merge_right_extent(cur->bc_mp,
cur->bc_ag.agno, cright, right); cur->bc_ag.pag->pag_agno, cright, right);
/* /*
* If the extent ending at agbno+aglen (cright) wasn't synthesized, * If the extent ending at agbno+aglen (cright) wasn't synthesized,
...@@ -594,7 +595,7 @@ xfs_refcount_merge_right_extent( ...@@ -594,7 +595,7 @@ xfs_refcount_merge_right_extent(
out_error: out_error:
trace_xfs_refcount_merge_right_extent_error(cur->bc_mp, trace_xfs_refcount_merge_right_extent_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -679,13 +680,13 @@ xfs_refcount_find_left_extents( ...@@ -679,13 +680,13 @@ xfs_refcount_find_left_extents(
cleft->rc_blockcount = aglen; cleft->rc_blockcount = aglen;
cleft->rc_refcount = 1; cleft->rc_refcount = 1;
} }
trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_ag.agno, trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno,
left, cleft, agbno); left, cleft, agbno);
return error; return error;
out_error: out_error:
trace_xfs_refcount_find_left_extent_error(cur->bc_mp, trace_xfs_refcount_find_left_extent_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -768,13 +769,13 @@ xfs_refcount_find_right_extents( ...@@ -768,13 +769,13 @@ xfs_refcount_find_right_extents(
cright->rc_blockcount = aglen; cright->rc_blockcount = aglen;
cright->rc_refcount = 1; cright->rc_refcount = 1;
} }
trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_ag.agno, trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_ag.pag->pag_agno,
cright, right, agbno + aglen); cright, right, agbno + aglen);
return error; return error;
out_error: out_error:
trace_xfs_refcount_find_right_extent_error(cur->bc_mp, trace_xfs_refcount_find_right_extent_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -952,7 +953,7 @@ xfs_refcount_adjust_extents( ...@@ -952,7 +953,7 @@ xfs_refcount_adjust_extents(
ext.rc_startblock - *agbno); ext.rc_startblock - *agbno);
tmp.rc_refcount = 1 + adj; tmp.rc_refcount = 1 + adj;
trace_xfs_refcount_modify_extent(cur->bc_mp, trace_xfs_refcount_modify_extent(cur->bc_mp,
cur->bc_ag.agno, &tmp); cur->bc_ag.pag->pag_agno, &tmp);
/* /*
* Either cover the hole (increment) or * Either cover the hole (increment) or
...@@ -971,7 +972,7 @@ xfs_refcount_adjust_extents( ...@@ -971,7 +972,7 @@ xfs_refcount_adjust_extents(
cur->bc_ag.refc.nr_ops++; cur->bc_ag.refc.nr_ops++;
} else { } else {
fsbno = XFS_AGB_TO_FSB(cur->bc_mp, fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
cur->bc_ag.agno, cur->bc_ag.pag->pag_agno,
tmp.rc_startblock); tmp.rc_startblock);
xfs_bmap_add_free(cur->bc_tp, fsbno, xfs_bmap_add_free(cur->bc_tp, fsbno,
tmp.rc_blockcount, oinfo); tmp.rc_blockcount, oinfo);
...@@ -998,7 +999,7 @@ xfs_refcount_adjust_extents( ...@@ -998,7 +999,7 @@ xfs_refcount_adjust_extents(
goto skip; goto skip;
ext.rc_refcount += adj; ext.rc_refcount += adj;
trace_xfs_refcount_modify_extent(cur->bc_mp, trace_xfs_refcount_modify_extent(cur->bc_mp,
cur->bc_ag.agno, &ext); cur->bc_ag.pag->pag_agno, &ext);
if (ext.rc_refcount > 1) { if (ext.rc_refcount > 1) {
error = xfs_refcount_update(cur, &ext); error = xfs_refcount_update(cur, &ext);
if (error) if (error)
...@@ -1016,7 +1017,7 @@ xfs_refcount_adjust_extents( ...@@ -1016,7 +1017,7 @@ xfs_refcount_adjust_extents(
goto advloop; goto advloop;
} else { } else {
fsbno = XFS_AGB_TO_FSB(cur->bc_mp, fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
cur->bc_ag.agno, cur->bc_ag.pag->pag_agno,
ext.rc_startblock); ext.rc_startblock);
xfs_bmap_add_free(cur->bc_tp, fsbno, ext.rc_blockcount, xfs_bmap_add_free(cur->bc_tp, fsbno, ext.rc_blockcount,
oinfo); oinfo);
...@@ -1035,7 +1036,7 @@ xfs_refcount_adjust_extents( ...@@ -1035,7 +1036,7 @@ xfs_refcount_adjust_extents(
return error; return error;
out_error: out_error:
trace_xfs_refcount_modify_extent_error(cur->bc_mp, trace_xfs_refcount_modify_extent_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -1057,10 +1058,10 @@ xfs_refcount_adjust( ...@@ -1057,10 +1058,10 @@ xfs_refcount_adjust(
*new_agbno = agbno; *new_agbno = agbno;
*new_aglen = aglen; *new_aglen = aglen;
if (adj == XFS_REFCOUNT_ADJUST_INCREASE) if (adj == XFS_REFCOUNT_ADJUST_INCREASE)
trace_xfs_refcount_increase(cur->bc_mp, cur->bc_ag.agno, trace_xfs_refcount_increase(cur->bc_mp, cur->bc_ag.pag->pag_agno,
agbno, aglen); agbno, aglen);
else else
trace_xfs_refcount_decrease(cur->bc_mp, cur->bc_ag.agno, trace_xfs_refcount_decrease(cur->bc_mp, cur->bc_ag.pag->pag_agno,
agbno, aglen); agbno, aglen);
/* /*
...@@ -1099,7 +1100,7 @@ xfs_refcount_adjust( ...@@ -1099,7 +1100,7 @@ xfs_refcount_adjust(
return 0; return 0;
out_error: out_error:
trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_ag.agno, trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_ag.pag->pag_agno,
error, _RET_IP_); error, _RET_IP_);
return error; return error;
} }
...@@ -1142,30 +1143,30 @@ xfs_refcount_finish_one( ...@@ -1142,30 +1143,30 @@ xfs_refcount_finish_one(
struct xfs_btree_cur *rcur; struct xfs_btree_cur *rcur;
struct xfs_buf *agbp = NULL; struct xfs_buf *agbp = NULL;
int error = 0; int error = 0;
xfs_agnumber_t agno;
xfs_agblock_t bno; xfs_agblock_t bno;
xfs_agblock_t new_agbno; xfs_agblock_t new_agbno;
unsigned long nr_ops = 0; unsigned long nr_ops = 0;
int shape_changes = 0; int shape_changes = 0;
struct xfs_perag *pag;
agno = XFS_FSB_TO_AGNO(mp, startblock); pag = xfs_perag_get(mp, XFS_FSB_TO_AGNO(mp, startblock));
ASSERT(agno != NULLAGNUMBER);
bno = XFS_FSB_TO_AGBNO(mp, startblock); bno = XFS_FSB_TO_AGBNO(mp, startblock);
trace_xfs_refcount_deferred(mp, XFS_FSB_TO_AGNO(mp, startblock), trace_xfs_refcount_deferred(mp, XFS_FSB_TO_AGNO(mp, startblock),
type, XFS_FSB_TO_AGBNO(mp, startblock), type, XFS_FSB_TO_AGBNO(mp, startblock),
blockcount); blockcount);
if (XFS_TEST_ERROR(false, mp, if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_REFCOUNT_FINISH_ONE)) {
XFS_ERRTAG_REFCOUNT_FINISH_ONE)) error = -EIO;
return -EIO; goto out_drop;
}
/* /*
* If we haven't gotten a cursor or the cursor AG doesn't match * If we haven't gotten a cursor or the cursor AG doesn't match
* the startblock, get one now. * the startblock, get one now.
*/ */
rcur = *pcur; rcur = *pcur;
if (rcur != NULL && rcur->bc_ag.agno != agno) { if (rcur != NULL && rcur->bc_ag.pag != pag) {
nr_ops = rcur->bc_ag.refc.nr_ops; nr_ops = rcur->bc_ag.refc.nr_ops;
shape_changes = rcur->bc_ag.refc.shape_changes; shape_changes = rcur->bc_ag.refc.shape_changes;
xfs_refcount_finish_one_cleanup(tp, rcur, 0); xfs_refcount_finish_one_cleanup(tp, rcur, 0);
...@@ -1173,12 +1174,12 @@ xfs_refcount_finish_one( ...@@ -1173,12 +1174,12 @@ xfs_refcount_finish_one(
*pcur = NULL; *pcur = NULL;
} }
if (rcur == NULL) { if (rcur == NULL) {
error = xfs_alloc_read_agf(tp->t_mountp, tp, agno, error = xfs_alloc_read_agf(tp->t_mountp, tp, pag->pag_agno,
XFS_ALLOC_FLAG_FREEING, &agbp); XFS_ALLOC_FLAG_FREEING, &agbp);
if (error) if (error)
return error; goto out_drop;
rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno); rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag);
rcur->bc_ag.refc.nr_ops = nr_ops; rcur->bc_ag.refc.nr_ops = nr_ops;
rcur->bc_ag.refc.shape_changes = shape_changes; rcur->bc_ag.refc.shape_changes = shape_changes;
} }
...@@ -1188,12 +1189,12 @@ xfs_refcount_finish_one( ...@@ -1188,12 +1189,12 @@ xfs_refcount_finish_one(
case XFS_REFCOUNT_INCREASE: case XFS_REFCOUNT_INCREASE:
error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno, error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno,
new_len, XFS_REFCOUNT_ADJUST_INCREASE, NULL); new_len, XFS_REFCOUNT_ADJUST_INCREASE, NULL);
*new_fsb = XFS_AGB_TO_FSB(mp, agno, new_agbno); *new_fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno);
break; break;
case XFS_REFCOUNT_DECREASE: case XFS_REFCOUNT_DECREASE:
error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno, error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno,
new_len, XFS_REFCOUNT_ADJUST_DECREASE, NULL); new_len, XFS_REFCOUNT_ADJUST_DECREASE, NULL);
*new_fsb = XFS_AGB_TO_FSB(mp, agno, new_agbno); *new_fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, new_agbno);
break; break;
case XFS_REFCOUNT_ALLOC_COW: case XFS_REFCOUNT_ALLOC_COW:
*new_fsb = startblock + blockcount; *new_fsb = startblock + blockcount;
...@@ -1210,8 +1211,10 @@ xfs_refcount_finish_one( ...@@ -1210,8 +1211,10 @@ xfs_refcount_finish_one(
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
} }
if (!error && *new_len > 0) if (!error && *new_len > 0)
trace_xfs_refcount_finish_one_leftover(mp, agno, type, trace_xfs_refcount_finish_one_leftover(mp, pag->pag_agno, type,
bno, blockcount, new_agbno, *new_len); bno, blockcount, new_agbno, *new_len);
out_drop:
xfs_perag_put(pag);
return error; return error;
} }
...@@ -1294,7 +1297,7 @@ xfs_refcount_find_shared( ...@@ -1294,7 +1297,7 @@ xfs_refcount_find_shared(
int have; int have;
int error; int error;
trace_xfs_refcount_find_shared(cur->bc_mp, cur->bc_ag.agno, trace_xfs_refcount_find_shared(cur->bc_mp, cur->bc_ag.pag->pag_agno,
agbno, aglen); agbno, aglen);
/* By default, skip the whole range */ /* By default, skip the whole range */
...@@ -1374,12 +1377,12 @@ xfs_refcount_find_shared( ...@@ -1374,12 +1377,12 @@ xfs_refcount_find_shared(
done: done:
trace_xfs_refcount_find_shared_result(cur->bc_mp, trace_xfs_refcount_find_shared_result(cur->bc_mp,
cur->bc_ag.agno, *fbno, *flen); cur->bc_ag.pag->pag_agno, *fbno, *flen);
out_error: out_error:
if (error) if (error)
trace_xfs_refcount_find_shared_error(cur->bc_mp, trace_xfs_refcount_find_shared_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -1476,7 +1479,7 @@ xfs_refcount_adjust_cow_extents( ...@@ -1476,7 +1479,7 @@ xfs_refcount_adjust_cow_extents(
tmp.rc_blockcount = aglen; tmp.rc_blockcount = aglen;
tmp.rc_refcount = 1; tmp.rc_refcount = 1;
trace_xfs_refcount_modify_extent(cur->bc_mp, trace_xfs_refcount_modify_extent(cur->bc_mp,
cur->bc_ag.agno, &tmp); cur->bc_ag.pag->pag_agno, &tmp);
error = xfs_refcount_insert(cur, &tmp, error = xfs_refcount_insert(cur, &tmp,
&found_tmp); &found_tmp);
...@@ -1504,7 +1507,7 @@ xfs_refcount_adjust_cow_extents( ...@@ -1504,7 +1507,7 @@ xfs_refcount_adjust_cow_extents(
ext.rc_refcount = 0; ext.rc_refcount = 0;
trace_xfs_refcount_modify_extent(cur->bc_mp, trace_xfs_refcount_modify_extent(cur->bc_mp,
cur->bc_ag.agno, &ext); cur->bc_ag.pag->pag_agno, &ext);
error = xfs_refcount_delete(cur, &found_rec); error = xfs_refcount_delete(cur, &found_rec);
if (error) if (error)
goto out_error; goto out_error;
...@@ -1520,7 +1523,7 @@ xfs_refcount_adjust_cow_extents( ...@@ -1520,7 +1523,7 @@ xfs_refcount_adjust_cow_extents(
return error; return error;
out_error: out_error:
trace_xfs_refcount_modify_extent_error(cur->bc_mp, trace_xfs_refcount_modify_extent_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -1566,7 +1569,7 @@ xfs_refcount_adjust_cow( ...@@ -1566,7 +1569,7 @@ xfs_refcount_adjust_cow(
return 0; return 0;
out_error: out_error:
trace_xfs_refcount_adjust_cow_error(cur->bc_mp, cur->bc_ag.agno, trace_xfs_refcount_adjust_cow_error(cur->bc_mp, cur->bc_ag.pag->pag_agno,
error, _RET_IP_); error, _RET_IP_);
return error; return error;
} }
...@@ -1580,7 +1583,7 @@ __xfs_refcount_cow_alloc( ...@@ -1580,7 +1583,7 @@ __xfs_refcount_cow_alloc(
xfs_agblock_t agbno, xfs_agblock_t agbno,
xfs_extlen_t aglen) xfs_extlen_t aglen)
{ {
trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_ag.agno, trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_ag.pag->pag_agno,
agbno, aglen); agbno, aglen);
/* Add refcount btree reservation */ /* Add refcount btree reservation */
...@@ -1597,7 +1600,7 @@ __xfs_refcount_cow_free( ...@@ -1597,7 +1600,7 @@ __xfs_refcount_cow_free(
xfs_agblock_t agbno, xfs_agblock_t agbno,
xfs_extlen_t aglen) xfs_extlen_t aglen)
{ {
trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_ag.agno, trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_ag.pag->pag_agno,
agbno, aglen); agbno, aglen);
/* Remove refcount btree reservation */ /* Remove refcount btree reservation */
...@@ -1672,7 +1675,7 @@ xfs_refcount_recover_extent( ...@@ -1672,7 +1675,7 @@ xfs_refcount_recover_extent(
int int
xfs_refcount_recover_cow_leftovers( xfs_refcount_recover_cow_leftovers(
struct xfs_mount *mp, struct xfs_mount *mp,
xfs_agnumber_t agno) struct xfs_perag *pag)
{ {
struct xfs_trans *tp; struct xfs_trans *tp;
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
...@@ -1704,10 +1707,10 @@ xfs_refcount_recover_cow_leftovers( ...@@ -1704,10 +1707,10 @@ xfs_refcount_recover_cow_leftovers(
if (error) if (error)
return error; return error;
error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0, &agbp);
if (error) if (error)
goto out_trans; goto out_trans;
cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno); cur = xfs_refcountbt_init_cursor(mp, tp, agbp, pag);
/* Find all the leftover CoW staging extents. */ /* Find all the leftover CoW staging extents. */
memset(&low, 0, sizeof(low)); memset(&low, 0, sizeof(low));
...@@ -1729,11 +1732,12 @@ xfs_refcount_recover_cow_leftovers( ...@@ -1729,11 +1732,12 @@ xfs_refcount_recover_cow_leftovers(
if (error) if (error)
goto out_free; goto out_free;
trace_xfs_refcount_recover_extent(mp, agno, &rr->rr_rrec); trace_xfs_refcount_recover_extent(mp, pag->pag_agno,
&rr->rr_rrec);
/* Free the orphan record */ /* Free the orphan record */
agbno = rr->rr_rrec.rc_startblock - XFS_REFC_COW_START; agbno = rr->rr_rrec.rc_startblock - XFS_REFC_COW_START;
fsb = XFS_AGB_TO_FSB(mp, agno, agbno); fsb = XFS_AGB_TO_FSB(mp, pag->pag_agno, agbno);
xfs_refcount_free_cow_extent(tp, fsb, xfs_refcount_free_cow_extent(tp, fsb,
rr->rr_rrec.rc_blockcount); rr->rr_rrec.rc_blockcount);
......
...@@ -6,6 +6,13 @@ ...@@ -6,6 +6,13 @@
#ifndef __XFS_REFCOUNT_H__ #ifndef __XFS_REFCOUNT_H__
#define __XFS_REFCOUNT_H__ #define __XFS_REFCOUNT_H__
struct xfs_trans;
struct xfs_mount;
struct xfs_perag;
struct xfs_btree_cur;
struct xfs_bmbt_irec;
struct xfs_refcount_irec;
extern int xfs_refcount_lookup_le(struct xfs_btree_cur *cur, extern int xfs_refcount_lookup_le(struct xfs_btree_cur *cur,
xfs_agblock_t bno, int *stat); xfs_agblock_t bno, int *stat);
extern int xfs_refcount_lookup_ge(struct xfs_btree_cur *cur, extern int xfs_refcount_lookup_ge(struct xfs_btree_cur *cur,
...@@ -50,7 +57,7 @@ void xfs_refcount_alloc_cow_extent(struct xfs_trans *tp, xfs_fsblock_t fsb, ...@@ -50,7 +57,7 @@ void xfs_refcount_alloc_cow_extent(struct xfs_trans *tp, xfs_fsblock_t fsb,
void xfs_refcount_free_cow_extent(struct xfs_trans *tp, xfs_fsblock_t fsb, void xfs_refcount_free_cow_extent(struct xfs_trans *tp, xfs_fsblock_t fsb,
xfs_extlen_t len); xfs_extlen_t len);
extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp, extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp,
xfs_agnumber_t agno); struct xfs_perag *pag);
/* /*
* While we're adjusting the refcounts records of an extent, we have * While we're adjusting the refcounts records of an extent, we have
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include "xfs_format.h" #include "xfs_format.h"
#include "xfs_log_format.h" #include "xfs_log_format.h"
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_sb.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_btree.h" #include "xfs_btree.h"
#include "xfs_btree_staging.h" #include "xfs_btree_staging.h"
...@@ -20,13 +19,14 @@ ...@@ -20,13 +19,14 @@
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_bit.h" #include "xfs_bit.h"
#include "xfs_rmap.h" #include "xfs_rmap.h"
#include "xfs_ag.h"
static struct xfs_btree_cur * static struct xfs_btree_cur *
xfs_refcountbt_dup_cursor( xfs_refcountbt_dup_cursor(
struct xfs_btree_cur *cur) struct xfs_btree_cur *cur)
{ {
return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp, return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp,
cur->bc_ag.agbp, cur->bc_ag.agno); cur->bc_ag.agbp, cur->bc_ag.pag);
} }
STATIC void STATIC void
...@@ -65,7 +65,7 @@ xfs_refcountbt_alloc_block( ...@@ -65,7 +65,7 @@ xfs_refcountbt_alloc_block(
args.tp = cur->bc_tp; args.tp = cur->bc_tp;
args.mp = cur->bc_mp; args.mp = cur->bc_mp;
args.type = XFS_ALLOCTYPE_NEAR_BNO; args.type = XFS_ALLOCTYPE_NEAR_BNO;
args.fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.agno, args.fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.pag->pag_agno,
xfs_refc_block(args.mp)); xfs_refc_block(args.mp));
args.oinfo = XFS_RMAP_OINFO_REFC; args.oinfo = XFS_RMAP_OINFO_REFC;
args.minlen = args.maxlen = args.prod = 1; args.minlen = args.maxlen = args.prod = 1;
...@@ -74,13 +74,13 @@ xfs_refcountbt_alloc_block( ...@@ -74,13 +74,13 @@ xfs_refcountbt_alloc_block(
error = xfs_alloc_vextent(&args); error = xfs_alloc_vextent(&args);
if (error) if (error)
goto out_error; goto out_error;
trace_xfs_refcountbt_alloc_block(cur->bc_mp, cur->bc_ag.agno, trace_xfs_refcountbt_alloc_block(cur->bc_mp, cur->bc_ag.pag->pag_agno,
args.agbno, 1); args.agbno, 1);
if (args.fsbno == NULLFSBLOCK) { if (args.fsbno == NULLFSBLOCK) {
*stat = 0; *stat = 0;
return 0; return 0;
} }
ASSERT(args.agno == cur->bc_ag.agno); ASSERT(args.agno == cur->bc_ag.pag->pag_agno);
ASSERT(args.len == 1); ASSERT(args.len == 1);
new->s = cpu_to_be32(args.agbno); new->s = cpu_to_be32(args.agbno);
...@@ -105,7 +105,7 @@ xfs_refcountbt_free_block( ...@@ -105,7 +105,7 @@ xfs_refcountbt_free_block(
xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp)); xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp));
int error; int error;
trace_xfs_refcountbt_free_block(cur->bc_mp, cur->bc_ag.agno, trace_xfs_refcountbt_free_block(cur->bc_mp, cur->bc_ag.pag->pag_agno,
XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1); XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1);
be32_add_cpu(&agf->agf_refcount_blocks, -1); be32_add_cpu(&agf->agf_refcount_blocks, -1);
xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS);
...@@ -170,7 +170,7 @@ xfs_refcountbt_init_ptr_from_cur( ...@@ -170,7 +170,7 @@ xfs_refcountbt_init_ptr_from_cur(
{ {
struct xfs_agf *agf = cur->bc_ag.agbp->b_addr; struct xfs_agf *agf = cur->bc_ag.agbp->b_addr;
ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno)); ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno));
ptr->s = agf->agf_refcount_root; ptr->s = agf->agf_refcount_root;
} }
...@@ -316,12 +316,11 @@ static struct xfs_btree_cur * ...@@ -316,12 +316,11 @@ static struct xfs_btree_cur *
xfs_refcountbt_init_common( xfs_refcountbt_init_common(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno) struct xfs_perag *pag)
{ {
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
ASSERT(agno != NULLAGNUMBER); ASSERT(pag->pag_agno < mp->m_sb.sb_agcount);
ASSERT(agno < mp->m_sb.sb_agcount);
cur = kmem_cache_zalloc(xfs_btree_cur_zone, GFP_NOFS | __GFP_NOFAIL); cur = kmem_cache_zalloc(xfs_btree_cur_zone, GFP_NOFS | __GFP_NOFAIL);
cur->bc_tp = tp; cur->bc_tp = tp;
...@@ -330,9 +329,12 @@ xfs_refcountbt_init_common( ...@@ -330,9 +329,12 @@ xfs_refcountbt_init_common(
cur->bc_blocklog = mp->m_sb.sb_blocklog; cur->bc_blocklog = mp->m_sb.sb_blocklog;
cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_refcbt_2); cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_refcbt_2);
cur->bc_ag.agno = agno;
cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;
/* take a reference for the cursor */
atomic_inc(&pag->pag_ref);
cur->bc_ag.pag = pag;
cur->bc_ag.refc.nr_ops = 0; cur->bc_ag.refc.nr_ops = 0;
cur->bc_ag.refc.shape_changes = 0; cur->bc_ag.refc.shape_changes = 0;
cur->bc_ops = &xfs_refcountbt_ops; cur->bc_ops = &xfs_refcountbt_ops;
...@@ -345,12 +347,12 @@ xfs_refcountbt_init_cursor( ...@@ -345,12 +347,12 @@ xfs_refcountbt_init_cursor(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_buf *agbp, struct xfs_buf *agbp,
xfs_agnumber_t agno) struct xfs_perag *pag)
{ {
struct xfs_agf *agf = agbp->b_addr; struct xfs_agf *agf = agbp->b_addr;
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
cur = xfs_refcountbt_init_common(mp, tp, agno); cur = xfs_refcountbt_init_common(mp, tp, pag);
cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level); cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level);
cur->bc_ag.agbp = agbp; cur->bc_ag.agbp = agbp;
return cur; return cur;
...@@ -361,11 +363,11 @@ struct xfs_btree_cur * ...@@ -361,11 +363,11 @@ struct xfs_btree_cur *
xfs_refcountbt_stage_cursor( xfs_refcountbt_stage_cursor(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xbtree_afakeroot *afake, struct xbtree_afakeroot *afake,
xfs_agnumber_t agno) struct xfs_perag *pag)
{ {
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
cur = xfs_refcountbt_init_common(mp, NULL, agno); cur = xfs_refcountbt_init_common(mp, NULL, pag);
xfs_btree_stage_afakeroot(cur, afake); xfs_btree_stage_afakeroot(cur, afake);
return cur; return cur;
} }
...@@ -450,7 +452,7 @@ int ...@@ -450,7 +452,7 @@ int
xfs_refcountbt_calc_reserves( xfs_refcountbt_calc_reserves(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_extlen_t *ask, xfs_extlen_t *ask,
xfs_extlen_t *used) xfs_extlen_t *used)
{ {
...@@ -463,8 +465,7 @@ xfs_refcountbt_calc_reserves( ...@@ -463,8 +465,7 @@ xfs_refcountbt_calc_reserves(
if (!xfs_sb_version_hasreflink(&mp->m_sb)) if (!xfs_sb_version_hasreflink(&mp->m_sb))
return 0; return 0;
error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0, &agbp);
error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
if (error) if (error)
return error; return error;
...@@ -479,7 +480,7 @@ xfs_refcountbt_calc_reserves( ...@@ -479,7 +480,7 @@ xfs_refcountbt_calc_reserves(
* expansion. We therefore can pretend the space isn't there. * expansion. We therefore can pretend the space isn't there.
*/ */
if (mp->m_sb.sb_logstart && if (mp->m_sb.sb_logstart &&
XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == agno) XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == pag->pag_agno)
agblocks -= mp->m_sb.sb_logblocks; agblocks -= mp->m_sb.sb_logblocks;
*ask += xfs_refcountbt_max_size(mp, agblocks); *ask += xfs_refcountbt_max_size(mp, agblocks);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
struct xfs_buf; struct xfs_buf;
struct xfs_btree_cur; struct xfs_btree_cur;
struct xfs_mount; struct xfs_mount;
struct xfs_perag;
struct xbtree_afakeroot; struct xbtree_afakeroot;
/* /*
...@@ -46,9 +47,9 @@ struct xbtree_afakeroot; ...@@ -46,9 +47,9 @@ struct xbtree_afakeroot;
extern struct xfs_btree_cur *xfs_refcountbt_init_cursor(struct xfs_mount *mp, extern struct xfs_btree_cur *xfs_refcountbt_init_cursor(struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_buf *agbp, struct xfs_trans *tp, struct xfs_buf *agbp,
xfs_agnumber_t agno); struct xfs_perag *pag);
struct xfs_btree_cur *xfs_refcountbt_stage_cursor(struct xfs_mount *mp, struct xfs_btree_cur *xfs_refcountbt_stage_cursor(struct xfs_mount *mp,
struct xbtree_afakeroot *afake, xfs_agnumber_t agno); struct xbtree_afakeroot *afake, struct xfs_perag *pag);
extern int xfs_refcountbt_maxrecs(int blocklen, bool leaf); extern int xfs_refcountbt_maxrecs(int blocklen, bool leaf);
extern void xfs_refcountbt_compute_maxlevels(struct xfs_mount *mp); extern void xfs_refcountbt_compute_maxlevels(struct xfs_mount *mp);
...@@ -58,7 +59,7 @@ extern xfs_extlen_t xfs_refcountbt_max_size(struct xfs_mount *mp, ...@@ -58,7 +59,7 @@ extern xfs_extlen_t xfs_refcountbt_max_size(struct xfs_mount *mp,
xfs_agblock_t agblocks); xfs_agblock_t agblocks);
extern int xfs_refcountbt_calc_reserves(struct xfs_mount *mp, extern int xfs_refcountbt_calc_reserves(struct xfs_mount *mp,
struct xfs_trans *tp, xfs_agnumber_t agno, xfs_extlen_t *ask, struct xfs_trans *tp, struct xfs_perag *pag, xfs_extlen_t *ask,
xfs_extlen_t *used); xfs_extlen_t *used);
void xfs_refcountbt_commit_staged_btree(struct xfs_btree_cur *cur, void xfs_refcountbt_commit_staged_btree(struct xfs_btree_cur *cur,
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_bit.h" #include "xfs_bit.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_sb.h"
#include "xfs_defer.h" #include "xfs_defer.h"
#include "xfs_btree.h" #include "xfs_btree.h"
#include "xfs_trans.h" #include "xfs_trans.h"
...@@ -21,6 +22,7 @@ ...@@ -21,6 +22,7 @@
#include "xfs_errortag.h" #include "xfs_errortag.h"
#include "xfs_error.h" #include "xfs_error.h"
#include "xfs_inode.h" #include "xfs_inode.h"
#include "xfs_ag.h"
/* /*
* Lookup the first record less than or equal to [bno, len, owner, offset] * Lookup the first record less than or equal to [bno, len, owner, offset]
...@@ -79,7 +81,7 @@ xfs_rmap_update( ...@@ -79,7 +81,7 @@ xfs_rmap_update(
union xfs_btree_rec rec; union xfs_btree_rec rec;
int error; int error;
trace_xfs_rmap_update(cur->bc_mp, cur->bc_ag.agno, trace_xfs_rmap_update(cur->bc_mp, cur->bc_ag.pag->pag_agno,
irec->rm_startblock, irec->rm_blockcount, irec->rm_startblock, irec->rm_blockcount,
irec->rm_owner, irec->rm_offset, irec->rm_flags); irec->rm_owner, irec->rm_offset, irec->rm_flags);
...@@ -91,7 +93,7 @@ xfs_rmap_update( ...@@ -91,7 +93,7 @@ xfs_rmap_update(
error = xfs_btree_update(cur, &rec); error = xfs_btree_update(cur, &rec);
if (error) if (error)
trace_xfs_rmap_update_error(cur->bc_mp, trace_xfs_rmap_update_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -107,7 +109,7 @@ xfs_rmap_insert( ...@@ -107,7 +109,7 @@ xfs_rmap_insert(
int i; int i;
int error; int error;
trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_ag.agno, agbno, trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
len, owner, offset, flags); len, owner, offset, flags);
error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i); error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
...@@ -133,7 +135,7 @@ xfs_rmap_insert( ...@@ -133,7 +135,7 @@ xfs_rmap_insert(
done: done:
if (error) if (error)
trace_xfs_rmap_insert_error(rcur->bc_mp, trace_xfs_rmap_insert_error(rcur->bc_mp,
rcur->bc_ag.agno, error, _RET_IP_); rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -149,7 +151,7 @@ xfs_rmap_delete( ...@@ -149,7 +151,7 @@ xfs_rmap_delete(
int i; int i;
int error; int error;
trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_ag.agno, agbno, trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_ag.pag->pag_agno, agbno,
len, owner, offset, flags); len, owner, offset, flags);
error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i); error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i);
...@@ -170,7 +172,7 @@ xfs_rmap_delete( ...@@ -170,7 +172,7 @@ xfs_rmap_delete(
done: done:
if (error) if (error)
trace_xfs_rmap_delete_error(rcur->bc_mp, trace_xfs_rmap_delete_error(rcur->bc_mp,
rcur->bc_ag.agno, error, _RET_IP_); rcur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -197,7 +199,7 @@ xfs_rmap_get_rec( ...@@ -197,7 +199,7 @@ xfs_rmap_get_rec(
int *stat) int *stat)
{ {
struct xfs_mount *mp = cur->bc_mp; struct xfs_mount *mp = cur->bc_mp;
xfs_agnumber_t agno = cur->bc_ag.agno; xfs_agnumber_t agno = cur->bc_ag.pag->pag_agno;
union xfs_btree_rec *rec; union xfs_btree_rec *rec;
int error; int error;
...@@ -260,7 +262,7 @@ xfs_rmap_find_left_neighbor_helper( ...@@ -260,7 +262,7 @@ xfs_rmap_find_left_neighbor_helper(
struct xfs_find_left_neighbor_info *info = priv; struct xfs_find_left_neighbor_info *info = priv;
trace_xfs_rmap_find_left_neighbor_candidate(cur->bc_mp, trace_xfs_rmap_find_left_neighbor_candidate(cur->bc_mp,
cur->bc_ag.agno, rec->rm_startblock, cur->bc_ag.pag->pag_agno, rec->rm_startblock,
rec->rm_blockcount, rec->rm_owner, rec->rm_offset, rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
rec->rm_flags); rec->rm_flags);
...@@ -312,7 +314,7 @@ xfs_rmap_find_left_neighbor( ...@@ -312,7 +314,7 @@ xfs_rmap_find_left_neighbor(
info.stat = stat; info.stat = stat;
trace_xfs_rmap_find_left_neighbor_query(cur->bc_mp, trace_xfs_rmap_find_left_neighbor_query(cur->bc_mp,
cur->bc_ag.agno, bno, 0, owner, offset, flags); cur->bc_ag.pag->pag_agno, bno, 0, owner, offset, flags);
error = xfs_rmap_query_range(cur, &info.high, &info.high, error = xfs_rmap_query_range(cur, &info.high, &info.high,
xfs_rmap_find_left_neighbor_helper, &info); xfs_rmap_find_left_neighbor_helper, &info);
...@@ -320,7 +322,7 @@ xfs_rmap_find_left_neighbor( ...@@ -320,7 +322,7 @@ xfs_rmap_find_left_neighbor(
error = 0; error = 0;
if (*stat) if (*stat)
trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp, trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
cur->bc_ag.agno, irec->rm_startblock, cur->bc_ag.pag->pag_agno, irec->rm_startblock,
irec->rm_blockcount, irec->rm_owner, irec->rm_blockcount, irec->rm_owner,
irec->rm_offset, irec->rm_flags); irec->rm_offset, irec->rm_flags);
return error; return error;
...@@ -336,7 +338,7 @@ xfs_rmap_lookup_le_range_helper( ...@@ -336,7 +338,7 @@ xfs_rmap_lookup_le_range_helper(
struct xfs_find_left_neighbor_info *info = priv; struct xfs_find_left_neighbor_info *info = priv;
trace_xfs_rmap_lookup_le_range_candidate(cur->bc_mp, trace_xfs_rmap_lookup_le_range_candidate(cur->bc_mp,
cur->bc_ag.agno, rec->rm_startblock, cur->bc_ag.pag->pag_agno, rec->rm_startblock,
rec->rm_blockcount, rec->rm_owner, rec->rm_offset, rec->rm_blockcount, rec->rm_owner, rec->rm_offset,
rec->rm_flags); rec->rm_flags);
...@@ -385,14 +387,14 @@ xfs_rmap_lookup_le_range( ...@@ -385,14 +387,14 @@ xfs_rmap_lookup_le_range(
info.stat = stat; info.stat = stat;
trace_xfs_rmap_lookup_le_range(cur->bc_mp, trace_xfs_rmap_lookup_le_range(cur->bc_mp,
cur->bc_ag.agno, bno, 0, owner, offset, flags); cur->bc_ag.pag->pag_agno, bno, 0, owner, offset, flags);
error = xfs_rmap_query_range(cur, &info.high, &info.high, error = xfs_rmap_query_range(cur, &info.high, &info.high,
xfs_rmap_lookup_le_range_helper, &info); xfs_rmap_lookup_le_range_helper, &info);
if (error == -ECANCELED) if (error == -ECANCELED)
error = 0; error = 0;
if (*stat) if (*stat)
trace_xfs_rmap_lookup_le_range_result(cur->bc_mp, trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
cur->bc_ag.agno, irec->rm_startblock, cur->bc_ag.pag->pag_agno, irec->rm_startblock,
irec->rm_blockcount, irec->rm_owner, irec->rm_blockcount, irec->rm_owner,
irec->rm_offset, irec->rm_flags); irec->rm_offset, irec->rm_flags);
return error; return error;
...@@ -498,7 +500,7 @@ xfs_rmap_unmap( ...@@ -498,7 +500,7 @@ xfs_rmap_unmap(
(flags & XFS_RMAP_BMBT_BLOCK); (flags & XFS_RMAP_BMBT_BLOCK);
if (unwritten) if (unwritten)
flags |= XFS_RMAP_UNWRITTEN; flags |= XFS_RMAP_UNWRITTEN;
trace_xfs_rmap_unmap(mp, cur->bc_ag.agno, bno, len, trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
unwritten, oinfo); unwritten, oinfo);
/* /*
...@@ -522,7 +524,7 @@ xfs_rmap_unmap( ...@@ -522,7 +524,7 @@ xfs_rmap_unmap(
goto out_error; goto out_error;
} }
trace_xfs_rmap_lookup_le_range_result(cur->bc_mp, trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
cur->bc_ag.agno, ltrec.rm_startblock, cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
ltrec.rm_blockcount, ltrec.rm_owner, ltrec.rm_blockcount, ltrec.rm_owner,
ltrec.rm_offset, ltrec.rm_flags); ltrec.rm_offset, ltrec.rm_flags);
ltoff = ltrec.rm_offset; ltoff = ltrec.rm_offset;
...@@ -588,7 +590,7 @@ xfs_rmap_unmap( ...@@ -588,7 +590,7 @@ xfs_rmap_unmap(
if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) { if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) {
/* exact match, simply remove the record from rmap tree */ /* exact match, simply remove the record from rmap tree */
trace_xfs_rmap_delete(mp, cur->bc_ag.agno, trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
ltrec.rm_startblock, ltrec.rm_blockcount, ltrec.rm_startblock, ltrec.rm_blockcount,
ltrec.rm_owner, ltrec.rm_offset, ltrec.rm_owner, ltrec.rm_offset,
ltrec.rm_flags); ltrec.rm_flags);
...@@ -666,7 +668,7 @@ xfs_rmap_unmap( ...@@ -666,7 +668,7 @@ xfs_rmap_unmap(
else else
cur->bc_rec.r.rm_offset = offset + len; cur->bc_rec.r.rm_offset = offset + len;
cur->bc_rec.r.rm_flags = flags; cur->bc_rec.r.rm_flags = flags;
trace_xfs_rmap_insert(mp, cur->bc_ag.agno, trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
cur->bc_rec.r.rm_startblock, cur->bc_rec.r.rm_startblock,
cur->bc_rec.r.rm_blockcount, cur->bc_rec.r.rm_blockcount,
cur->bc_rec.r.rm_owner, cur->bc_rec.r.rm_owner,
...@@ -678,11 +680,11 @@ xfs_rmap_unmap( ...@@ -678,11 +680,11 @@ xfs_rmap_unmap(
} }
out_done: out_done:
trace_xfs_rmap_unmap_done(mp, cur->bc_ag.agno, bno, len, trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
unwritten, oinfo); unwritten, oinfo);
out_error: out_error:
if (error) if (error)
trace_xfs_rmap_unmap_error(mp, cur->bc_ag.agno, trace_xfs_rmap_unmap_error(mp, cur->bc_ag.pag->pag_agno,
error, _RET_IP_); error, _RET_IP_);
return error; return error;
} }
...@@ -694,7 +696,7 @@ int ...@@ -694,7 +696,7 @@ int
xfs_rmap_free( xfs_rmap_free(
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_buf *agbp, struct xfs_buf *agbp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_agblock_t bno, xfs_agblock_t bno,
xfs_extlen_t len, xfs_extlen_t len,
const struct xfs_owner_info *oinfo) const struct xfs_owner_info *oinfo)
...@@ -706,7 +708,7 @@ xfs_rmap_free( ...@@ -706,7 +708,7 @@ xfs_rmap_free(
if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
return 0; return 0;
cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno); cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
error = xfs_rmap_unmap(cur, bno, len, false, oinfo); error = xfs_rmap_unmap(cur, bno, len, false, oinfo);
...@@ -773,7 +775,7 @@ xfs_rmap_map( ...@@ -773,7 +775,7 @@ xfs_rmap_map(
(flags & XFS_RMAP_BMBT_BLOCK); (flags & XFS_RMAP_BMBT_BLOCK);
if (unwritten) if (unwritten)
flags |= XFS_RMAP_UNWRITTEN; flags |= XFS_RMAP_UNWRITTEN;
trace_xfs_rmap_map(mp, cur->bc_ag.agno, bno, len, trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
unwritten, oinfo); unwritten, oinfo);
ASSERT(!xfs_rmap_should_skip_owner_update(oinfo)); ASSERT(!xfs_rmap_should_skip_owner_update(oinfo));
...@@ -795,7 +797,7 @@ xfs_rmap_map( ...@@ -795,7 +797,7 @@ xfs_rmap_map(
goto out_error; goto out_error;
} }
trace_xfs_rmap_lookup_le_range_result(cur->bc_mp, trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
cur->bc_ag.agno, ltrec.rm_startblock, cur->bc_ag.pag->pag_agno, ltrec.rm_startblock,
ltrec.rm_blockcount, ltrec.rm_owner, ltrec.rm_blockcount, ltrec.rm_owner,
ltrec.rm_offset, ltrec.rm_flags); ltrec.rm_offset, ltrec.rm_flags);
...@@ -831,7 +833,7 @@ xfs_rmap_map( ...@@ -831,7 +833,7 @@ xfs_rmap_map(
goto out_error; goto out_error;
} }
trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp, trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
cur->bc_ag.agno, gtrec.rm_startblock, cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
gtrec.rm_blockcount, gtrec.rm_owner, gtrec.rm_blockcount, gtrec.rm_owner,
gtrec.rm_offset, gtrec.rm_flags); gtrec.rm_offset, gtrec.rm_flags);
if (!xfs_rmap_is_mergeable(&gtrec, owner, flags)) if (!xfs_rmap_is_mergeable(&gtrec, owner, flags))
...@@ -870,7 +872,7 @@ xfs_rmap_map( ...@@ -870,7 +872,7 @@ xfs_rmap_map(
* result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr| * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr|
*/ */
ltrec.rm_blockcount += gtrec.rm_blockcount; ltrec.rm_blockcount += gtrec.rm_blockcount;
trace_xfs_rmap_delete(mp, cur->bc_ag.agno, trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
gtrec.rm_startblock, gtrec.rm_startblock,
gtrec.rm_blockcount, gtrec.rm_blockcount,
gtrec.rm_owner, gtrec.rm_owner,
...@@ -921,7 +923,7 @@ xfs_rmap_map( ...@@ -921,7 +923,7 @@ xfs_rmap_map(
cur->bc_rec.r.rm_owner = owner; cur->bc_rec.r.rm_owner = owner;
cur->bc_rec.r.rm_offset = offset; cur->bc_rec.r.rm_offset = offset;
cur->bc_rec.r.rm_flags = flags; cur->bc_rec.r.rm_flags = flags;
trace_xfs_rmap_insert(mp, cur->bc_ag.agno, bno, len, trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
owner, offset, flags); owner, offset, flags);
error = xfs_btree_insert(cur, &i); error = xfs_btree_insert(cur, &i);
if (error) if (error)
...@@ -932,11 +934,11 @@ xfs_rmap_map( ...@@ -932,11 +934,11 @@ xfs_rmap_map(
} }
} }
trace_xfs_rmap_map_done(mp, cur->bc_ag.agno, bno, len, trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
unwritten, oinfo); unwritten, oinfo);
out_error: out_error:
if (error) if (error)
trace_xfs_rmap_map_error(mp, cur->bc_ag.agno, trace_xfs_rmap_map_error(mp, cur->bc_ag.pag->pag_agno,
error, _RET_IP_); error, _RET_IP_);
return error; return error;
} }
...@@ -948,7 +950,7 @@ int ...@@ -948,7 +950,7 @@ int
xfs_rmap_alloc( xfs_rmap_alloc(
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_buf *agbp, struct xfs_buf *agbp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_agblock_t bno, xfs_agblock_t bno,
xfs_extlen_t len, xfs_extlen_t len,
const struct xfs_owner_info *oinfo) const struct xfs_owner_info *oinfo)
...@@ -960,7 +962,7 @@ xfs_rmap_alloc( ...@@ -960,7 +962,7 @@ xfs_rmap_alloc(
if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
return 0; return 0;
cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno); cur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
error = xfs_rmap_map(cur, bno, len, false, oinfo); error = xfs_rmap_map(cur, bno, len, false, oinfo);
xfs_btree_del_cursor(cur, error); xfs_btree_del_cursor(cur, error);
...@@ -1010,7 +1012,7 @@ xfs_rmap_convert( ...@@ -1010,7 +1012,7 @@ xfs_rmap_convert(
(flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK)))); (flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0; oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
new_endoff = offset + len; new_endoff = offset + len;
trace_xfs_rmap_convert(mp, cur->bc_ag.agno, bno, len, trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
unwritten, oinfo); unwritten, oinfo);
/* /*
...@@ -1034,7 +1036,7 @@ xfs_rmap_convert( ...@@ -1034,7 +1036,7 @@ xfs_rmap_convert(
goto done; goto done;
} }
trace_xfs_rmap_lookup_le_range_result(cur->bc_mp, trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
cur->bc_ag.agno, PREV.rm_startblock, cur->bc_ag.pag->pag_agno, PREV.rm_startblock,
PREV.rm_blockcount, PREV.rm_owner, PREV.rm_blockcount, PREV.rm_owner,
PREV.rm_offset, PREV.rm_flags); PREV.rm_offset, PREV.rm_flags);
...@@ -1076,7 +1078,7 @@ xfs_rmap_convert( ...@@ -1076,7 +1078,7 @@ xfs_rmap_convert(
goto done; goto done;
} }
trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp, trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp,
cur->bc_ag.agno, LEFT.rm_startblock, cur->bc_ag.pag->pag_agno, LEFT.rm_startblock,
LEFT.rm_blockcount, LEFT.rm_owner, LEFT.rm_blockcount, LEFT.rm_owner,
LEFT.rm_offset, LEFT.rm_flags); LEFT.rm_offset, LEFT.rm_flags);
if (LEFT.rm_startblock + LEFT.rm_blockcount == bno && if (LEFT.rm_startblock + LEFT.rm_blockcount == bno &&
...@@ -1114,7 +1116,7 @@ xfs_rmap_convert( ...@@ -1114,7 +1116,7 @@ xfs_rmap_convert(
goto done; goto done;
} }
trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp, trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
cur->bc_ag.agno, RIGHT.rm_startblock, cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
RIGHT.rm_blockcount, RIGHT.rm_owner, RIGHT.rm_blockcount, RIGHT.rm_owner,
RIGHT.rm_offset, RIGHT.rm_flags); RIGHT.rm_offset, RIGHT.rm_flags);
if (bno + len == RIGHT.rm_startblock && if (bno + len == RIGHT.rm_startblock &&
...@@ -1132,7 +1134,7 @@ xfs_rmap_convert( ...@@ -1132,7 +1134,7 @@ xfs_rmap_convert(
RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX) RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
state &= ~RMAP_RIGHT_CONTIG; state &= ~RMAP_RIGHT_CONTIG;
trace_xfs_rmap_convert_state(mp, cur->bc_ag.agno, state, trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
_RET_IP_); _RET_IP_);
/* reset the cursor back to PREV */ /* reset the cursor back to PREV */
...@@ -1162,7 +1164,7 @@ xfs_rmap_convert( ...@@ -1162,7 +1164,7 @@ xfs_rmap_convert(
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
goto done; goto done;
} }
trace_xfs_rmap_delete(mp, cur->bc_ag.agno, trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
RIGHT.rm_startblock, RIGHT.rm_blockcount, RIGHT.rm_startblock, RIGHT.rm_blockcount,
RIGHT.rm_owner, RIGHT.rm_offset, RIGHT.rm_owner, RIGHT.rm_offset,
RIGHT.rm_flags); RIGHT.rm_flags);
...@@ -1180,7 +1182,7 @@ xfs_rmap_convert( ...@@ -1180,7 +1182,7 @@ xfs_rmap_convert(
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
goto done; goto done;
} }
trace_xfs_rmap_delete(mp, cur->bc_ag.agno, trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
PREV.rm_startblock, PREV.rm_blockcount, PREV.rm_startblock, PREV.rm_blockcount,
PREV.rm_owner, PREV.rm_offset, PREV.rm_owner, PREV.rm_offset,
PREV.rm_flags); PREV.rm_flags);
...@@ -1210,7 +1212,7 @@ xfs_rmap_convert( ...@@ -1210,7 +1212,7 @@ xfs_rmap_convert(
* Setting all of a previous oldext extent to newext. * Setting all of a previous oldext extent to newext.
* The left neighbor is contiguous, the right is not. * The left neighbor is contiguous, the right is not.
*/ */
trace_xfs_rmap_delete(mp, cur->bc_ag.agno, trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
PREV.rm_startblock, PREV.rm_blockcount, PREV.rm_startblock, PREV.rm_blockcount,
PREV.rm_owner, PREV.rm_offset, PREV.rm_owner, PREV.rm_offset,
PREV.rm_flags); PREV.rm_flags);
...@@ -1247,7 +1249,7 @@ xfs_rmap_convert( ...@@ -1247,7 +1249,7 @@ xfs_rmap_convert(
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
goto done; goto done;
} }
trace_xfs_rmap_delete(mp, cur->bc_ag.agno, trace_xfs_rmap_delete(mp, cur->bc_ag.pag->pag_agno,
RIGHT.rm_startblock, RIGHT.rm_blockcount, RIGHT.rm_startblock, RIGHT.rm_blockcount,
RIGHT.rm_owner, RIGHT.rm_offset, RIGHT.rm_owner, RIGHT.rm_offset,
RIGHT.rm_flags); RIGHT.rm_flags);
...@@ -1326,7 +1328,7 @@ xfs_rmap_convert( ...@@ -1326,7 +1328,7 @@ xfs_rmap_convert(
NEW.rm_blockcount = len; NEW.rm_blockcount = len;
NEW.rm_flags = newext; NEW.rm_flags = newext;
cur->bc_rec.r = NEW; cur->bc_rec.r = NEW;
trace_xfs_rmap_insert(mp, cur->bc_ag.agno, bno, trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
len, owner, offset, newext); len, owner, offset, newext);
error = xfs_btree_insert(cur, &i); error = xfs_btree_insert(cur, &i);
if (error) if (error)
...@@ -1383,7 +1385,7 @@ xfs_rmap_convert( ...@@ -1383,7 +1385,7 @@ xfs_rmap_convert(
NEW.rm_blockcount = len; NEW.rm_blockcount = len;
NEW.rm_flags = newext; NEW.rm_flags = newext;
cur->bc_rec.r = NEW; cur->bc_rec.r = NEW;
trace_xfs_rmap_insert(mp, cur->bc_ag.agno, bno, trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno,
len, owner, offset, newext); len, owner, offset, newext);
error = xfs_btree_insert(cur, &i); error = xfs_btree_insert(cur, &i);
if (error) if (error)
...@@ -1414,7 +1416,7 @@ xfs_rmap_convert( ...@@ -1414,7 +1416,7 @@ xfs_rmap_convert(
NEW = PREV; NEW = PREV;
NEW.rm_blockcount = offset - PREV.rm_offset; NEW.rm_blockcount = offset - PREV.rm_offset;
cur->bc_rec.r = NEW; cur->bc_rec.r = NEW;
trace_xfs_rmap_insert(mp, cur->bc_ag.agno, trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno,
NEW.rm_startblock, NEW.rm_blockcount, NEW.rm_startblock, NEW.rm_blockcount,
NEW.rm_owner, NEW.rm_offset, NEW.rm_owner, NEW.rm_offset,
NEW.rm_flags); NEW.rm_flags);
...@@ -1441,7 +1443,7 @@ xfs_rmap_convert( ...@@ -1441,7 +1443,7 @@ xfs_rmap_convert(
/* new middle extent - newext */ /* new middle extent - newext */
cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN; cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN;
cur->bc_rec.r.rm_flags |= newext; cur->bc_rec.r.rm_flags |= newext;
trace_xfs_rmap_insert(mp, cur->bc_ag.agno, bno, len, trace_xfs_rmap_insert(mp, cur->bc_ag.pag->pag_agno, bno, len,
owner, offset, newext); owner, offset, newext);
error = xfs_btree_insert(cur, &i); error = xfs_btree_insert(cur, &i);
if (error) if (error)
...@@ -1465,12 +1467,12 @@ xfs_rmap_convert( ...@@ -1465,12 +1467,12 @@ xfs_rmap_convert(
ASSERT(0); ASSERT(0);
} }
trace_xfs_rmap_convert_done(mp, cur->bc_ag.agno, bno, len, trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
unwritten, oinfo); unwritten, oinfo);
done: done:
if (error) if (error)
trace_xfs_rmap_convert_error(cur->bc_mp, trace_xfs_rmap_convert_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -1506,7 +1508,7 @@ xfs_rmap_convert_shared( ...@@ -1506,7 +1508,7 @@ xfs_rmap_convert_shared(
(flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK)))); (flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))));
oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0; oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0;
new_endoff = offset + len; new_endoff = offset + len;
trace_xfs_rmap_convert(mp, cur->bc_ag.agno, bno, len, trace_xfs_rmap_convert(mp, cur->bc_ag.pag->pag_agno, bno, len,
unwritten, oinfo); unwritten, oinfo);
/* /*
...@@ -1573,7 +1575,7 @@ xfs_rmap_convert_shared( ...@@ -1573,7 +1575,7 @@ xfs_rmap_convert_shared(
goto done; goto done;
} }
trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp, trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
cur->bc_ag.agno, RIGHT.rm_startblock, cur->bc_ag.pag->pag_agno, RIGHT.rm_startblock,
RIGHT.rm_blockcount, RIGHT.rm_owner, RIGHT.rm_blockcount, RIGHT.rm_owner,
RIGHT.rm_offset, RIGHT.rm_flags); RIGHT.rm_offset, RIGHT.rm_flags);
if (xfs_rmap_is_mergeable(&RIGHT, owner, newext)) if (xfs_rmap_is_mergeable(&RIGHT, owner, newext))
...@@ -1589,7 +1591,7 @@ xfs_rmap_convert_shared( ...@@ -1589,7 +1591,7 @@ xfs_rmap_convert_shared(
RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX) RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX)
state &= ~RMAP_RIGHT_CONTIG; state &= ~RMAP_RIGHT_CONTIG;
trace_xfs_rmap_convert_state(mp, cur->bc_ag.agno, state, trace_xfs_rmap_convert_state(mp, cur->bc_ag.pag->pag_agno, state,
_RET_IP_); _RET_IP_);
/* /*
* Switch out based on the FILLING and CONTIG state bits. * Switch out based on the FILLING and CONTIG state bits.
...@@ -1880,12 +1882,12 @@ xfs_rmap_convert_shared( ...@@ -1880,12 +1882,12 @@ xfs_rmap_convert_shared(
ASSERT(0); ASSERT(0);
} }
trace_xfs_rmap_convert_done(mp, cur->bc_ag.agno, bno, len, trace_xfs_rmap_convert_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
unwritten, oinfo); unwritten, oinfo);
done: done:
if (error) if (error)
trace_xfs_rmap_convert_error(cur->bc_mp, trace_xfs_rmap_convert_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -1923,7 +1925,7 @@ xfs_rmap_unmap_shared( ...@@ -1923,7 +1925,7 @@ xfs_rmap_unmap_shared(
xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
if (unwritten) if (unwritten)
flags |= XFS_RMAP_UNWRITTEN; flags |= XFS_RMAP_UNWRITTEN;
trace_xfs_rmap_unmap(mp, cur->bc_ag.agno, bno, len, trace_xfs_rmap_unmap(mp, cur->bc_ag.pag->pag_agno, bno, len,
unwritten, oinfo); unwritten, oinfo);
/* /*
...@@ -2072,12 +2074,12 @@ xfs_rmap_unmap_shared( ...@@ -2072,12 +2074,12 @@ xfs_rmap_unmap_shared(
goto out_error; goto out_error;
} }
trace_xfs_rmap_unmap_done(mp, cur->bc_ag.agno, bno, len, trace_xfs_rmap_unmap_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
unwritten, oinfo); unwritten, oinfo);
out_error: out_error:
if (error) if (error)
trace_xfs_rmap_unmap_error(cur->bc_mp, trace_xfs_rmap_unmap_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -2112,7 +2114,7 @@ xfs_rmap_map_shared( ...@@ -2112,7 +2114,7 @@ xfs_rmap_map_shared(
xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); xfs_owner_info_unpack(oinfo, &owner, &offset, &flags);
if (unwritten) if (unwritten)
flags |= XFS_RMAP_UNWRITTEN; flags |= XFS_RMAP_UNWRITTEN;
trace_xfs_rmap_map(mp, cur->bc_ag.agno, bno, len, trace_xfs_rmap_map(mp, cur->bc_ag.pag->pag_agno, bno, len,
unwritten, oinfo); unwritten, oinfo);
/* Is there a left record that abuts our range? */ /* Is there a left record that abuts our range? */
...@@ -2138,7 +2140,7 @@ xfs_rmap_map_shared( ...@@ -2138,7 +2140,7 @@ xfs_rmap_map_shared(
goto out_error; goto out_error;
} }
trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp, trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp,
cur->bc_ag.agno, gtrec.rm_startblock, cur->bc_ag.pag->pag_agno, gtrec.rm_startblock,
gtrec.rm_blockcount, gtrec.rm_owner, gtrec.rm_blockcount, gtrec.rm_owner,
gtrec.rm_offset, gtrec.rm_flags); gtrec.rm_offset, gtrec.rm_flags);
...@@ -2231,12 +2233,12 @@ xfs_rmap_map_shared( ...@@ -2231,12 +2233,12 @@ xfs_rmap_map_shared(
goto out_error; goto out_error;
} }
trace_xfs_rmap_map_done(mp, cur->bc_ag.agno, bno, len, trace_xfs_rmap_map_done(mp, cur->bc_ag.pag->pag_agno, bno, len,
unwritten, oinfo); unwritten, oinfo);
out_error: out_error:
if (error) if (error)
trace_xfs_rmap_map_error(cur->bc_mp, trace_xfs_rmap_map_error(cur->bc_mp,
cur->bc_ag.agno, error, _RET_IP_); cur->bc_ag.pag->pag_agno, error, _RET_IP_);
return error; return error;
} }
...@@ -2362,31 +2364,32 @@ xfs_rmap_finish_one( ...@@ -2362,31 +2364,32 @@ xfs_rmap_finish_one(
struct xfs_btree_cur **pcur) struct xfs_btree_cur **pcur)
{ {
struct xfs_mount *mp = tp->t_mountp; struct xfs_mount *mp = tp->t_mountp;
struct xfs_perag *pag;
struct xfs_btree_cur *rcur; struct xfs_btree_cur *rcur;
struct xfs_buf *agbp = NULL; struct xfs_buf *agbp = NULL;
int error = 0; int error = 0;
xfs_agnumber_t agno;
struct xfs_owner_info oinfo; struct xfs_owner_info oinfo;
xfs_agblock_t bno; xfs_agblock_t bno;
bool unwritten; bool unwritten;
agno = XFS_FSB_TO_AGNO(mp, startblock); pag = xfs_perag_get(mp, XFS_FSB_TO_AGNO(mp, startblock));
ASSERT(agno != NULLAGNUMBER);
bno = XFS_FSB_TO_AGBNO(mp, startblock); bno = XFS_FSB_TO_AGBNO(mp, startblock);
trace_xfs_rmap_deferred(mp, agno, type, bno, owner, whichfork, trace_xfs_rmap_deferred(mp, pag->pag_agno, type, bno, owner, whichfork,
startoff, blockcount, state); startoff, blockcount, state);
if (XFS_TEST_ERROR(false, mp, if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_RMAP_FINISH_ONE)) {
XFS_ERRTAG_RMAP_FINISH_ONE)) error = -EIO;
return -EIO; goto out_drop;
}
/* /*
* If we haven't gotten a cursor or the cursor AG doesn't match * If we haven't gotten a cursor or the cursor AG doesn't match
* the startblock, get one now. * the startblock, get one now.
*/ */
rcur = *pcur; rcur = *pcur;
if (rcur != NULL && rcur->bc_ag.agno != agno) { if (rcur != NULL && rcur->bc_ag.pag != pag) {
xfs_rmap_finish_one_cleanup(tp, rcur, 0); xfs_rmap_finish_one_cleanup(tp, rcur, 0);
rcur = NULL; rcur = NULL;
*pcur = NULL; *pcur = NULL;
...@@ -2397,13 +2400,15 @@ xfs_rmap_finish_one( ...@@ -2397,13 +2400,15 @@ xfs_rmap_finish_one(
* rmapbt, because a shape change could cause us to * rmapbt, because a shape change could cause us to
* allocate blocks. * allocate blocks.
*/ */
error = xfs_free_extent_fix_freelist(tp, agno, &agbp); error = xfs_free_extent_fix_freelist(tp, pag, &agbp);
if (error) if (error)
return error; goto out_drop;
if (XFS_IS_CORRUPT(tp->t_mountp, !agbp)) if (XFS_IS_CORRUPT(tp->t_mountp, !agbp)) {
return -EFSCORRUPTED; error = -EFSCORRUPTED;
goto out_drop;
}
rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno); rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, pag);
} }
*pcur = rcur; *pcur = rcur;
...@@ -2441,6 +2446,8 @@ xfs_rmap_finish_one( ...@@ -2441,6 +2446,8 @@ xfs_rmap_finish_one(
ASSERT(0); ASSERT(0);
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
} }
out_drop:
xfs_perag_put(pag);
return error; return error;
} }
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#ifndef __XFS_RMAP_H__ #ifndef __XFS_RMAP_H__
#define __XFS_RMAP_H__ #define __XFS_RMAP_H__
struct xfs_perag;
static inline void static inline void
xfs_rmap_ino_bmbt_owner( xfs_rmap_ino_bmbt_owner(
struct xfs_owner_info *oi, struct xfs_owner_info *oi,
...@@ -113,10 +115,10 @@ xfs_owner_info_pack( ...@@ -113,10 +115,10 @@ xfs_owner_info_pack(
} }
int xfs_rmap_alloc(struct xfs_trans *tp, struct xfs_buf *agbp, int xfs_rmap_alloc(struct xfs_trans *tp, struct xfs_buf *agbp,
xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, struct xfs_perag *pag, xfs_agblock_t bno, xfs_extlen_t len,
const struct xfs_owner_info *oinfo); const struct xfs_owner_info *oinfo);
int xfs_rmap_free(struct xfs_trans *tp, struct xfs_buf *agbp, int xfs_rmap_free(struct xfs_trans *tp, struct xfs_buf *agbp,
xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, struct xfs_perag *pag, xfs_agblock_t bno, xfs_extlen_t len,
const struct xfs_owner_info *oinfo); const struct xfs_owner_info *oinfo);
int xfs_rmap_lookup_le(struct xfs_btree_cur *cur, xfs_agblock_t bno, int xfs_rmap_lookup_le(struct xfs_btree_cur *cur, xfs_agblock_t bno,
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include "xfs_format.h" #include "xfs_format.h"
#include "xfs_log_format.h" #include "xfs_log_format.h"
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_sb.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_alloc.h" #include "xfs_alloc.h"
...@@ -20,6 +19,7 @@ ...@@ -20,6 +19,7 @@
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_error.h" #include "xfs_error.h"
#include "xfs_extent_busy.h" #include "xfs_extent_busy.h"
#include "xfs_ag.h"
#include "xfs_ag_resv.h" #include "xfs_ag_resv.h"
/* /*
...@@ -52,7 +52,7 @@ xfs_rmapbt_dup_cursor( ...@@ -52,7 +52,7 @@ xfs_rmapbt_dup_cursor(
struct xfs_btree_cur *cur) struct xfs_btree_cur *cur)
{ {
return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp, return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp,
cur->bc_ag.agbp, cur->bc_ag.agno); cur->bc_ag.agbp, cur->bc_ag.pag);
} }
STATIC void STATIC void
...@@ -64,13 +64,12 @@ xfs_rmapbt_set_root( ...@@ -64,13 +64,12 @@ xfs_rmapbt_set_root(
struct xfs_buf *agbp = cur->bc_ag.agbp; struct xfs_buf *agbp = cur->bc_ag.agbp;
struct xfs_agf *agf = agbp->b_addr; struct xfs_agf *agf = agbp->b_addr;
int btnum = cur->bc_btnum; int btnum = cur->bc_btnum;
struct xfs_perag *pag = agbp->b_pag;
ASSERT(ptr->s != 0); ASSERT(ptr->s != 0);
agf->agf_roots[btnum] = ptr->s; agf->agf_roots[btnum] = ptr->s;
be32_add_cpu(&agf->agf_levels[btnum], inc); be32_add_cpu(&agf->agf_levels[btnum], inc);
pag->pagf_levels[btnum] += inc; cur->bc_ag.pag->pagf_levels[btnum] += inc;
xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS);
} }
...@@ -84,6 +83,7 @@ xfs_rmapbt_alloc_block( ...@@ -84,6 +83,7 @@ xfs_rmapbt_alloc_block(
{ {
struct xfs_buf *agbp = cur->bc_ag.agbp; struct xfs_buf *agbp = cur->bc_ag.agbp;
struct xfs_agf *agf = agbp->b_addr; struct xfs_agf *agf = agbp->b_addr;
struct xfs_perag *pag = cur->bc_ag.pag;
int error; int error;
xfs_agblock_t bno; xfs_agblock_t bno;
...@@ -93,21 +93,19 @@ xfs_rmapbt_alloc_block( ...@@ -93,21 +93,19 @@ xfs_rmapbt_alloc_block(
if (error) if (error)
return error; return error;
trace_xfs_rmapbt_alloc_block(cur->bc_mp, cur->bc_ag.agno, trace_xfs_rmapbt_alloc_block(cur->bc_mp, pag->pag_agno, bno, 1);
bno, 1);
if (bno == NULLAGBLOCK) { if (bno == NULLAGBLOCK) {
*stat = 0; *stat = 0;
return 0; return 0;
} }
xfs_extent_busy_reuse(cur->bc_mp, cur->bc_ag.agno, bno, 1, xfs_extent_busy_reuse(cur->bc_mp, pag, bno, 1, false);
false);
new->s = cpu_to_be32(bno); new->s = cpu_to_be32(bno);
be32_add_cpu(&agf->agf_rmap_blocks, 1); be32_add_cpu(&agf->agf_rmap_blocks, 1);
xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS);
xfs_ag_resv_rmapbt_alloc(cur->bc_mp, cur->bc_ag.agno); xfs_ag_resv_rmapbt_alloc(cur->bc_mp, pag->pag_agno);
*stat = 1; *stat = 1;
return 0; return 0;
...@@ -120,12 +118,12 @@ xfs_rmapbt_free_block( ...@@ -120,12 +118,12 @@ xfs_rmapbt_free_block(
{ {
struct xfs_buf *agbp = cur->bc_ag.agbp; struct xfs_buf *agbp = cur->bc_ag.agbp;
struct xfs_agf *agf = agbp->b_addr; struct xfs_agf *agf = agbp->b_addr;
struct xfs_perag *pag; struct xfs_perag *pag = cur->bc_ag.pag;
xfs_agblock_t bno; xfs_agblock_t bno;
int error; int error;
bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp)); bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp));
trace_xfs_rmapbt_free_block(cur->bc_mp, cur->bc_ag.agno, trace_xfs_rmapbt_free_block(cur->bc_mp, pag->pag_agno,
bno, 1); bno, 1);
be32_add_cpu(&agf->agf_rmap_blocks, -1); be32_add_cpu(&agf->agf_rmap_blocks, -1);
xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS); xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS);
...@@ -133,10 +131,9 @@ xfs_rmapbt_free_block( ...@@ -133,10 +131,9 @@ xfs_rmapbt_free_block(
if (error) if (error)
return error; return error;
xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1, xfs_extent_busy_insert(cur->bc_tp, pag, bno, 1,
XFS_EXTENT_BUSY_SKIP_DISCARD); XFS_EXTENT_BUSY_SKIP_DISCARD);
pag = cur->bc_ag.agbp->b_pag;
xfs_ag_resv_free_extent(pag, XFS_AG_RESV_RMAPBT, NULL, 1); xfs_ag_resv_free_extent(pag, XFS_AG_RESV_RMAPBT, NULL, 1);
return 0; return 0;
} }
...@@ -215,7 +212,7 @@ xfs_rmapbt_init_ptr_from_cur( ...@@ -215,7 +212,7 @@ xfs_rmapbt_init_ptr_from_cur(
{ {
struct xfs_agf *agf = cur->bc_ag.agbp->b_addr; struct xfs_agf *agf = cur->bc_ag.agbp->b_addr;
ASSERT(cur->bc_ag.agno == be32_to_cpu(agf->agf_seqno)); ASSERT(cur->bc_ag.pag->pag_agno == be32_to_cpu(agf->agf_seqno));
ptr->s = agf->agf_roots[cur->bc_btnum]; ptr->s = agf->agf_roots[cur->bc_btnum];
} }
...@@ -450,7 +447,7 @@ static struct xfs_btree_cur * ...@@ -450,7 +447,7 @@ static struct xfs_btree_cur *
xfs_rmapbt_init_common( xfs_rmapbt_init_common(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno) struct xfs_perag *pag)
{ {
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
...@@ -462,9 +459,12 @@ xfs_rmapbt_init_common( ...@@ -462,9 +459,12 @@ xfs_rmapbt_init_common(
cur->bc_flags = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING; cur->bc_flags = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING;
cur->bc_blocklog = mp->m_sb.sb_blocklog; cur->bc_blocklog = mp->m_sb.sb_blocklog;
cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2); cur->bc_statoff = XFS_STATS_CALC_INDEX(xs_rmap_2);
cur->bc_ag.agno = agno;
cur->bc_ops = &xfs_rmapbt_ops; cur->bc_ops = &xfs_rmapbt_ops;
/* take a reference for the cursor */
atomic_inc(&pag->pag_ref);
cur->bc_ag.pag = pag;
return cur; return cur;
} }
...@@ -474,12 +474,12 @@ xfs_rmapbt_init_cursor( ...@@ -474,12 +474,12 @@ xfs_rmapbt_init_cursor(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_buf *agbp, struct xfs_buf *agbp,
xfs_agnumber_t agno) struct xfs_perag *pag)
{ {
struct xfs_agf *agf = agbp->b_addr; struct xfs_agf *agf = agbp->b_addr;
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
cur = xfs_rmapbt_init_common(mp, tp, agno); cur = xfs_rmapbt_init_common(mp, tp, pag);
cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]); cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
cur->bc_ag.agbp = agbp; cur->bc_ag.agbp = agbp;
return cur; return cur;
...@@ -490,11 +490,11 @@ struct xfs_btree_cur * ...@@ -490,11 +490,11 @@ struct xfs_btree_cur *
xfs_rmapbt_stage_cursor( xfs_rmapbt_stage_cursor(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xbtree_afakeroot *afake, struct xbtree_afakeroot *afake,
xfs_agnumber_t agno) struct xfs_perag *pag)
{ {
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
cur = xfs_rmapbt_init_common(mp, NULL, agno); cur = xfs_rmapbt_init_common(mp, NULL, pag);
xfs_btree_stage_afakeroot(cur, afake); xfs_btree_stage_afakeroot(cur, afake);
return cur; return cur;
} }
...@@ -596,7 +596,7 @@ int ...@@ -596,7 +596,7 @@ int
xfs_rmapbt_calc_reserves( xfs_rmapbt_calc_reserves(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_extlen_t *ask, xfs_extlen_t *ask,
xfs_extlen_t *used) xfs_extlen_t *used)
{ {
...@@ -609,7 +609,7 @@ xfs_rmapbt_calc_reserves( ...@@ -609,7 +609,7 @@ xfs_rmapbt_calc_reserves(
if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
return 0; return 0;
error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp); error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0, &agbp);
if (error) if (error)
return error; return error;
...@@ -624,7 +624,7 @@ xfs_rmapbt_calc_reserves( ...@@ -624,7 +624,7 @@ xfs_rmapbt_calc_reserves(
* expansion. We therefore can pretend the space isn't there. * expansion. We therefore can pretend the space isn't there.
*/ */
if (mp->m_sb.sb_logstart && if (mp->m_sb.sb_logstart &&
XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == agno) XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == pag->pag_agno)
agblocks -= mp->m_sb.sb_logblocks; agblocks -= mp->m_sb.sb_logblocks;
/* Reserve 1% of the AG or enough for 1 block per record. */ /* Reserve 1% of the AG or enough for 1 block per record. */
......
...@@ -43,9 +43,9 @@ struct xbtree_afakeroot; ...@@ -43,9 +43,9 @@ struct xbtree_afakeroot;
struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp, struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp,
struct xfs_trans *tp, struct xfs_buf *bp, struct xfs_trans *tp, struct xfs_buf *bp,
xfs_agnumber_t agno); struct xfs_perag *pag);
struct xfs_btree_cur *xfs_rmapbt_stage_cursor(struct xfs_mount *mp, struct xfs_btree_cur *xfs_rmapbt_stage_cursor(struct xfs_mount *mp,
struct xbtree_afakeroot *afake, xfs_agnumber_t agno); struct xbtree_afakeroot *afake, struct xfs_perag *pag);
void xfs_rmapbt_commit_staged_btree(struct xfs_btree_cur *cur, void xfs_rmapbt_commit_staged_btree(struct xfs_btree_cur *cur,
struct xfs_trans *tp, struct xfs_buf *agbp); struct xfs_trans *tp, struct xfs_buf *agbp);
int xfs_rmapbt_maxrecs(int blocklen, int leaf); int xfs_rmapbt_maxrecs(int blocklen, int leaf);
...@@ -57,6 +57,6 @@ extern xfs_extlen_t xfs_rmapbt_max_size(struct xfs_mount *mp, ...@@ -57,6 +57,6 @@ extern xfs_extlen_t xfs_rmapbt_max_size(struct xfs_mount *mp,
xfs_agblock_t agblocks); xfs_agblock_t agblocks);
extern int xfs_rmapbt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp, extern int xfs_rmapbt_calc_reserves(struct xfs_mount *mp, struct xfs_trans *tp,
xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used); struct xfs_perag *pag, xfs_extlen_t *ask, xfs_extlen_t *used);
#endif /* __XFS_RMAP_BTREE_H__ */ #endif /* __XFS_RMAP_BTREE_H__ */
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include "xfs_ialloc.h" #include "xfs_ialloc.h"
#include "xfs_alloc.h" #include "xfs_alloc.h"
#include "xfs_error.h" #include "xfs_error.h"
#include "xfs_trace.h"
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_buf_item.h" #include "xfs_buf_item.h"
#include "xfs_bmap_btree.h" #include "xfs_bmap_btree.h"
...@@ -25,72 +24,12 @@ ...@@ -25,72 +24,12 @@
#include "xfs_refcount_btree.h" #include "xfs_refcount_btree.h"
#include "xfs_da_format.h" #include "xfs_da_format.h"
#include "xfs_health.h" #include "xfs_health.h"
#include "xfs_ag.h"
/* /*
* Physical superblock buffer manipulations. Shared with libxfs in userspace. * Physical superblock buffer manipulations. Shared with libxfs in userspace.
*/ */
/*
* Reference counting access wrappers to the perag structures.
* Because we never free per-ag structures, the only thing we
* have to protect against changes is the tree structure itself.
*/
struct xfs_perag *
xfs_perag_get(
struct xfs_mount *mp,
xfs_agnumber_t agno)
{
struct xfs_perag *pag;
int ref = 0;
rcu_read_lock();
pag = radix_tree_lookup(&mp->m_perag_tree, agno);
if (pag) {
ASSERT(atomic_read(&pag->pag_ref) >= 0);
ref = atomic_inc_return(&pag->pag_ref);
}
rcu_read_unlock();
trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
return pag;
}
/*
* search from @first to find the next perag with the given tag set.
*/
struct xfs_perag *
xfs_perag_get_tag(
struct xfs_mount *mp,
xfs_agnumber_t first,
int tag)
{
struct xfs_perag *pag;
int found;
int ref;
rcu_read_lock();
found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
(void **)&pag, first, 1, tag);
if (found <= 0) {
rcu_read_unlock();
return NULL;
}
ref = atomic_inc_return(&pag->pag_ref);
rcu_read_unlock();
trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_);
return pag;
}
void
xfs_perag_put(
struct xfs_perag *pag)
{
int ref;
ASSERT(atomic_read(&pag->pag_ref) > 0);
ref = atomic_dec_return(&pag->pag_ref);
trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
}
/* Check all the superblock fields we care about when reading one in. */ /* Check all the superblock fields we care about when reading one in. */
STATIC int STATIC int
xfs_validate_sb_read( xfs_validate_sb_read(
...@@ -841,78 +780,6 @@ xfs_sb_mount_common( ...@@ -841,78 +780,6 @@ xfs_sb_mount_common(
mp->m_ag_max_usable = xfs_alloc_ag_max_usable(mp); mp->m_ag_max_usable = xfs_alloc_ag_max_usable(mp);
} }
/*
* xfs_initialize_perag_data
*
* Read in each per-ag structure so we can count up the number of
* allocated inodes, free inodes and used filesystem blocks as this
* information is no longer persistent in the superblock. Once we have
* this information, write it into the in-core superblock structure.
*/
int
xfs_initialize_perag_data(
struct xfs_mount *mp,
xfs_agnumber_t agcount)
{
xfs_agnumber_t index;
xfs_perag_t *pag;
xfs_sb_t *sbp = &mp->m_sb;
uint64_t ifree = 0;
uint64_t ialloc = 0;
uint64_t bfree = 0;
uint64_t bfreelst = 0;
uint64_t btree = 0;
uint64_t fdblocks;
int error = 0;
for (index = 0; index < agcount; index++) {
/*
* read the agf, then the agi. This gets us
* all the information we need and populates the
* per-ag structures for us.
*/
error = xfs_alloc_pagf_init(mp, NULL, index, 0);
if (error)
return error;
error = xfs_ialloc_pagi_init(mp, NULL, index);
if (error)
return error;
pag = xfs_perag_get(mp, index);
ifree += pag->pagi_freecount;
ialloc += pag->pagi_count;
bfree += pag->pagf_freeblks;
bfreelst += pag->pagf_flcount;
btree += pag->pagf_btreeblks;
xfs_perag_put(pag);
}
fdblocks = bfree + bfreelst + btree;
/*
* If the new summary counts are obviously incorrect, fail the
* mount operation because that implies the AGFs are also corrupt.
* Clear FS_COUNTERS so that we don't unmount with a dirty log, which
* will prevent xfs_repair from fixing anything.
*/
if (fdblocks > sbp->sb_dblocks || ifree > ialloc) {
xfs_alert(mp, "AGF corruption. Please run xfs_repair.");
error = -EFSCORRUPTED;
goto out;
}
/* Overwrite incore superblock counters with just-read data */
spin_lock(&mp->m_sb_lock);
sbp->sb_ifree = ifree;
sbp->sb_icount = ialloc;
sbp->sb_fdblocks = fdblocks;
spin_unlock(&mp->m_sb_lock);
xfs_reinit_percpu_counters(mp);
out:
xfs_fs_mark_healthy(mp, XFS_SICK_FS_COUNTERS);
return error;
}
/* /*
* xfs_log_sb() can be used to copy arbitrary changes to the in-core superblock * xfs_log_sb() can be used to copy arbitrary changes to the in-core superblock
* into the superblock buffer to be logged. It does not provide the higher * into the superblock buffer to be logged. It does not provide the higher
...@@ -989,17 +856,18 @@ int ...@@ -989,17 +856,18 @@ int
xfs_update_secondary_sbs( xfs_update_secondary_sbs(
struct xfs_mount *mp) struct xfs_mount *mp)
{ {
xfs_agnumber_t agno; struct xfs_perag *pag;
xfs_agnumber_t agno = 1;
int saved_error = 0; int saved_error = 0;
int error = 0; int error = 0;
LIST_HEAD (buffer_list); LIST_HEAD (buffer_list);
/* update secondary superblocks. */ /* update secondary superblocks. */
for (agno = 1; agno < mp->m_sb.sb_agcount; agno++) { for_each_perag_from(mp, agno, pag) {
struct xfs_buf *bp; struct xfs_buf *bp;
error = xfs_buf_get(mp->m_ddev_targp, error = xfs_buf_get(mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), XFS_AG_DADDR(mp, pag->pag_agno, XFS_SB_DADDR),
XFS_FSS_TO_BB(mp, 1), &bp); XFS_FSS_TO_BB(mp, 1), &bp);
/* /*
* If we get an error reading or writing alternate superblocks, * If we get an error reading or writing alternate superblocks,
...@@ -1011,7 +879,7 @@ xfs_update_secondary_sbs( ...@@ -1011,7 +879,7 @@ xfs_update_secondary_sbs(
if (error) { if (error) {
xfs_warn(mp, xfs_warn(mp,
"error allocating secondary superblock for ag %d", "error allocating secondary superblock for ag %d",
agno); pag->pag_agno);
if (!saved_error) if (!saved_error)
saved_error = error; saved_error = error;
continue; continue;
...@@ -1032,7 +900,7 @@ xfs_update_secondary_sbs( ...@@ -1032,7 +900,7 @@ xfs_update_secondary_sbs(
if (error) { if (error) {
xfs_warn(mp, xfs_warn(mp,
"write error %d updating a secondary superblock near ag %d", "write error %d updating a secondary superblock near ag %d",
error, agno); error, pag->pag_agno);
if (!saved_error) if (!saved_error)
saved_error = error; saved_error = error;
continue; continue;
......
...@@ -13,15 +13,6 @@ struct xfs_trans; ...@@ -13,15 +13,6 @@ struct xfs_trans;
struct xfs_fsop_geom; struct xfs_fsop_geom;
struct xfs_perag; struct xfs_perag;
/*
* perag get/put wrappers for ref counting
*/
extern struct xfs_perag *xfs_perag_get(struct xfs_mount *, xfs_agnumber_t);
extern struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t,
int tag);
extern void xfs_perag_put(struct xfs_perag *pag);
extern int xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
extern void xfs_log_sb(struct xfs_trans *tp); extern void xfs_log_sb(struct xfs_trans *tp);
extern int xfs_sync_sb(struct xfs_mount *mp, bool wait); extern int xfs_sync_sb(struct xfs_mount *mp, bool wait);
extern int xfs_sync_sb_buf(struct xfs_mount *mp); extern int xfs_sync_sb_buf(struct xfs_mount *mp);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_bit.h" #include "xfs_bit.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_ag.h"
/* Find the size of the AG, in blocks. */ /* Find the size of the AG, in blocks. */
inline xfs_agblock_t inline xfs_agblock_t
...@@ -222,12 +223,13 @@ xfs_icount_range( ...@@ -222,12 +223,13 @@ xfs_icount_range(
unsigned long long *max) unsigned long long *max)
{ {
unsigned long long nr_inos = 0; unsigned long long nr_inos = 0;
struct xfs_perag *pag;
xfs_agnumber_t agno; xfs_agnumber_t agno;
/* root, rtbitmap, rtsum all live in the first chunk */ /* root, rtbitmap, rtsum all live in the first chunk */
*min = XFS_INODES_PER_CHUNK; *min = XFS_INODES_PER_CHUNK;
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { for_each_perag(mp, agno, pag) {
xfs_agino_t first, last; xfs_agino_t first, last;
xfs_agino_range(mp, agno, &first, &last); xfs_agino_range(mp, agno, &first, &last);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "xfs_alloc.h" #include "xfs_alloc.h"
#include "xfs_ialloc.h" #include "xfs_ialloc.h"
#include "xfs_rmap.h" #include "xfs_rmap.h"
#include "xfs_ag.h"
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/common.h" #include "scrub/common.h"
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "xfs_rmap.h" #include "xfs_rmap.h"
#include "xfs_rmap_btree.h" #include "xfs_rmap_btree.h"
#include "xfs_refcount_btree.h" #include "xfs_refcount_btree.h"
#include "xfs_ag.h"
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/common.h" #include "scrub/common.h"
#include "scrub/trace.h" #include "scrub/trace.h"
...@@ -245,8 +246,8 @@ xrep_agf_calc_from_btrees( ...@@ -245,8 +246,8 @@ xrep_agf_calc_from_btrees(
int error; int error;
/* Update the AGF counters from the bnobt. */ /* Update the AGF counters from the bnobt. */
cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno, cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
XFS_BTNUM_BNO); sc->sa.pag, XFS_BTNUM_BNO);
error = xfs_alloc_query_all(cur, xrep_agf_walk_allocbt, &raa); error = xfs_alloc_query_all(cur, xrep_agf_walk_allocbt, &raa);
if (error) if (error)
goto err; goto err;
...@@ -259,8 +260,8 @@ xrep_agf_calc_from_btrees( ...@@ -259,8 +260,8 @@ xrep_agf_calc_from_btrees(
agf->agf_longest = cpu_to_be32(raa.longest); agf->agf_longest = cpu_to_be32(raa.longest);
/* Update the AGF counters from the cntbt. */ /* Update the AGF counters from the cntbt. */
cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno, cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
XFS_BTNUM_CNT); sc->sa.pag, XFS_BTNUM_CNT);
error = xfs_btree_count_blocks(cur, &blocks); error = xfs_btree_count_blocks(cur, &blocks);
if (error) if (error)
goto err; goto err;
...@@ -268,7 +269,7 @@ xrep_agf_calc_from_btrees( ...@@ -268,7 +269,7 @@ xrep_agf_calc_from_btrees(
btreeblks += blocks - 1; btreeblks += blocks - 1;
/* Update the AGF counters from the rmapbt. */ /* Update the AGF counters from the rmapbt. */
cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno); cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
error = xfs_btree_count_blocks(cur, &blocks); error = xfs_btree_count_blocks(cur, &blocks);
if (error) if (error)
goto err; goto err;
...@@ -281,7 +282,7 @@ xrep_agf_calc_from_btrees( ...@@ -281,7 +282,7 @@ xrep_agf_calc_from_btrees(
/* Update the AGF counters from the refcountbt. */ /* Update the AGF counters from the refcountbt. */
if (xfs_sb_version_hasreflink(&mp->m_sb)) { if (xfs_sb_version_hasreflink(&mp->m_sb)) {
cur = xfs_refcountbt_init_cursor(mp, sc->tp, agf_bp, cur = xfs_refcountbt_init_cursor(mp, sc->tp, agf_bp,
sc->sa.agno); sc->sa.pag);
error = xfs_btree_count_blocks(cur, &blocks); error = xfs_btree_count_blocks(cur, &blocks);
if (error) if (error)
goto err; goto err;
...@@ -453,7 +454,7 @@ xrep_agfl_walk_rmap( ...@@ -453,7 +454,7 @@ xrep_agfl_walk_rmap(
/* Record all the OWN_AG blocks. */ /* Record all the OWN_AG blocks. */
if (rec->rm_owner == XFS_RMAP_OWN_AG) { if (rec->rm_owner == XFS_RMAP_OWN_AG) {
fsb = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.agno, fsb = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.pag->pag_agno,
rec->rm_startblock); rec->rm_startblock);
error = xbitmap_set(ra->freesp, fsb, rec->rm_blockcount); error = xbitmap_set(ra->freesp, fsb, rec->rm_blockcount);
if (error) if (error)
...@@ -489,23 +490,23 @@ xrep_agfl_collect_blocks( ...@@ -489,23 +490,23 @@ xrep_agfl_collect_blocks(
xbitmap_init(&ra.agmetablocks); xbitmap_init(&ra.agmetablocks);
/* Find all space used by the free space btrees & rmapbt. */ /* Find all space used by the free space btrees & rmapbt. */
cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno); cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
error = xfs_rmap_query_all(cur, xrep_agfl_walk_rmap, &ra); error = xfs_rmap_query_all(cur, xrep_agfl_walk_rmap, &ra);
if (error) if (error)
goto err; goto err;
xfs_btree_del_cursor(cur, error); xfs_btree_del_cursor(cur, error);
/* Find all blocks currently being used by the bnobt. */ /* Find all blocks currently being used by the bnobt. */
cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno, cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
XFS_BTNUM_BNO); sc->sa.pag, XFS_BTNUM_BNO);
error = xbitmap_set_btblocks(&ra.agmetablocks, cur); error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
if (error) if (error)
goto err; goto err;
xfs_btree_del_cursor(cur, error); xfs_btree_del_cursor(cur, error);
/* Find all blocks currently being used by the cntbt. */ /* Find all blocks currently being used by the cntbt. */
cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno, cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
XFS_BTNUM_CNT); sc->sa.pag, XFS_BTNUM_CNT);
error = xbitmap_set_btblocks(&ra.agmetablocks, cur); error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
if (error) if (error)
goto err; goto err;
...@@ -805,8 +806,8 @@ xrep_agi_calc_from_btrees( ...@@ -805,8 +806,8 @@ xrep_agi_calc_from_btrees(
xfs_agino_t freecount; xfs_agino_t freecount;
int error; int error;
cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno, cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp,
XFS_BTNUM_INO); sc->sa.pag, XFS_BTNUM_INO);
error = xfs_ialloc_count_inodes(cur, &count, &freecount); error = xfs_ialloc_count_inodes(cur, &count, &freecount);
if (error) if (error)
goto err; goto err;
...@@ -827,8 +828,8 @@ xrep_agi_calc_from_btrees( ...@@ -827,8 +828,8 @@ xrep_agi_calc_from_btrees(
xfs_sb_version_hasinobtcounts(&mp->m_sb)) { xfs_sb_version_hasinobtcounts(&mp->m_sb)) {
xfs_agblock_t blocks; xfs_agblock_t blocks;
cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno, cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp,
XFS_BTNUM_FINO); sc->sa.pag, XFS_BTNUM_FINO);
error = xfs_btree_count_blocks(cur, &blocks); error = xfs_btree_count_blocks(cur, &blocks);
if (error) if (error)
goto err; goto err;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/common.h" #include "scrub/common.h"
#include "scrub/btree.h" #include "scrub/btree.h"
#include "xfs_ag.h"
/* /*
* Set us up to scrub free space btrees. * Set us up to scrub free space btrees.
...@@ -93,7 +94,7 @@ xchk_allocbt_rec( ...@@ -93,7 +94,7 @@ xchk_allocbt_rec(
union xfs_btree_rec *rec) union xfs_btree_rec *rec)
{ {
struct xfs_mount *mp = bs->cur->bc_mp; struct xfs_mount *mp = bs->cur->bc_mp;
xfs_agnumber_t agno = bs->cur->bc_ag.agno; xfs_agnumber_t agno = bs->cur->bc_ag.pag->pag_agno;
xfs_agblock_t bno; xfs_agblock_t bno;
xfs_extlen_t len; xfs_extlen_t len;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/common.h" #include "scrub/common.h"
#include "scrub/btree.h" #include "scrub/btree.h"
#include "xfs_ag.h"
/* Set us up with an inode's bmap. */ /* Set us up with an inode's bmap. */
int int
...@@ -514,7 +515,7 @@ xchk_bmap_check_rmap( ...@@ -514,7 +515,7 @@ xchk_bmap_check_rmap(
xchk_fblock_set_corrupt(sc, sbcri->whichfork, xchk_fblock_set_corrupt(sc, sbcri->whichfork,
rec->rm_offset); rec->rm_offset);
if (irec.br_startblock != XFS_AGB_TO_FSB(sc->mp, if (irec.br_startblock != XFS_AGB_TO_FSB(sc->mp,
cur->bc_ag.agno, rec->rm_startblock)) cur->bc_ag.pag->pag_agno, rec->rm_startblock))
xchk_fblock_set_corrupt(sc, sbcri->whichfork, xchk_fblock_set_corrupt(sc, sbcri->whichfork,
rec->rm_offset); rec->rm_offset);
if (irec.br_blockcount > rec->rm_blockcount) if (irec.br_blockcount > rec->rm_blockcount)
...@@ -544,18 +545,18 @@ STATIC int ...@@ -544,18 +545,18 @@ STATIC int
xchk_bmap_check_ag_rmaps( xchk_bmap_check_ag_rmaps(
struct xfs_scrub *sc, struct xfs_scrub *sc,
int whichfork, int whichfork,
xfs_agnumber_t agno) struct xfs_perag *pag)
{ {
struct xchk_bmap_check_rmap_info sbcri; struct xchk_bmap_check_rmap_info sbcri;
struct xfs_btree_cur *cur; struct xfs_btree_cur *cur;
struct xfs_buf *agf; struct xfs_buf *agf;
int error; int error;
error = xfs_alloc_read_agf(sc->mp, sc->tp, agno, 0, &agf); error = xfs_alloc_read_agf(sc->mp, sc->tp, pag->pag_agno, 0, &agf);
if (error) if (error)
return error; return error;
cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, agno); cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf, pag);
sbcri.sc = sc; sbcri.sc = sc;
sbcri.whichfork = whichfork; sbcri.whichfork = whichfork;
...@@ -575,6 +576,7 @@ xchk_bmap_check_rmaps( ...@@ -575,6 +576,7 @@ xchk_bmap_check_rmaps(
int whichfork) int whichfork)
{ {
struct xfs_ifork *ifp = XFS_IFORK_PTR(sc->ip, whichfork); struct xfs_ifork *ifp = XFS_IFORK_PTR(sc->ip, whichfork);
struct xfs_perag *pag;
xfs_agnumber_t agno; xfs_agnumber_t agno;
bool zero_size; bool zero_size;
int error; int error;
...@@ -607,15 +609,16 @@ xchk_bmap_check_rmaps( ...@@ -607,15 +609,16 @@ xchk_bmap_check_rmaps(
(zero_size || ifp->if_nextents > 0)) (zero_size || ifp->if_nextents > 0))
return 0; return 0;
for (agno = 0; agno < sc->mp->m_sb.sb_agcount; agno++) { for_each_perag(sc->mp, agno, pag) {
error = xchk_bmap_check_ag_rmaps(sc, whichfork, agno); error = xchk_bmap_check_ag_rmaps(sc, whichfork, pag);
if (error) if (error)
return error; break;
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
break; break;
} }
if (pag)
return 0; xfs_perag_put(pag);
return error;
} }
/* /*
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include "xfs_btree.h" #include "xfs_btree.h"
#include "xfs_log_format.h" #include "xfs_log_format.h"
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_inode.h" #include "xfs_inode.h"
#include "xfs_icache.h" #include "xfs_icache.h"
#include "xfs_alloc.h" #include "xfs_alloc.h"
...@@ -26,6 +25,7 @@ ...@@ -26,6 +25,7 @@
#include "xfs_trans_priv.h" #include "xfs_trans_priv.h"
#include "xfs_attr.h" #include "xfs_attr.h"
#include "xfs_reflink.h" #include "xfs_reflink.h"
#include "xfs_ag.h"
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/common.h" #include "scrub/common.h"
#include "scrub/trace.h" #include "scrub/trace.h"
...@@ -460,49 +460,48 @@ xchk_ag_btcur_init( ...@@ -460,49 +460,48 @@ xchk_ag_btcur_init(
struct xchk_ag *sa) struct xchk_ag *sa)
{ {
struct xfs_mount *mp = sc->mp; struct xfs_mount *mp = sc->mp;
xfs_agnumber_t agno = sa->agno;
xchk_perag_get(sc->mp, sa); xchk_perag_get(sc->mp, sa);
if (sa->agf_bp && if (sa->agf_bp &&
xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_BNO)) { xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_BNO)) {
/* Set up a bnobt cursor for cross-referencing. */ /* Set up a bnobt cursor for cross-referencing. */
sa->bno_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp, sa->bno_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
agno, XFS_BTNUM_BNO); sa->pag, XFS_BTNUM_BNO);
} }
if (sa->agf_bp && if (sa->agf_bp &&
xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_CNT)) { xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_CNT)) {
/* Set up a cntbt cursor for cross-referencing. */ /* Set up a cntbt cursor for cross-referencing. */
sa->cnt_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp, sa->cnt_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp,
agno, XFS_BTNUM_CNT); sa->pag, XFS_BTNUM_CNT);
} }
/* Set up a inobt cursor for cross-referencing. */ /* Set up a inobt cursor for cross-referencing. */
if (sa->agi_bp && if (sa->agi_bp &&
xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_INO)) { xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_INO)) {
sa->ino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp, sa->ino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
agno, XFS_BTNUM_INO); sa->pag, XFS_BTNUM_INO);
} }
/* Set up a finobt cursor for cross-referencing. */ /* Set up a finobt cursor for cross-referencing. */
if (sa->agi_bp && xfs_sb_version_hasfinobt(&mp->m_sb) && if (sa->agi_bp && xfs_sb_version_hasfinobt(&mp->m_sb) &&
xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_FINO)) { xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_FINO)) {
sa->fino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp, sa->fino_cur = xfs_inobt_init_cursor(mp, sc->tp, sa->agi_bp,
agno, XFS_BTNUM_FINO); sa->pag, XFS_BTNUM_FINO);
} }
/* Set up a rmapbt cursor for cross-referencing. */ /* Set up a rmapbt cursor for cross-referencing. */
if (sa->agf_bp && xfs_sb_version_hasrmapbt(&mp->m_sb) && if (sa->agf_bp && xfs_sb_version_hasrmapbt(&mp->m_sb) &&
xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_RMAP)) { xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_RMAP)) {
sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp, sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp,
agno); sa->pag);
} }
/* Set up a refcountbt cursor for cross-referencing. */ /* Set up a refcountbt cursor for cross-referencing. */
if (sa->agf_bp && xfs_sb_version_hasreflink(&mp->m_sb) && if (sa->agf_bp && xfs_sb_version_hasreflink(&mp->m_sb) &&
xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_REFC)) { xchk_ag_btree_healthy_enough(sc, sa->pag, XFS_BTNUM_REFC)) {
sa->refc_cur = xfs_refcountbt_init_cursor(mp, sc->tp, sa->refc_cur = xfs_refcountbt_init_cursor(mp, sc->tp,
sa->agf_bp, agno); sa->agf_bp, sa->pag);
} }
} }
......
...@@ -9,11 +9,11 @@ ...@@ -9,11 +9,11 @@
#include "xfs_format.h" #include "xfs_format.h"
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_sb.h"
#include "xfs_alloc.h" #include "xfs_alloc.h"
#include "xfs_ialloc.h" #include "xfs_ialloc.h"
#include "xfs_health.h" #include "xfs_health.h"
#include "xfs_btree.h" #include "xfs_btree.h"
#include "xfs_ag.h"
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/common.h" #include "scrub/common.h"
#include "scrub/trace.h" #include "scrub/trace.h"
...@@ -71,11 +71,11 @@ xchk_fscount_warmup( ...@@ -71,11 +71,11 @@ xchk_fscount_warmup(
xfs_agnumber_t agno; xfs_agnumber_t agno;
int error = 0; int error = 0;
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { for_each_perag(mp, agno, pag) {
pag = xfs_perag_get(mp, agno); if (xchk_should_terminate(sc, &error))
break;
if (pag->pagi_init && pag->pagf_init) if (pag->pagi_init && pag->pagf_init)
goto next_loop_perag; continue;
/* Lock both AG headers. */ /* Lock both AG headers. */
error = xfs_ialloc_read_agi(mp, sc->tp, agno, &agi_bp); error = xfs_ialloc_read_agi(mp, sc->tp, agno, &agi_bp);
...@@ -89,21 +89,15 @@ xchk_fscount_warmup( ...@@ -89,21 +89,15 @@ xchk_fscount_warmup(
* These are supposed to be initialized by the header read * These are supposed to be initialized by the header read
* function. * function.
*/ */
error = -EFSCORRUPTED; if (!pag->pagi_init || !pag->pagf_init) {
if (!pag->pagi_init || !pag->pagf_init) error = -EFSCORRUPTED;
break; break;
}
xfs_buf_relse(agf_bp); xfs_buf_relse(agf_bp);
agf_bp = NULL; agf_bp = NULL;
xfs_buf_relse(agi_bp); xfs_buf_relse(agi_bp);
agi_bp = NULL; agi_bp = NULL;
next_loop_perag:
xfs_perag_put(pag);
pag = NULL;
error = 0;
if (xchk_should_terminate(sc, &error))
break;
} }
if (agf_bp) if (agf_bp)
...@@ -196,13 +190,14 @@ xchk_fscount_aggregate_agcounts( ...@@ -196,13 +190,14 @@ xchk_fscount_aggregate_agcounts(
fsc->ifree = 0; fsc->ifree = 0;
fsc->fdblocks = 0; fsc->fdblocks = 0;
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { for_each_perag(mp, agno, pag) {
pag = xfs_perag_get(mp, agno); if (xchk_should_terminate(sc, &error))
break;
/* This somehow got unset since the warmup? */ /* This somehow got unset since the warmup? */
if (!pag->pagi_init || !pag->pagf_init) { if (!pag->pagi_init || !pag->pagf_init) {
xfs_perag_put(pag); error = -EFSCORRUPTED;
return -EFSCORRUPTED; break;
} }
/* Count all the inodes */ /* Count all the inodes */
...@@ -216,10 +211,8 @@ xchk_fscount_aggregate_agcounts( ...@@ -216,10 +211,8 @@ xchk_fscount_aggregate_agcounts(
fsc->fdblocks += pag->pagf_btreeblks; fsc->fdblocks += pag->pagf_btreeblks;
} else { } else {
error = xchk_fscount_btreeblks(sc, fsc, agno); error = xchk_fscount_btreeblks(sc, fsc, agno);
if (error) { if (error)
xfs_perag_put(pag);
break; break;
}
} }
/* /*
...@@ -229,12 +222,9 @@ xchk_fscount_aggregate_agcounts( ...@@ -229,12 +222,9 @@ xchk_fscount_aggregate_agcounts(
fsc->fdblocks -= pag->pag_meta_resv.ar_reserved; fsc->fdblocks -= pag->pag_meta_resv.ar_reserved;
fsc->fdblocks -= pag->pag_rmapbt_resv.ar_orig_reserved; fsc->fdblocks -= pag->pag_rmapbt_resv.ar_orig_reserved;
xfs_perag_put(pag);
if (xchk_should_terminate(sc, &error))
break;
} }
if (pag)
xfs_perag_put(pag);
if (error) if (error)
return error; return error;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
#include "xfs_shared.h" #include "xfs_shared.h"
#include "xfs_format.h" #include "xfs_format.h"
#include "xfs_btree.h" #include "xfs_btree.h"
#include "xfs_sb.h" #include "xfs_ag.h"
#include "xfs_health.h" #include "xfs_health.h"
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/health.h" #include "scrub/health.h"
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "scrub/common.h" #include "scrub/common.h"
#include "scrub/btree.h" #include "scrub/btree.h"
#include "scrub/trace.h" #include "scrub/trace.h"
#include "xfs_ag.h"
/* /*
* Set us up to scrub inode btrees. * Set us up to scrub inode btrees.
...@@ -103,7 +104,7 @@ xchk_iallocbt_chunk( ...@@ -103,7 +104,7 @@ xchk_iallocbt_chunk(
xfs_extlen_t len) xfs_extlen_t len)
{ {
struct xfs_mount *mp = bs->cur->bc_mp; struct xfs_mount *mp = bs->cur->bc_mp;
xfs_agnumber_t agno = bs->cur->bc_ag.agno; xfs_agnumber_t agno = bs->cur->bc_ag.pag->pag_agno;
xfs_agblock_t bno; xfs_agblock_t bno;
bno = XFS_AGINO_TO_AGBNO(mp, agino); bno = XFS_AGINO_TO_AGBNO(mp, agino);
...@@ -163,7 +164,7 @@ xchk_iallocbt_check_cluster_ifree( ...@@ -163,7 +164,7 @@ xchk_iallocbt_check_cluster_ifree(
* the record, compute which fs inode we're talking about. * the record, compute which fs inode we're talking about.
*/ */
agino = irec->ir_startino + irec_ino; agino = irec->ir_startino + irec_ino;
fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_ag.agno, agino); fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_ag.pag->pag_agno, agino);
irec_free = (irec->ir_free & XFS_INOBT_MASK(irec_ino)); irec_free = (irec->ir_free & XFS_INOBT_MASK(irec_ino));
if (be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC || if (be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC ||
...@@ -213,7 +214,7 @@ xchk_iallocbt_check_cluster( ...@@ -213,7 +214,7 @@ xchk_iallocbt_check_cluster(
struct xfs_mount *mp = bs->cur->bc_mp; struct xfs_mount *mp = bs->cur->bc_mp;
struct xfs_buf *cluster_bp; struct xfs_buf *cluster_bp;
unsigned int nr_inodes; unsigned int nr_inodes;
xfs_agnumber_t agno = bs->cur->bc_ag.agno; xfs_agnumber_t agno = bs->cur->bc_ag.pag->pag_agno;
xfs_agblock_t agbno; xfs_agblock_t agbno;
unsigned int cluster_index; unsigned int cluster_index;
uint16_t cluster_mask = 0; uint16_t cluster_mask = 0;
...@@ -423,7 +424,7 @@ xchk_iallocbt_rec( ...@@ -423,7 +424,7 @@ xchk_iallocbt_rec(
struct xchk_iallocbt *iabt = bs->private; struct xchk_iallocbt *iabt = bs->private;
struct xfs_inobt_rec_incore irec; struct xfs_inobt_rec_incore irec;
uint64_t holes; uint64_t holes;
xfs_agnumber_t agno = bs->cur->bc_ag.agno; xfs_agnumber_t agno = bs->cur->bc_ag.pag->pag_agno;
xfs_agino_t agino; xfs_agino_t agino;
xfs_extlen_t len; xfs_extlen_t len;
int holecount; int holecount;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/common.h" #include "scrub/common.h"
#include "scrub/btree.h" #include "scrub/btree.h"
#include "xfs_ag.h"
/* /*
* Set us up to scrub reference count btrees. * Set us up to scrub reference count btrees.
...@@ -333,7 +334,7 @@ xchk_refcountbt_rec( ...@@ -333,7 +334,7 @@ xchk_refcountbt_rec(
{ {
struct xfs_mount *mp = bs->cur->bc_mp; struct xfs_mount *mp = bs->cur->bc_mp;
xfs_agblock_t *cow_blocks = bs->private; xfs_agblock_t *cow_blocks = bs->private;
xfs_agnumber_t agno = bs->cur->bc_ag.agno; xfs_agnumber_t agno = bs->cur->bc_ag.pag->pag_agno;
xfs_agblock_t bno; xfs_agblock_t bno;
xfs_extlen_t len; xfs_extlen_t len;
xfs_nlink_t refcount; xfs_nlink_t refcount;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "xfs_rmap_btree.h" #include "xfs_rmap_btree.h"
#include "xfs_refcount_btree.h" #include "xfs_refcount_btree.h"
#include "xfs_extent_busy.h" #include "xfs_extent_busy.h"
#include "xfs_ag.h"
#include "xfs_ag_resv.h" #include "xfs_ag_resv.h"
#include "xfs_quota.h" #include "xfs_quota.h"
#include "scrub/scrub.h" #include "scrub/scrub.h"
...@@ -303,7 +304,7 @@ xrep_alloc_ag_block( ...@@ -303,7 +304,7 @@ xrep_alloc_ag_block(
return error; return error;
if (bno == NULLAGBLOCK) if (bno == NULLAGBLOCK)
return -ENOSPC; return -ENOSPC;
xfs_extent_busy_reuse(sc->mp, sc->sa.agno, bno, xfs_extent_busy_reuse(sc->mp, sc->sa.pag, bno,
1, false); 1, false);
*fsbno = XFS_AGB_TO_FSB(sc->mp, sc->sa.agno, bno); *fsbno = XFS_AGB_TO_FSB(sc->mp, sc->sa.agno, bno);
if (resv == XFS_AG_RESV_RMAPBT) if (resv == XFS_AG_RESV_RMAPBT)
...@@ -508,7 +509,7 @@ xrep_put_freelist( ...@@ -508,7 +509,7 @@ xrep_put_freelist(
* create an rmap for the block prior to merging it or else other * create an rmap for the block prior to merging it or else other
* parts will break. * parts will break.
*/ */
error = xfs_rmap_alloc(sc->tp, sc->sa.agf_bp, sc->sa.agno, agbno, 1, error = xfs_rmap_alloc(sc->tp, sc->sa.agf_bp, sc->sa.pag, agbno, 1,
&XFS_RMAP_OINFO_AG); &XFS_RMAP_OINFO_AG);
if (error) if (error)
return error; return error;
...@@ -518,7 +519,7 @@ xrep_put_freelist( ...@@ -518,7 +519,7 @@ xrep_put_freelist(
agbno, 0); agbno, 0);
if (error) if (error)
return error; return error;
xfs_extent_busy_insert(sc->tp, sc->sa.agno, agbno, 1, xfs_extent_busy_insert(sc->tp, sc->sa.pag, agbno, 1,
XFS_EXTENT_BUSY_SKIP_DISCARD); XFS_EXTENT_BUSY_SKIP_DISCARD);
return 0; return 0;
...@@ -554,7 +555,7 @@ xrep_reap_block( ...@@ -554,7 +555,7 @@ xrep_reap_block(
} else { } else {
agf_bp = sc->sa.agf_bp; agf_bp = sc->sa.agf_bp;
} }
cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, agno); cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, agf_bp, sc->sa.pag);
/* Can we find any other rmappings? */ /* Can we find any other rmappings? */
error = xfs_rmap_has_other_keys(cur, agbno, 1, oinfo, &has_other_rmap); error = xfs_rmap_has_other_keys(cur, agbno, 1, oinfo, &has_other_rmap);
...@@ -576,7 +577,8 @@ xrep_reap_block( ...@@ -576,7 +577,8 @@ xrep_reap_block(
* to run xfs_repair. * to run xfs_repair.
*/ */
if (has_other_rmap) if (has_other_rmap)
error = xfs_rmap_free(sc->tp, agf_bp, agno, agbno, 1, oinfo); error = xfs_rmap_free(sc->tp, agf_bp, sc->sa.pag, agbno,
1, oinfo);
else if (resv == XFS_AG_RESV_AGFL) else if (resv == XFS_AG_RESV_AGFL)
error = xrep_put_freelist(sc, agbno); error = xrep_put_freelist(sc, agbno);
else else
...@@ -891,7 +893,7 @@ xrep_find_ag_btree_roots( ...@@ -891,7 +893,7 @@ xrep_find_ag_btree_roots(
fab->height = 0; fab->height = 0;
} }
cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno); cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
error = xfs_rmap_query_all(cur, xrep_findroot_rmap, &ri); error = xfs_rmap_query_all(cur, xrep_findroot_rmap, &ri);
xfs_btree_del_cursor(cur, error); xfs_btree_del_cursor(cur, error);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/common.h" #include "scrub/common.h"
#include "scrub/btree.h" #include "scrub/btree.h"
#include "xfs_ag.h"
/* /*
* Set us up to scrub reverse mapping btrees. * Set us up to scrub reverse mapping btrees.
...@@ -91,7 +92,7 @@ xchk_rmapbt_rec( ...@@ -91,7 +92,7 @@ xchk_rmapbt_rec(
{ {
struct xfs_mount *mp = bs->cur->bc_mp; struct xfs_mount *mp = bs->cur->bc_mp;
struct xfs_rmap_irec irec; struct xfs_rmap_irec irec;
xfs_agnumber_t agno = bs->cur->bc_ag.agno; xfs_agnumber_t agno = bs->cur->bc_ag.pag->pag_agno;
bool non_inode; bool non_inode;
bool is_unwritten; bool is_unwritten;
bool is_bmbt; bool is_bmbt;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "xfs_inode.h" #include "xfs_inode.h"
#include "xfs_btree.h" #include "xfs_btree.h"
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "xfs_ag.h"
/* Figure out which block the btree cursor was pointing to. */ /* Figure out which block the btree cursor was pointing to. */
static inline xfs_fsblock_t static inline xfs_fsblock_t
...@@ -26,7 +27,7 @@ xchk_btree_cur_fsbno( ...@@ -26,7 +27,7 @@ xchk_btree_cur_fsbno(
cur->bc_flags & XFS_BTREE_LONG_PTRS) cur->bc_flags & XFS_BTREE_LONG_PTRS)
return XFS_INO_TO_FSB(cur->bc_mp, cur->bc_ino.ip->i_ino); return XFS_INO_TO_FSB(cur->bc_mp, cur->bc_ino.ip->i_ino);
else if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS)) else if (!(cur->bc_flags & XFS_BTREE_LONG_PTRS))
return XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.agno, 0); return XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.pag->pag_agno, 0);
return NULLFSBLOCK; return NULLFSBLOCK;
} }
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include "xfs_format.h" #include "xfs_format.h"
#include "xfs_log_format.h" #include "xfs_log_format.h"
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_sb.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_log.h" #include "xfs_log.h"
...@@ -19,6 +18,7 @@ ...@@ -19,6 +18,7 @@
#include "xfs_buf_item.h" #include "xfs_buf_item.h"
#include "xfs_errortag.h" #include "xfs_errortag.h"
#include "xfs_error.h" #include "xfs_error.h"
#include "xfs_ag.h"
static kmem_zone_t *xfs_buf_zone; static kmem_zone_t *xfs_buf_zone;
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include "xfs_format.h" #include "xfs_format.h"
#include "xfs_log_format.h" #include "xfs_log_format.h"
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_sb.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_btree.h" #include "xfs_btree.h"
#include "xfs_alloc_btree.h" #include "xfs_alloc_btree.h"
...@@ -18,6 +17,7 @@ ...@@ -18,6 +17,7 @@
#include "xfs_extent_busy.h" #include "xfs_extent_busy.h"
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_log.h" #include "xfs_log.h"
#include "xfs_ag.h"
STATIC int STATIC int
xfs_trim_extents( xfs_trim_extents(
...@@ -50,7 +50,7 @@ xfs_trim_extents( ...@@ -50,7 +50,7 @@ xfs_trim_extents(
goto out_put_perag; goto out_put_perag;
agf = agbp->b_addr; agf = agbp->b_addr;
cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT); cur = xfs_allocbt_init_cursor(mp, NULL, agbp, pag, XFS_BTNUM_CNT);
/* /*
* Look up the longest btree in the AGF and start with it. * Look up the longest btree in the AGF and start with it.
...@@ -108,7 +108,7 @@ xfs_trim_extents( ...@@ -108,7 +108,7 @@ xfs_trim_extents(
* If any blocks in the range are still busy, skip the * If any blocks in the range are still busy, skip the
* discard and try again the next time. * discard and try again the next time.
*/ */
if (xfs_extent_busy_search(mp, agno, fbno, flen)) { if (xfs_extent_busy_search(mp, pag, fbno, flen)) {
trace_xfs_discard_busy(mp, agno, fbno, flen); trace_xfs_discard_busy(mp, agno, fbno, flen);
goto next_extent; goto next_extent;
} }
......
...@@ -11,39 +11,37 @@ ...@@ -11,39 +11,37 @@
#include "xfs_log_format.h" #include "xfs_log_format.h"
#include "xfs_shared.h" #include "xfs_shared.h"
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_sb.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_alloc.h" #include "xfs_alloc.h"
#include "xfs_extent_busy.h" #include "xfs_extent_busy.h"
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_log.h" #include "xfs_log.h"
#include "xfs_ag.h"
void void
xfs_extent_busy_insert( xfs_extent_busy_insert(
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_agblock_t bno, xfs_agblock_t bno,
xfs_extlen_t len, xfs_extlen_t len,
unsigned int flags) unsigned int flags)
{ {
struct xfs_extent_busy *new; struct xfs_extent_busy *new;
struct xfs_extent_busy *busyp; struct xfs_extent_busy *busyp;
struct xfs_perag *pag;
struct rb_node **rbp; struct rb_node **rbp;
struct rb_node *parent = NULL; struct rb_node *parent = NULL;
new = kmem_zalloc(sizeof(struct xfs_extent_busy), 0); new = kmem_zalloc(sizeof(struct xfs_extent_busy), 0);
new->agno = agno; new->agno = pag->pag_agno;
new->bno = bno; new->bno = bno;
new->length = len; new->length = len;
INIT_LIST_HEAD(&new->list); INIT_LIST_HEAD(&new->list);
new->flags = flags; new->flags = flags;
/* trace before insert to be able to see failed inserts */ /* trace before insert to be able to see failed inserts */
trace_xfs_extent_busy(tp->t_mountp, agno, bno, len); trace_xfs_extent_busy(tp->t_mountp, pag->pag_agno, bno, len);
pag = xfs_perag_get(tp->t_mountp, new->agno);
spin_lock(&pag->pagb_lock); spin_lock(&pag->pagb_lock);
rbp = &pag->pagb_tree.rb_node; rbp = &pag->pagb_tree.rb_node;
while (*rbp) { while (*rbp) {
...@@ -66,7 +64,6 @@ xfs_extent_busy_insert( ...@@ -66,7 +64,6 @@ xfs_extent_busy_insert(
list_add(&new->list, &tp->t_busy); list_add(&new->list, &tp->t_busy);
spin_unlock(&pag->pagb_lock); spin_unlock(&pag->pagb_lock);
xfs_perag_put(pag);
} }
/* /*
...@@ -81,21 +78,17 @@ xfs_extent_busy_insert( ...@@ -81,21 +78,17 @@ xfs_extent_busy_insert(
int int
xfs_extent_busy_search( xfs_extent_busy_search(
struct xfs_mount *mp, struct xfs_mount *mp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_agblock_t bno, xfs_agblock_t bno,
xfs_extlen_t len) xfs_extlen_t len)
{ {
struct xfs_perag *pag;
struct rb_node *rbp; struct rb_node *rbp;
struct xfs_extent_busy *busyp; struct xfs_extent_busy *busyp;
int match = 0; int match = 0;
pag = xfs_perag_get(mp, agno); /* find closest start bno overlap */
spin_lock(&pag->pagb_lock); spin_lock(&pag->pagb_lock);
rbp = pag->pagb_tree.rb_node; rbp = pag->pagb_tree.rb_node;
/* find closest start bno overlap */
while (rbp) { while (rbp) {
busyp = rb_entry(rbp, struct xfs_extent_busy, rb_node); busyp = rb_entry(rbp, struct xfs_extent_busy, rb_node);
if (bno < busyp->bno) { if (bno < busyp->bno) {
...@@ -115,7 +108,6 @@ xfs_extent_busy_search( ...@@ -115,7 +108,6 @@ xfs_extent_busy_search(
} }
} }
spin_unlock(&pag->pagb_lock); spin_unlock(&pag->pagb_lock);
xfs_perag_put(pag);
return match; return match;
} }
...@@ -281,17 +273,14 @@ xfs_extent_busy_update_extent( ...@@ -281,17 +273,14 @@ xfs_extent_busy_update_extent(
void void
xfs_extent_busy_reuse( xfs_extent_busy_reuse(
struct xfs_mount *mp, struct xfs_mount *mp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_agblock_t fbno, xfs_agblock_t fbno,
xfs_extlen_t flen, xfs_extlen_t flen,
bool userdata) bool userdata)
{ {
struct xfs_perag *pag;
struct rb_node *rbp; struct rb_node *rbp;
ASSERT(flen > 0); ASSERT(flen > 0);
pag = xfs_perag_get(mp, agno);
spin_lock(&pag->pagb_lock); spin_lock(&pag->pagb_lock);
restart: restart:
rbp = pag->pagb_tree.rb_node; rbp = pag->pagb_tree.rb_node;
...@@ -314,7 +303,6 @@ xfs_extent_busy_reuse( ...@@ -314,7 +303,6 @@ xfs_extent_busy_reuse(
goto restart; goto restart;
} }
spin_unlock(&pag->pagb_lock); spin_unlock(&pag->pagb_lock);
xfs_perag_put(pag);
} }
/* /*
...@@ -605,12 +593,11 @@ void ...@@ -605,12 +593,11 @@ void
xfs_extent_busy_wait_all( xfs_extent_busy_wait_all(
struct xfs_mount *mp) struct xfs_mount *mp)
{ {
struct xfs_perag *pag;
DEFINE_WAIT (wait); DEFINE_WAIT (wait);
xfs_agnumber_t agno; xfs_agnumber_t agno;
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { for_each_perag(mp, agno, pag) {
struct xfs_perag *pag = xfs_perag_get(mp, agno);
do { do {
prepare_to_wait(&pag->pagb_wait, &wait, TASK_KILLABLE); prepare_to_wait(&pag->pagb_wait, &wait, TASK_KILLABLE);
if (RB_EMPTY_ROOT(&pag->pagb_tree)) if (RB_EMPTY_ROOT(&pag->pagb_tree))
...@@ -618,8 +605,6 @@ xfs_extent_busy_wait_all( ...@@ -618,8 +605,6 @@ xfs_extent_busy_wait_all(
schedule(); schedule();
} while (1); } while (1);
finish_wait(&pag->pagb_wait, &wait); finish_wait(&pag->pagb_wait, &wait);
xfs_perag_put(pag);
} }
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#define __XFS_EXTENT_BUSY_H__ #define __XFS_EXTENT_BUSY_H__
struct xfs_mount; struct xfs_mount;
struct xfs_perag;
struct xfs_trans; struct xfs_trans;
struct xfs_alloc_arg; struct xfs_alloc_arg;
...@@ -31,7 +32,7 @@ struct xfs_extent_busy { ...@@ -31,7 +32,7 @@ struct xfs_extent_busy {
}; };
void void
xfs_extent_busy_insert(struct xfs_trans *tp, xfs_agnumber_t agno, xfs_extent_busy_insert(struct xfs_trans *tp, struct xfs_perag *pag,
xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags); xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags);
void void
...@@ -39,11 +40,11 @@ xfs_extent_busy_clear(struct xfs_mount *mp, struct list_head *list, ...@@ -39,11 +40,11 @@ xfs_extent_busy_clear(struct xfs_mount *mp, struct list_head *list,
bool do_discard); bool do_discard);
int int
xfs_extent_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_extent_busy_search(struct xfs_mount *mp, struct xfs_perag *pag,
xfs_agblock_t bno, xfs_extlen_t len); xfs_agblock_t bno, xfs_extlen_t len);
void void
xfs_extent_busy_reuse(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_extent_busy_reuse(struct xfs_mount *mp, struct xfs_perag *pag,
xfs_agblock_t fbno, xfs_extlen_t flen, bool userdata); xfs_agblock_t fbno, xfs_extlen_t flen, bool userdata);
bool bool
......
...@@ -9,13 +9,13 @@ ...@@ -9,13 +9,13 @@
#include "xfs_format.h" #include "xfs_format.h"
#include "xfs_log_format.h" #include "xfs_log_format.h"
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_sb.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_inode.h" #include "xfs_inode.h"
#include "xfs_bmap.h" #include "xfs_bmap.h"
#include "xfs_alloc.h" #include "xfs_alloc.h"
#include "xfs_mru_cache.h" #include "xfs_mru_cache.h"
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_ag.h"
#include "xfs_ag_resv.h" #include "xfs_ag_resv.h"
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_filestream.h" #include "xfs_filestream.h"
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "xfs_refcount_btree.h" #include "xfs_refcount_btree.h"
#include "xfs_alloc_btree.h" #include "xfs_alloc_btree.h"
#include "xfs_rtalloc.h" #include "xfs_rtalloc.h"
#include "xfs_ag.h"
/* Convert an xfs_fsmap to an fsmap. */ /* Convert an xfs_fsmap to an fsmap. */
static void static void
...@@ -157,10 +158,10 @@ struct xfs_getfsmap_info { ...@@ -157,10 +158,10 @@ struct xfs_getfsmap_info {
struct xfs_fsmap_head *head; struct xfs_fsmap_head *head;
struct fsmap *fsmap_recs; /* mapping records */ struct fsmap *fsmap_recs; /* mapping records */
struct xfs_buf *agf_bp; /* AGF, for refcount queries */ struct xfs_buf *agf_bp; /* AGF, for refcount queries */
struct xfs_perag *pag; /* AG info, if applicable */
xfs_daddr_t next_daddr; /* next daddr we expect */ xfs_daddr_t next_daddr; /* next daddr we expect */
u64 missing_owner; /* owner of holes */ u64 missing_owner; /* owner of holes */
u32 dev; /* device id */ u32 dev; /* device id */
xfs_agnumber_t agno; /* AG number, if applicable */
struct xfs_rmap_irec low; /* low rmap key */ struct xfs_rmap_irec low; /* low rmap key */
struct xfs_rmap_irec high; /* high rmap key */ struct xfs_rmap_irec high; /* high rmap key */
bool last; /* last extent? */ bool last; /* last extent? */
...@@ -203,14 +204,13 @@ xfs_getfsmap_is_shared( ...@@ -203,14 +204,13 @@ xfs_getfsmap_is_shared(
*stat = false; *stat = false;
if (!xfs_sb_version_hasreflink(&mp->m_sb)) if (!xfs_sb_version_hasreflink(&mp->m_sb))
return 0; return 0;
/* rt files will have agno set to NULLAGNUMBER */ /* rt files will have no perag structure */
if (info->agno == NULLAGNUMBER) if (!info->pag)
return 0; return 0;
/* Are there any shared blocks here? */ /* Are there any shared blocks here? */
flen = 0; flen = 0;
cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp, cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp, info->pag);
info->agno);
error = xfs_refcount_find_shared(cur, rec->rm_startblock, error = xfs_refcount_find_shared(cur, rec->rm_startblock,
rec->rm_blockcount, &fbno, &flen, false); rec->rm_blockcount, &fbno, &flen, false);
...@@ -311,7 +311,8 @@ xfs_getfsmap_helper( ...@@ -311,7 +311,8 @@ xfs_getfsmap_helper(
if (info->head->fmh_entries >= info->head->fmh_count) if (info->head->fmh_entries >= info->head->fmh_count)
return -ECANCELED; return -ECANCELED;
trace_xfs_fsmap_mapping(mp, info->dev, info->agno, rec); trace_xfs_fsmap_mapping(mp, info->dev,
info->pag ? info->pag->pag_agno : NULLAGNUMBER, rec);
fmr.fmr_device = info->dev; fmr.fmr_device = info->dev;
fmr.fmr_physical = rec_daddr; fmr.fmr_physical = rec_daddr;
...@@ -354,7 +355,7 @@ xfs_getfsmap_datadev_helper( ...@@ -354,7 +355,7 @@ xfs_getfsmap_datadev_helper(
xfs_fsblock_t fsb; xfs_fsblock_t fsb;
xfs_daddr_t rec_daddr; xfs_daddr_t rec_daddr;
fsb = XFS_AGB_TO_FSB(mp, cur->bc_ag.agno, rec->rm_startblock); fsb = XFS_AGB_TO_FSB(mp, cur->bc_ag.pag->pag_agno, rec->rm_startblock);
rec_daddr = XFS_FSB_TO_DADDR(mp, fsb); rec_daddr = XFS_FSB_TO_DADDR(mp, fsb);
return xfs_getfsmap_helper(cur->bc_tp, info, rec, rec_daddr); return xfs_getfsmap_helper(cur->bc_tp, info, rec, rec_daddr);
...@@ -372,7 +373,7 @@ xfs_getfsmap_datadev_bnobt_helper( ...@@ -372,7 +373,7 @@ xfs_getfsmap_datadev_bnobt_helper(
struct xfs_rmap_irec irec; struct xfs_rmap_irec irec;
xfs_daddr_t rec_daddr; xfs_daddr_t rec_daddr;
rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.agno, rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_ag.pag->pag_agno,
rec->ar_startblock); rec->ar_startblock);
irec.rm_startblock = rec->ar_startblock; irec.rm_startblock = rec->ar_startblock;
...@@ -429,8 +430,8 @@ xfs_getfsmap_logdev( ...@@ -429,8 +430,8 @@ xfs_getfsmap_logdev(
info->high.rm_flags = XFS_RMAP_KEY_FLAGS | XFS_RMAP_REC_FLAGS; info->high.rm_flags = XFS_RMAP_KEY_FLAGS | XFS_RMAP_REC_FLAGS;
info->missing_owner = XFS_FMR_OWN_FREE; info->missing_owner = XFS_FMR_OWN_FREE;
trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low); trace_xfs_fsmap_low_key(mp, info->dev, NULLAGNUMBER, &info->low);
trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->high); trace_xfs_fsmap_high_key(mp, info->dev, NULLAGNUMBER, &info->high);
if (keys[0].fmr_physical > 0) if (keys[0].fmr_physical > 0)
return 0; return 0;
...@@ -508,8 +509,8 @@ __xfs_getfsmap_rtdev( ...@@ -508,8 +509,8 @@ __xfs_getfsmap_rtdev(
info->high.rm_blockcount = 0; info->high.rm_blockcount = 0;
xfs_getfsmap_set_irec_flags(&info->high, &keys[1]); xfs_getfsmap_set_irec_flags(&info->high, &keys[1]);
trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low); trace_xfs_fsmap_low_key(mp, info->dev, NULLAGNUMBER, &info->low);
trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->high); trace_xfs_fsmap_high_key(mp, info->dev, NULLAGNUMBER, &info->high);
return query_fn(tp, info); return query_fn(tp, info);
} }
...@@ -572,6 +573,7 @@ __xfs_getfsmap_datadev( ...@@ -572,6 +573,7 @@ __xfs_getfsmap_datadev(
void *priv) void *priv)
{ {
struct xfs_mount *mp = tp->t_mountp; struct xfs_mount *mp = tp->t_mountp;
struct xfs_perag *pag;
struct xfs_btree_cur *bt_cur = NULL; struct xfs_btree_cur *bt_cur = NULL;
xfs_fsblock_t start_fsb; xfs_fsblock_t start_fsb;
xfs_fsblock_t end_fsb; xfs_fsblock_t end_fsb;
...@@ -610,20 +612,20 @@ __xfs_getfsmap_datadev( ...@@ -610,20 +612,20 @@ __xfs_getfsmap_datadev(
start_ag = XFS_FSB_TO_AGNO(mp, start_fsb); start_ag = XFS_FSB_TO_AGNO(mp, start_fsb);
end_ag = XFS_FSB_TO_AGNO(mp, end_fsb); end_ag = XFS_FSB_TO_AGNO(mp, end_fsb);
/* Query each AG */ for_each_perag_range(mp, start_ag, end_ag, pag) {
for (info->agno = start_ag; info->agno <= end_ag; info->agno++) {
/* /*
* Set the AG high key from the fsmap high key if this * Set the AG high key from the fsmap high key if this
* is the last AG that we're querying. * is the last AG that we're querying.
*/ */
if (info->agno == end_ag) { info->pag = pag;
if (pag->pag_agno == end_ag) {
info->high.rm_startblock = XFS_FSB_TO_AGBNO(mp, info->high.rm_startblock = XFS_FSB_TO_AGBNO(mp,
end_fsb); end_fsb);
info->high.rm_offset = XFS_BB_TO_FSBT(mp, info->high.rm_offset = XFS_BB_TO_FSBT(mp,
keys[1].fmr_offset); keys[1].fmr_offset);
error = xfs_fsmap_owner_to_rmap(&info->high, &keys[1]); error = xfs_fsmap_owner_to_rmap(&info->high, &keys[1]);
if (error) if (error)
goto err; break;
xfs_getfsmap_set_irec_flags(&info->high, &keys[1]); xfs_getfsmap_set_irec_flags(&info->high, &keys[1]);
} }
...@@ -634,38 +636,45 @@ __xfs_getfsmap_datadev( ...@@ -634,38 +636,45 @@ __xfs_getfsmap_datadev(
info->agf_bp = NULL; info->agf_bp = NULL;
} }
error = xfs_alloc_read_agf(mp, tp, info->agno, 0, error = xfs_alloc_read_agf(mp, tp, pag->pag_agno, 0,
&info->agf_bp); &info->agf_bp);
if (error) if (error)
goto err; break;
trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low); trace_xfs_fsmap_low_key(mp, info->dev, pag->pag_agno,
trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->low);
trace_xfs_fsmap_high_key(mp, info->dev, pag->pag_agno,
&info->high); &info->high);
error = query_fn(tp, info, &bt_cur, priv); error = query_fn(tp, info, &bt_cur, priv);
if (error) if (error)
goto err; break;
/* /*
* Set the AG low key to the start of the AG prior to * Set the AG low key to the start of the AG prior to
* moving on to the next AG. * moving on to the next AG.
*/ */
if (info->agno == start_ag) { if (pag->pag_agno == start_ag) {
info->low.rm_startblock = 0; info->low.rm_startblock = 0;
info->low.rm_owner = 0; info->low.rm_owner = 0;
info->low.rm_offset = 0; info->low.rm_offset = 0;
info->low.rm_flags = 0; info->low.rm_flags = 0;
} }
}
/* Report any gap at the end of the AG */ /*
info->last = true; * If this is the last AG, report any gap at the end of it
error = query_fn(tp, info, &bt_cur, priv); * before we drop the reference to the perag when the loop
if (error) * terminates.
goto err; */
if (pag->pag_agno == end_ag) {
info->last = true;
error = query_fn(tp, info, &bt_cur, priv);
if (error)
break;
}
info->pag = NULL;
}
err:
if (bt_cur) if (bt_cur)
xfs_btree_del_cursor(bt_cur, error < 0 ? XFS_BTREE_ERROR : xfs_btree_del_cursor(bt_cur, error < 0 ? XFS_BTREE_ERROR :
XFS_BTREE_NOERROR); XFS_BTREE_NOERROR);
...@@ -673,6 +682,13 @@ __xfs_getfsmap_datadev( ...@@ -673,6 +682,13 @@ __xfs_getfsmap_datadev(
xfs_trans_brelse(tp, info->agf_bp); xfs_trans_brelse(tp, info->agf_bp);
info->agf_bp = NULL; info->agf_bp = NULL;
} }
if (info->pag) {
xfs_perag_put(info->pag);
info->pag = NULL;
} else if (pag) {
/* loop termination case */
xfs_perag_put(pag);
}
return error; return error;
} }
...@@ -691,7 +707,7 @@ xfs_getfsmap_datadev_rmapbt_query( ...@@ -691,7 +707,7 @@ xfs_getfsmap_datadev_rmapbt_query(
/* Allocate cursor for this AG and query_range it. */ /* Allocate cursor for this AG and query_range it. */
*curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp, *curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
info->agno); info->pag);
return xfs_rmap_query_range(*curpp, &info->low, &info->high, return xfs_rmap_query_range(*curpp, &info->low, &info->high,
xfs_getfsmap_datadev_helper, info); xfs_getfsmap_datadev_helper, info);
} }
...@@ -724,7 +740,7 @@ xfs_getfsmap_datadev_bnobt_query( ...@@ -724,7 +740,7 @@ xfs_getfsmap_datadev_bnobt_query(
/* Allocate cursor for this AG and query_range it. */ /* Allocate cursor for this AG and query_range it. */
*curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp, *curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
info->agno, XFS_BTNUM_BNO); info->pag, XFS_BTNUM_BNO);
key->ar_startblock = info->low.rm_startblock; key->ar_startblock = info->low.rm_startblock;
key[1].ar_startblock = info->high.rm_startblock; key[1].ar_startblock = info->high.rm_startblock;
return xfs_alloc_query_range(*curpp, key, &key[1], return xfs_alloc_query_range(*curpp, key, &key[1],
...@@ -937,7 +953,7 @@ xfs_getfsmap( ...@@ -937,7 +953,7 @@ xfs_getfsmap(
info.dev = handlers[i].dev; info.dev = handlers[i].dev;
info.last = false; info.last = false;
info.agno = NULLAGNUMBER; info.pag = NULL;
error = handlers[i].fn(tp, dkeys, &info); error = handlers[i].fn(tp, dkeys, &info);
if (error) if (error)
break; break;
......
...@@ -576,10 +576,8 @@ xfs_fs_reserve_ag_blocks( ...@@ -576,10 +576,8 @@ xfs_fs_reserve_ag_blocks(
int err2; int err2;
mp->m_finobt_nores = false; mp->m_finobt_nores = false;
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { for_each_perag(mp, agno, pag) {
pag = xfs_perag_get(mp, agno);
err2 = xfs_ag_resv_init(pag, NULL); err2 = xfs_ag_resv_init(pag, NULL);
xfs_perag_put(pag);
if (err2 && !error) if (err2 && !error)
error = err2; error = err2;
} }
...@@ -605,10 +603,8 @@ xfs_fs_unreserve_ag_blocks( ...@@ -605,10 +603,8 @@ xfs_fs_unreserve_ag_blocks(
int error = 0; int error = 0;
int err2; int err2;
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { for_each_perag(mp, agno, pag) {
pag = xfs_perag_get(mp, agno);
err2 = xfs_ag_resv_free(pag); err2 = xfs_ag_resv_free(pag);
xfs_perag_put(pag);
if (err2 && !error) if (err2 && !error)
error = err2; error = err2;
} }
......
...@@ -9,11 +9,11 @@ ...@@ -9,11 +9,11 @@
#include "xfs_format.h" #include "xfs_format.h"
#include "xfs_log_format.h" #include "xfs_log_format.h"
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_sb.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_inode.h" #include "xfs_inode.h"
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_health.h" #include "xfs_health.h"
#include "xfs_ag.h"
/* /*
* Warn about metadata corruption that we detected but haven't fixed, and * Warn about metadata corruption that we detected but haven't fixed, and
...@@ -34,14 +34,12 @@ xfs_health_unmount( ...@@ -34,14 +34,12 @@ xfs_health_unmount(
return; return;
/* Measure AG corruption levels. */ /* Measure AG corruption levels. */
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { for_each_perag(mp, agno, pag) {
pag = xfs_perag_get(mp, agno);
xfs_ag_measure_sickness(pag, &sick, &checked); xfs_ag_measure_sickness(pag, &sick, &checked);
if (sick) { if (sick) {
trace_xfs_ag_unfixed_corruption(mp, agno, sick); trace_xfs_ag_unfixed_corruption(mp, agno, sick);
warn = true; warn = true;
} }
xfs_perag_put(pag);
} }
/* Measure realtime volume corruption levels. */ /* Measure realtime volume corruption levels. */
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include "xfs_format.h" #include "xfs_format.h"
#include "xfs_log_format.h" #include "xfs_log_format.h"
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_sb.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_inode.h" #include "xfs_inode.h"
#include "xfs_trans.h" #include "xfs_trans.h"
...@@ -23,6 +22,7 @@ ...@@ -23,6 +22,7 @@
#include "xfs_dquot.h" #include "xfs_dquot.h"
#include "xfs_reflink.h" #include "xfs_reflink.h"
#include "xfs_ialloc.h" #include "xfs_ialloc.h"
#include "xfs_ag.h"
#include <linux/iversion.h> #include <linux/iversion.h>
...@@ -1061,15 +1061,13 @@ xfs_reclaim_inodes_ag( ...@@ -1061,15 +1061,13 @@ xfs_reclaim_inodes_ag(
int *nr_to_scan) int *nr_to_scan)
{ {
struct xfs_perag *pag; struct xfs_perag *pag;
xfs_agnumber_t ag = 0; xfs_agnumber_t agno;
while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) { for_each_perag_tag(mp, agno, pag, XFS_ICI_RECLAIM_TAG) {
unsigned long first_index = 0; unsigned long first_index = 0;
int done = 0; int done = 0;
int nr_found = 0; int nr_found = 0;
ag = pag->pag_agno + 1;
first_index = READ_ONCE(pag->pag_ici_reclaim_cursor); first_index = READ_ONCE(pag->pag_ici_reclaim_cursor);
do { do {
struct xfs_inode *batch[XFS_LOOKUP_BATCH]; struct xfs_inode *batch[XFS_LOOKUP_BATCH];
...@@ -1134,7 +1132,6 @@ xfs_reclaim_inodes_ag( ...@@ -1134,7 +1132,6 @@ xfs_reclaim_inodes_ag(
if (done) if (done)
first_index = 0; first_index = 0;
WRITE_ONCE(pag->pag_ici_reclaim_cursor, first_index); WRITE_ONCE(pag->pag_ici_reclaim_cursor, first_index);
xfs_perag_put(pag);
} }
} }
...@@ -1554,14 +1551,6 @@ xfs_inode_clear_cowblocks_tag( ...@@ -1554,14 +1551,6 @@ xfs_inode_clear_cowblocks_tag(
return xfs_blockgc_clear_iflag(ip, XFS_ICOWBLOCKS); return xfs_blockgc_clear_iflag(ip, XFS_ICOWBLOCKS);
} }
#define for_each_perag_tag(mp, next_agno, pag, tag) \
for ((next_agno) = 0, (pag) = xfs_perag_get_tag((mp), 0, (tag)); \
(pag) != NULL; \
(next_agno) = (pag)->pag_agno + 1, \
xfs_perag_put(pag), \
(pag) = xfs_perag_get_tag((mp), (next_agno), (tag)))
/* Disable post-EOF and CoW block auto-reclamation. */ /* Disable post-EOF and CoW block auto-reclamation. */
void void
xfs_blockgc_stop( xfs_blockgc_stop(
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "xfs_format.h" #include "xfs_format.h"
#include "xfs_log_format.h" #include "xfs_log_format.h"
#include "xfs_trans_resv.h" #include "xfs_trans_resv.h"
#include "xfs_sb.h"
#include "xfs_mount.h" #include "xfs_mount.h"
#include "xfs_defer.h" #include "xfs_defer.h"
#include "xfs_inode.h" #include "xfs_inode.h"
...@@ -35,6 +34,7 @@ ...@@ -35,6 +34,7 @@
#include "xfs_log.h" #include "xfs_log.h"
#include "xfs_bmap_btree.h" #include "xfs_bmap_btree.h"
#include "xfs_reflink.h" #include "xfs_reflink.h"
#include "xfs_ag.h"
kmem_zone_t *xfs_inode_zone; kmem_zone_t *xfs_inode_zone;
...@@ -45,7 +45,8 @@ kmem_zone_t *xfs_inode_zone; ...@@ -45,7 +45,8 @@ kmem_zone_t *xfs_inode_zone;
#define XFS_ITRUNC_MAX_EXTENTS 2 #define XFS_ITRUNC_MAX_EXTENTS 2
STATIC int xfs_iunlink(struct xfs_trans *, struct xfs_inode *); STATIC int xfs_iunlink(struct xfs_trans *, struct xfs_inode *);
STATIC int xfs_iunlink_remove(struct xfs_trans *, struct xfs_inode *); STATIC int xfs_iunlink_remove(struct xfs_trans *tp, struct xfs_perag *pag,
struct xfs_inode *);
/* /*
* helper function to extract extent size hint from inode * helper function to extract extent size hint from inode
...@@ -778,7 +779,7 @@ xfs_inode_inherit_flags2( ...@@ -778,7 +779,7 @@ xfs_inode_inherit_flags2(
* Initialise a newly allocated inode and return the in-core inode to the * Initialise a newly allocated inode and return the in-core inode to the
* caller locked exclusively. * caller locked exclusively.
*/ */
static int int
xfs_init_new_inode( xfs_init_new_inode(
struct user_namespace *mnt_userns, struct user_namespace *mnt_userns,
struct xfs_trans *tp, struct xfs_trans *tp,
...@@ -914,57 +915,6 @@ xfs_init_new_inode( ...@@ -914,57 +915,6 @@ xfs_init_new_inode(
return 0; return 0;
} }
/*
* Allocates a new inode from disk and return a pointer to the incore copy. This
* routine will internally commit the current transaction and allocate a new one
* if we needed to allocate more on-disk free inodes to perform the requested
* operation.
*
* If we are allocating quota inodes, we do not have a parent inode to attach to
* or associate with (i.e. dp == NULL) because they are not linked into the
* directory structure - they are attached directly to the superblock - and so
* have no parent.
*/
int
xfs_dir_ialloc(
struct user_namespace *mnt_userns,
struct xfs_trans **tpp,
struct xfs_inode *dp,
umode_t mode,
xfs_nlink_t nlink,
dev_t rdev,
prid_t prid,
bool init_xattrs,
struct xfs_inode **ipp)
{
struct xfs_buf *agibp;
xfs_ino_t parent_ino = dp ? dp->i_ino : 0;
xfs_ino_t ino;
int error;
ASSERT((*tpp)->t_flags & XFS_TRANS_PERM_LOG_RES);
/*
* Call the space management code to pick the on-disk inode to be
* allocated.
*/
error = xfs_dialloc_select_ag(tpp, parent_ino, mode, &agibp);
if (error)
return error;
if (!agibp)
return -ENOSPC;
/* Allocate an inode from the selected AG */
error = xfs_dialloc_ag(*tpp, agibp, parent_ino, &ino);
if (error)
return error;
ASSERT(ino != NULLFSINO);
return xfs_init_new_inode(mnt_userns, *tpp, dp, ino, mode, nlink, rdev,
prid, init_xattrs, ipp);
}
/* /*
* Decrement the link count on an inode & log the change. If this causes the * Decrement the link count on an inode & log the change. If this causes the
* link count to go to zero, move the inode to AGI unlinked list so that it can * link count to go to zero, move the inode to AGI unlinked list so that it can
...@@ -1022,6 +972,7 @@ xfs_create( ...@@ -1022,6 +972,7 @@ xfs_create(
struct xfs_dquot *pdqp = NULL; struct xfs_dquot *pdqp = NULL;
struct xfs_trans_res *tres; struct xfs_trans_res *tres;
uint resblks; uint resblks;
xfs_ino_t ino;
trace_xfs_create(dp, name); trace_xfs_create(dp, name);
...@@ -1078,14 +1029,16 @@ xfs_create( ...@@ -1078,14 +1029,16 @@ xfs_create(
* entry pointing to them, but a directory also the "." entry * entry pointing to them, but a directory also the "." entry
* pointing to itself. * pointing to itself.
*/ */
error = xfs_dir_ialloc(mnt_userns, &tp, dp, mode, is_dir ? 2 : 1, rdev, error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
prid, init_xattrs, &ip); if (!error)
error = xfs_init_new_inode(mnt_userns, tp, dp, ino, mode,
is_dir ? 2 : 1, rdev, prid, init_xattrs, &ip);
if (error) if (error)
goto out_trans_cancel; goto out_trans_cancel;
/* /*
* Now we join the directory inode to the transaction. We do not do it * Now we join the directory inode to the transaction. We do not do it
* earlier because xfs_dir_ialloc might commit the previous transaction * earlier because xfs_dialloc might commit the previous transaction
* (and release all the locks). An error from here on will result in * (and release all the locks). An error from here on will result in
* the transaction cancel unlocking dp so don't do it explicitly in the * the transaction cancel unlocking dp so don't do it explicitly in the
* error path. * error path.
...@@ -1175,6 +1128,7 @@ xfs_create_tmpfile( ...@@ -1175,6 +1128,7 @@ xfs_create_tmpfile(
struct xfs_dquot *pdqp = NULL; struct xfs_dquot *pdqp = NULL;
struct xfs_trans_res *tres; struct xfs_trans_res *tres;
uint resblks; uint resblks;
xfs_ino_t ino;
if (XFS_FORCED_SHUTDOWN(mp)) if (XFS_FORCED_SHUTDOWN(mp))
return -EIO; return -EIO;
...@@ -1199,8 +1153,10 @@ xfs_create_tmpfile( ...@@ -1199,8 +1153,10 @@ xfs_create_tmpfile(
if (error) if (error)
goto out_release_dquots; goto out_release_dquots;
error = xfs_dir_ialloc(mnt_userns, &tp, dp, mode, 0, 0, prid, error = xfs_dialloc(&tp, dp->i_ino, mode, &ino);
false, &ip); if (!error)
error = xfs_init_new_inode(mnt_userns, tp, dp, ino, mode,
0, 0, prid, false, &ip);
if (error) if (error)
goto out_trans_cancel; goto out_trans_cancel;
...@@ -1315,7 +1271,11 @@ xfs_link( ...@@ -1315,7 +1271,11 @@ xfs_link(
* Handle initial link state of O_TMPFILE inode * Handle initial link state of O_TMPFILE inode
*/ */
if (VFS_I(sip)->i_nlink == 0) { if (VFS_I(sip)->i_nlink == 0) {
error = xfs_iunlink_remove(tp, sip); struct xfs_perag *pag;
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, sip->i_ino));
error = xfs_iunlink_remove(tp, pag, sip);
xfs_perag_put(pag);
if (error) if (error)
goto error_return; goto error_return;
} }
...@@ -2008,7 +1968,7 @@ xfs_iunlink_destroy( ...@@ -2008,7 +1968,7 @@ xfs_iunlink_destroy(
STATIC int STATIC int
xfs_iunlink_update_bucket( xfs_iunlink_update_bucket(
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno, struct xfs_perag *pag,
struct xfs_buf *agibp, struct xfs_buf *agibp,
unsigned int bucket_index, unsigned int bucket_index,
xfs_agino_t new_agino) xfs_agino_t new_agino)
...@@ -2017,10 +1977,10 @@ xfs_iunlink_update_bucket( ...@@ -2017,10 +1977,10 @@ xfs_iunlink_update_bucket(
xfs_agino_t old_value; xfs_agino_t old_value;
int offset; int offset;
ASSERT(xfs_verify_agino_or_null(tp->t_mountp, agno, new_agino)); ASSERT(xfs_verify_agino_or_null(tp->t_mountp, pag->pag_agno, new_agino));
old_value = be32_to_cpu(agi->agi_unlinked[bucket_index]); old_value = be32_to_cpu(agi->agi_unlinked[bucket_index]);
trace_xfs_iunlink_update_bucket(tp->t_mountp, agno, bucket_index, trace_xfs_iunlink_update_bucket(tp->t_mountp, pag->pag_agno, bucket_index,
old_value, new_agino); old_value, new_agino);
/* /*
...@@ -2044,7 +2004,7 @@ xfs_iunlink_update_bucket( ...@@ -2044,7 +2004,7 @@ xfs_iunlink_update_bucket(
STATIC void STATIC void
xfs_iunlink_update_dinode( xfs_iunlink_update_dinode(
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_agino_t agino, xfs_agino_t agino,
struct xfs_buf *ibp, struct xfs_buf *ibp,
struct xfs_dinode *dip, struct xfs_dinode *dip,
...@@ -2054,9 +2014,9 @@ xfs_iunlink_update_dinode( ...@@ -2054,9 +2014,9 @@ xfs_iunlink_update_dinode(
struct xfs_mount *mp = tp->t_mountp; struct xfs_mount *mp = tp->t_mountp;
int offset; int offset;
ASSERT(xfs_verify_agino_or_null(mp, agno, next_agino)); ASSERT(xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino));
trace_xfs_iunlink_update_dinode(mp, agno, agino, trace_xfs_iunlink_update_dinode(mp, pag->pag_agno, agino,
be32_to_cpu(dip->di_next_unlinked), next_agino); be32_to_cpu(dip->di_next_unlinked), next_agino);
dip->di_next_unlinked = cpu_to_be32(next_agino); dip->di_next_unlinked = cpu_to_be32(next_agino);
...@@ -2074,7 +2034,7 @@ STATIC int ...@@ -2074,7 +2034,7 @@ STATIC int
xfs_iunlink_update_inode( xfs_iunlink_update_inode(
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_inode *ip, struct xfs_inode *ip,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_agino_t next_agino, xfs_agino_t next_agino,
xfs_agino_t *old_next_agino) xfs_agino_t *old_next_agino)
{ {
...@@ -2084,7 +2044,7 @@ xfs_iunlink_update_inode( ...@@ -2084,7 +2044,7 @@ xfs_iunlink_update_inode(
xfs_agino_t old_value; xfs_agino_t old_value;
int error; int error;
ASSERT(xfs_verify_agino_or_null(mp, agno, next_agino)); ASSERT(xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino));
error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &ibp); error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &ibp);
if (error) if (error)
...@@ -2093,7 +2053,7 @@ xfs_iunlink_update_inode( ...@@ -2093,7 +2053,7 @@ xfs_iunlink_update_inode(
/* Make sure the old pointer isn't garbage. */ /* Make sure the old pointer isn't garbage. */
old_value = be32_to_cpu(dip->di_next_unlinked); old_value = be32_to_cpu(dip->di_next_unlinked);
if (!xfs_verify_agino_or_null(mp, agno, old_value)) { if (!xfs_verify_agino_or_null(mp, pag->pag_agno, old_value)) {
xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip, xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
sizeof(*dip), __this_address); sizeof(*dip), __this_address);
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
...@@ -2116,7 +2076,7 @@ xfs_iunlink_update_inode( ...@@ -2116,7 +2076,7 @@ xfs_iunlink_update_inode(
} }
/* Ok, update the new pointer. */ /* Ok, update the new pointer. */
xfs_iunlink_update_dinode(tp, agno, XFS_INO_TO_AGINO(mp, ip->i_ino), xfs_iunlink_update_dinode(tp, pag, XFS_INO_TO_AGINO(mp, ip->i_ino),
ibp, dip, &ip->i_imap, next_agino); ibp, dip, &ip->i_imap, next_agino);
return 0; return 0;
out: out:
...@@ -2137,10 +2097,10 @@ xfs_iunlink( ...@@ -2137,10 +2097,10 @@ xfs_iunlink(
struct xfs_inode *ip) struct xfs_inode *ip)
{ {
struct xfs_mount *mp = tp->t_mountp; struct xfs_mount *mp = tp->t_mountp;
struct xfs_perag *pag;
struct xfs_agi *agi; struct xfs_agi *agi;
struct xfs_buf *agibp; struct xfs_buf *agibp;
xfs_agino_t next_agino; xfs_agino_t next_agino;
xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, ip->i_ino);
xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ip->i_ino); xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
short bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS; short bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS;
int error; int error;
...@@ -2149,10 +2109,12 @@ xfs_iunlink( ...@@ -2149,10 +2109,12 @@ xfs_iunlink(
ASSERT(VFS_I(ip)->i_mode != 0); ASSERT(VFS_I(ip)->i_mode != 0);
trace_xfs_iunlink(ip); trace_xfs_iunlink(ip);
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
/* Get the agi buffer first. It ensures lock ordering on the list. */ /* Get the agi buffer first. It ensures lock ordering on the list. */
error = xfs_read_agi(mp, tp, agno, &agibp); error = xfs_read_agi(mp, tp, pag->pag_agno, &agibp);
if (error) if (error)
return error; goto out;
agi = agibp->b_addr; agi = agibp->b_addr;
/* /*
...@@ -2162,9 +2124,10 @@ xfs_iunlink( ...@@ -2162,9 +2124,10 @@ xfs_iunlink(
*/ */
next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]); next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
if (next_agino == agino || if (next_agino == agino ||
!xfs_verify_agino_or_null(mp, agno, next_agino)) { !xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino)) {
xfs_buf_mark_corrupt(agibp); xfs_buf_mark_corrupt(agibp);
return -EFSCORRUPTED; error = -EFSCORRUPTED;
goto out;
} }
if (next_agino != NULLAGINO) { if (next_agino != NULLAGINO) {
...@@ -2174,23 +2137,26 @@ xfs_iunlink( ...@@ -2174,23 +2137,26 @@ xfs_iunlink(
* There is already another inode in the bucket, so point this * There is already another inode in the bucket, so point this
* inode to the current head of the list. * inode to the current head of the list.
*/ */
error = xfs_iunlink_update_inode(tp, ip, agno, next_agino, error = xfs_iunlink_update_inode(tp, ip, pag, next_agino,
&old_agino); &old_agino);
if (error) if (error)
return error; goto out;
ASSERT(old_agino == NULLAGINO); ASSERT(old_agino == NULLAGINO);
/* /*
* agino has been unlinked, add a backref from the next inode * agino has been unlinked, add a backref from the next inode
* back to agino. * back to agino.
*/ */
error = xfs_iunlink_add_backref(agibp->b_pag, agino, next_agino); error = xfs_iunlink_add_backref(pag, agino, next_agino);
if (error) if (error)
return error; goto out;
} }
/* Point the head of the list to point to this inode. */ /* Point the head of the list to point to this inode. */
return xfs_iunlink_update_bucket(tp, agno, agibp, bucket_index, agino); error = xfs_iunlink_update_bucket(tp, pag, agibp, bucket_index, agino);
out:
xfs_perag_put(pag);
return error;
} }
/* Return the imap, dinode pointer, and buffer for an inode. */ /* Return the imap, dinode pointer, and buffer for an inode. */
...@@ -2238,14 +2204,13 @@ xfs_iunlink_map_ino( ...@@ -2238,14 +2204,13 @@ xfs_iunlink_map_ino(
STATIC int STATIC int
xfs_iunlink_map_prev( xfs_iunlink_map_prev(
struct xfs_trans *tp, struct xfs_trans *tp,
xfs_agnumber_t agno, struct xfs_perag *pag,
xfs_agino_t head_agino, xfs_agino_t head_agino,
xfs_agino_t target_agino, xfs_agino_t target_agino,
xfs_agino_t *agino, xfs_agino_t *agino,
struct xfs_imap *imap, struct xfs_imap *imap,
struct xfs_dinode **dipp, struct xfs_dinode **dipp,
struct xfs_buf **bpp, struct xfs_buf **bpp)
struct xfs_perag *pag)
{ {
struct xfs_mount *mp = tp->t_mountp; struct xfs_mount *mp = tp->t_mountp;
xfs_agino_t next_agino; xfs_agino_t next_agino;
...@@ -2257,7 +2222,8 @@ xfs_iunlink_map_prev( ...@@ -2257,7 +2222,8 @@ xfs_iunlink_map_prev(
/* See if our backref cache can find it faster. */ /* See if our backref cache can find it faster. */
*agino = xfs_iunlink_lookup_backref(pag, target_agino); *agino = xfs_iunlink_lookup_backref(pag, target_agino);
if (*agino != NULLAGINO) { if (*agino != NULLAGINO) {
error = xfs_iunlink_map_ino(tp, agno, *agino, imap, dipp, bpp); error = xfs_iunlink_map_ino(tp, pag->pag_agno, *agino, imap,
dipp, bpp);
if (error) if (error)
return error; return error;
...@@ -2273,7 +2239,7 @@ xfs_iunlink_map_prev( ...@@ -2273,7 +2239,7 @@ xfs_iunlink_map_prev(
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
} }
trace_xfs_iunlink_map_prev_fallback(mp, agno); trace_xfs_iunlink_map_prev_fallback(mp, pag->pag_agno);
/* Otherwise, walk the entire bucket until we find it. */ /* Otherwise, walk the entire bucket until we find it. */
next_agino = head_agino; next_agino = head_agino;
...@@ -2284,8 +2250,8 @@ xfs_iunlink_map_prev( ...@@ -2284,8 +2250,8 @@ xfs_iunlink_map_prev(
xfs_trans_brelse(tp, *bpp); xfs_trans_brelse(tp, *bpp);
*agino = next_agino; *agino = next_agino;
error = xfs_iunlink_map_ino(tp, agno, next_agino, imap, dipp, error = xfs_iunlink_map_ino(tp, pag->pag_agno, next_agino, imap,
bpp); dipp, bpp);
if (error) if (error)
return error; return error;
...@@ -2294,7 +2260,7 @@ xfs_iunlink_map_prev( ...@@ -2294,7 +2260,7 @@ xfs_iunlink_map_prev(
* Make sure this pointer is valid and isn't an obvious * Make sure this pointer is valid and isn't an obvious
* infinite loop. * infinite loop.
*/ */
if (!xfs_verify_agino(mp, agno, unlinked_agino) || if (!xfs_verify_agino(mp, pag->pag_agno, unlinked_agino) ||
next_agino == unlinked_agino) { next_agino == unlinked_agino) {
XFS_CORRUPTION_ERROR(__func__, XFS_CORRUPTION_ERROR(__func__,
XFS_ERRLEVEL_LOW, mp, XFS_ERRLEVEL_LOW, mp,
...@@ -2314,6 +2280,7 @@ xfs_iunlink_map_prev( ...@@ -2314,6 +2280,7 @@ xfs_iunlink_map_prev(
STATIC int STATIC int
xfs_iunlink_remove( xfs_iunlink_remove(
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_perag *pag,
struct xfs_inode *ip) struct xfs_inode *ip)
{ {
struct xfs_mount *mp = tp->t_mountp; struct xfs_mount *mp = tp->t_mountp;
...@@ -2321,7 +2288,6 @@ xfs_iunlink_remove( ...@@ -2321,7 +2288,6 @@ xfs_iunlink_remove(
struct xfs_buf *agibp; struct xfs_buf *agibp;
struct xfs_buf *last_ibp; struct xfs_buf *last_ibp;
struct xfs_dinode *last_dip = NULL; struct xfs_dinode *last_dip = NULL;
xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, ip->i_ino);
xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ip->i_ino); xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
xfs_agino_t next_agino; xfs_agino_t next_agino;
xfs_agino_t head_agino; xfs_agino_t head_agino;
...@@ -2331,7 +2297,7 @@ xfs_iunlink_remove( ...@@ -2331,7 +2297,7 @@ xfs_iunlink_remove(
trace_xfs_iunlink_remove(ip); trace_xfs_iunlink_remove(ip);
/* Get the agi buffer first. It ensures lock ordering on the list. */ /* Get the agi buffer first. It ensures lock ordering on the list. */
error = xfs_read_agi(mp, tp, agno, &agibp); error = xfs_read_agi(mp, tp, pag->pag_agno, &agibp);
if (error) if (error)
return error; return error;
agi = agibp->b_addr; agi = agibp->b_addr;
...@@ -2341,7 +2307,7 @@ xfs_iunlink_remove( ...@@ -2341,7 +2307,7 @@ xfs_iunlink_remove(
* go on. Make sure the head pointer isn't garbage. * go on. Make sure the head pointer isn't garbage.
*/ */
head_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]); head_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
if (!xfs_verify_agino(mp, agno, head_agino)) { if (!xfs_verify_agino(mp, pag->pag_agno, head_agino)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
agi, sizeof(*agi)); agi, sizeof(*agi));
return -EFSCORRUPTED; return -EFSCORRUPTED;
...@@ -2352,7 +2318,7 @@ xfs_iunlink_remove( ...@@ -2352,7 +2318,7 @@ xfs_iunlink_remove(
* the old pointer value so that we can update whatever was previous * the old pointer value so that we can update whatever was previous
* to us in the list to point to whatever was next in the list. * to us in the list to point to whatever was next in the list.
*/ */
error = xfs_iunlink_update_inode(tp, ip, agno, NULLAGINO, &next_agino); error = xfs_iunlink_update_inode(tp, ip, pag, NULLAGINO, &next_agino);
if (error) if (error)
return error; return error;
...@@ -2364,8 +2330,7 @@ xfs_iunlink_remove( ...@@ -2364,8 +2330,7 @@ xfs_iunlink_remove(
* this inode's backref to point from the next inode. * this inode's backref to point from the next inode.
*/ */
if (next_agino != NULLAGINO) { if (next_agino != NULLAGINO) {
error = xfs_iunlink_change_backref(agibp->b_pag, next_agino, error = xfs_iunlink_change_backref(pag, next_agino, NULLAGINO);
NULLAGINO);
if (error) if (error)
return error; return error;
} }
...@@ -2375,14 +2340,13 @@ xfs_iunlink_remove( ...@@ -2375,14 +2340,13 @@ xfs_iunlink_remove(
xfs_agino_t prev_agino; xfs_agino_t prev_agino;
/* We need to search the list for the inode being freed. */ /* We need to search the list for the inode being freed. */
error = xfs_iunlink_map_prev(tp, agno, head_agino, agino, error = xfs_iunlink_map_prev(tp, pag, head_agino, agino,
&prev_agino, &imap, &last_dip, &last_ibp, &prev_agino, &imap, &last_dip, &last_ibp);
agibp->b_pag);
if (error) if (error)
return error; return error;
/* Point the previous inode on the list to the next inode. */ /* Point the previous inode on the list to the next inode. */
xfs_iunlink_update_dinode(tp, agno, prev_agino, last_ibp, xfs_iunlink_update_dinode(tp, pag, prev_agino, last_ibp,
last_dip, &imap, next_agino); last_dip, &imap, next_agino);
/* /*
...@@ -2398,7 +2362,7 @@ xfs_iunlink_remove( ...@@ -2398,7 +2362,7 @@ xfs_iunlink_remove(
} }
/* Point the head of the list to the next unlinked inode. */ /* Point the head of the list to the next unlinked inode. */
return xfs_iunlink_update_bucket(tp, agno, agibp, bucket_index, return xfs_iunlink_update_bucket(tp, pag, agibp, bucket_index,
next_agino); next_agino);
} }
...@@ -2409,12 +2373,11 @@ xfs_iunlink_remove( ...@@ -2409,12 +2373,11 @@ xfs_iunlink_remove(
*/ */
static void static void
xfs_ifree_mark_inode_stale( xfs_ifree_mark_inode_stale(
struct xfs_buf *bp, struct xfs_perag *pag,
struct xfs_inode *free_ip, struct xfs_inode *free_ip,
xfs_ino_t inum) xfs_ino_t inum)
{ {
struct xfs_mount *mp = bp->b_mount; struct xfs_mount *mp = pag->pag_mount;
struct xfs_perag *pag = bp->b_pag;
struct xfs_inode_log_item *iip; struct xfs_inode_log_item *iip;
struct xfs_inode *ip; struct xfs_inode *ip;
...@@ -2504,10 +2467,11 @@ xfs_ifree_mark_inode_stale( ...@@ -2504,10 +2467,11 @@ xfs_ifree_mark_inode_stale(
* inodes that are in memory - they all must be marked stale and attached to * inodes that are in memory - they all must be marked stale and attached to
* the cluster buffer. * the cluster buffer.
*/ */
STATIC int static int
xfs_ifree_cluster( xfs_ifree_cluster(
struct xfs_inode *free_ip,
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_perag *pag,
struct xfs_inode *free_ip,
struct xfs_icluster *xic) struct xfs_icluster *xic)
{ {
struct xfs_mount *mp = free_ip->i_mount; struct xfs_mount *mp = free_ip->i_mount;
...@@ -2569,7 +2533,7 @@ xfs_ifree_cluster( ...@@ -2569,7 +2533,7 @@ xfs_ifree_cluster(
* already marked XFS_ISTALE. * already marked XFS_ISTALE.
*/ */
for (i = 0; i < igeo->inodes_per_cluster; i++) for (i = 0; i < igeo->inodes_per_cluster; i++)
xfs_ifree_mark_inode_stale(bp, free_ip, inum + i); xfs_ifree_mark_inode_stale(pag, free_ip, inum + i);
xfs_trans_stale_inode_buf(tp, bp); xfs_trans_stale_inode_buf(tp, bp);
xfs_trans_binval(tp, bp); xfs_trans_binval(tp, bp);
...@@ -2592,9 +2556,11 @@ xfs_ifree( ...@@ -2592,9 +2556,11 @@ xfs_ifree(
struct xfs_trans *tp, struct xfs_trans *tp,
struct xfs_inode *ip) struct xfs_inode *ip)
{ {
int error; struct xfs_mount *mp = ip->i_mount;
struct xfs_perag *pag;
struct xfs_icluster xic = { 0 }; struct xfs_icluster xic = { 0 };
struct xfs_inode_log_item *iip = ip->i_itemp; struct xfs_inode_log_item *iip = ip->i_itemp;
int error;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT(VFS_I(ip)->i_nlink == 0); ASSERT(VFS_I(ip)->i_nlink == 0);
...@@ -2602,16 +2568,18 @@ xfs_ifree( ...@@ -2602,16 +2568,18 @@ xfs_ifree(
ASSERT(ip->i_disk_size == 0 || !S_ISREG(VFS_I(ip)->i_mode)); ASSERT(ip->i_disk_size == 0 || !S_ISREG(VFS_I(ip)->i_mode));
ASSERT(ip->i_nblocks == 0); ASSERT(ip->i_nblocks == 0);
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
/* /*
* Pull the on-disk inode from the AGI unlinked list. * Pull the on-disk inode from the AGI unlinked list.
*/ */
error = xfs_iunlink_remove(tp, ip); error = xfs_iunlink_remove(tp, pag, ip);
if (error) if (error)
return error; goto out;
error = xfs_difree(tp, ip->i_ino, &xic); error = xfs_difree(tp, pag, ip->i_ino, &xic);
if (error) if (error)
return error; goto out;
/* /*
* Free any local-format data sitting around before we reset the * Free any local-format data sitting around before we reset the
...@@ -2626,7 +2594,7 @@ xfs_ifree( ...@@ -2626,7 +2594,7 @@ xfs_ifree(
VFS_I(ip)->i_mode = 0; /* mark incore inode as free */ VFS_I(ip)->i_mode = 0; /* mark incore inode as free */
ip->i_diflags = 0; ip->i_diflags = 0;
ip->i_diflags2 = ip->i_mount->m_ino_geo.new_diflags2; ip->i_diflags2 = mp->m_ino_geo.new_diflags2;
ip->i_forkoff = 0; /* mark the attr fork not in use */ ip->i_forkoff = 0; /* mark the attr fork not in use */
ip->i_df.if_format = XFS_DINODE_FMT_EXTENTS; ip->i_df.if_format = XFS_DINODE_FMT_EXTENTS;
if (xfs_iflags_test(ip, XFS_IPRESERVE_DM_FIELDS)) if (xfs_iflags_test(ip, XFS_IPRESERVE_DM_FIELDS))
...@@ -2645,8 +2613,9 @@ xfs_ifree( ...@@ -2645,8 +2613,9 @@ xfs_ifree(
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
if (xic.deleted) if (xic.deleted)
error = xfs_ifree_cluster(ip, tp, &xic); error = xfs_ifree_cluster(tp, pag, ip, &xic);
out:
xfs_perag_put(pag);
return error; return error;
} }
...@@ -3250,8 +3219,13 @@ xfs_rename( ...@@ -3250,8 +3219,13 @@ xfs_rename(
* in future. * in future.
*/ */
if (wip) { if (wip) {
struct xfs_perag *pag;
ASSERT(VFS_I(wip)->i_nlink == 0); ASSERT(VFS_I(wip)->i_nlink == 0);
error = xfs_iunlink_remove(tp, wip);
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, wip->i_ino));
error = xfs_iunlink_remove(tp, pag, wip);
xfs_perag_put(pag);
if (error) if (error)
goto out_trans_cancel; goto out_trans_cancel;
......
...@@ -431,11 +431,10 @@ void xfs_lock_two_inodes(struct xfs_inode *ip0, uint ip0_mode, ...@@ -431,11 +431,10 @@ void xfs_lock_two_inodes(struct xfs_inode *ip0, uint ip0_mode,
xfs_extlen_t xfs_get_extsz_hint(struct xfs_inode *ip); xfs_extlen_t xfs_get_extsz_hint(struct xfs_inode *ip);
xfs_extlen_t xfs_get_cowextsz_hint(struct xfs_inode *ip); xfs_extlen_t xfs_get_cowextsz_hint(struct xfs_inode *ip);
int xfs_dir_ialloc(struct user_namespace *mnt_userns, int xfs_init_new_inode(struct user_namespace *mnt_userns, struct xfs_trans *tp,
struct xfs_trans **tpp, struct xfs_inode *dp, struct xfs_inode *pip, xfs_ino_t ino, umode_t mode,
umode_t mode, xfs_nlink_t nlink, dev_t dev, xfs_nlink_t nlink, dev_t rdev, prid_t prid, bool init_xattrs,
prid_t prid, bool need_xattr, struct xfs_inode **ipp);
struct xfs_inode **ipp);
static inline int static inline int
xfs_itruncate_extents( xfs_itruncate_extents(
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "xfs_health.h" #include "xfs_health.h"
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_pwork.h" #include "xfs_pwork.h"
#include "xfs_ag.h"
/* /*
* Walking Inodes in the Filesystem * Walking Inodes in the Filesystem
...@@ -51,6 +52,7 @@ struct xfs_iwalk_ag { ...@@ -51,6 +52,7 @@ struct xfs_iwalk_ag {
struct xfs_mount *mp; struct xfs_mount *mp;
struct xfs_trans *tp; struct xfs_trans *tp;
struct xfs_perag *pag;
/* Where do we start the traversal? */ /* Where do we start the traversal? */
xfs_ino_t startino; xfs_ino_t startino;
...@@ -90,7 +92,7 @@ struct xfs_iwalk_ag { ...@@ -90,7 +92,7 @@ struct xfs_iwalk_ag {
STATIC void STATIC void
xfs_iwalk_ichunk_ra( xfs_iwalk_ichunk_ra(
struct xfs_mount *mp, struct xfs_mount *mp,
xfs_agnumber_t agno, struct xfs_perag *pag,
struct xfs_inobt_rec_incore *irec) struct xfs_inobt_rec_incore *irec)
{ {
struct xfs_ino_geometry *igeo = M_IGEO(mp); struct xfs_ino_geometry *igeo = M_IGEO(mp);
...@@ -106,7 +108,7 @@ xfs_iwalk_ichunk_ra( ...@@ -106,7 +108,7 @@ xfs_iwalk_ichunk_ra(
imask = xfs_inobt_maskn(i, igeo->inodes_per_cluster); imask = xfs_inobt_maskn(i, igeo->inodes_per_cluster);
if (imask & ~irec->ir_free) { if (imask & ~irec->ir_free) {
xfs_btree_reada_bufs(mp, agno, agbno, xfs_btree_reada_bufs(mp, pag->pag_agno, agbno,
igeo->blocks_per_cluster, igeo->blocks_per_cluster,
&xfs_inode_buf_ops); &xfs_inode_buf_ops);
} }
...@@ -174,26 +176,25 @@ xfs_iwalk_free( ...@@ -174,26 +176,25 @@ xfs_iwalk_free(
/* For each inuse inode in each cached inobt record, call our function. */ /* For each inuse inode in each cached inobt record, call our function. */
STATIC int STATIC int
xfs_iwalk_ag_recs( xfs_iwalk_ag_recs(
struct xfs_iwalk_ag *iwag) struct xfs_iwalk_ag *iwag)
{ {
struct xfs_mount *mp = iwag->mp; struct xfs_mount *mp = iwag->mp;
struct xfs_trans *tp = iwag->tp; struct xfs_trans *tp = iwag->tp;
xfs_ino_t ino; struct xfs_perag *pag = iwag->pag;
unsigned int i, j; xfs_ino_t ino;
xfs_agnumber_t agno; unsigned int i, j;
int error; int error;
agno = XFS_INO_TO_AGNO(mp, iwag->startino);
for (i = 0; i < iwag->nr_recs; i++) { for (i = 0; i < iwag->nr_recs; i++) {
struct xfs_inobt_rec_incore *irec = &iwag->recs[i]; struct xfs_inobt_rec_incore *irec = &iwag->recs[i];
trace_xfs_iwalk_ag_rec(mp, agno, irec); trace_xfs_iwalk_ag_rec(mp, pag->pag_agno, irec);
if (xfs_pwork_want_abort(&iwag->pwork)) if (xfs_pwork_want_abort(&iwag->pwork))
return 0; return 0;
if (iwag->inobt_walk_fn) { if (iwag->inobt_walk_fn) {
error = iwag->inobt_walk_fn(mp, tp, agno, irec, error = iwag->inobt_walk_fn(mp, tp, pag->pag_agno, irec,
iwag->data); iwag->data);
if (error) if (error)
return error; return error;
...@@ -211,7 +212,8 @@ xfs_iwalk_ag_recs( ...@@ -211,7 +212,8 @@ xfs_iwalk_ag_recs(
continue; continue;
/* Otherwise call our function. */ /* Otherwise call our function. */
ino = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino + j); ino = XFS_AGINO_TO_INO(mp, pag->pag_agno,
irec->ir_startino + j);
error = iwag->iwalk_fn(mp, tp, ino, iwag->data); error = iwag->iwalk_fn(mp, tp, ino, iwag->data);
if (error) if (error)
return error; return error;
...@@ -257,7 +259,6 @@ xfs_iwalk_del_inobt( ...@@ -257,7 +259,6 @@ xfs_iwalk_del_inobt(
STATIC int STATIC int
xfs_iwalk_ag_start( xfs_iwalk_ag_start(
struct xfs_iwalk_ag *iwag, struct xfs_iwalk_ag *iwag,
xfs_agnumber_t agno,
xfs_agino_t agino, xfs_agino_t agino,
struct xfs_btree_cur **curpp, struct xfs_btree_cur **curpp,
struct xfs_buf **agi_bpp, struct xfs_buf **agi_bpp,
...@@ -265,12 +266,13 @@ xfs_iwalk_ag_start( ...@@ -265,12 +266,13 @@ xfs_iwalk_ag_start(
{ {
struct xfs_mount *mp = iwag->mp; struct xfs_mount *mp = iwag->mp;
struct xfs_trans *tp = iwag->tp; struct xfs_trans *tp = iwag->tp;
struct xfs_perag *pag = iwag->pag;
struct xfs_inobt_rec_incore *irec; struct xfs_inobt_rec_incore *irec;
int error; int error;
/* Set up a fresh cursor and empty the inobt cache. */ /* Set up a fresh cursor and empty the inobt cache. */
iwag->nr_recs = 0; iwag->nr_recs = 0;
error = xfs_inobt_cur(mp, tp, agno, XFS_BTNUM_INO, curpp, agi_bpp); error = xfs_inobt_cur(mp, tp, pag, XFS_BTNUM_INO, curpp, agi_bpp);
if (error) if (error)
return error; return error;
...@@ -304,7 +306,7 @@ xfs_iwalk_ag_start( ...@@ -304,7 +306,7 @@ xfs_iwalk_ag_start(
if (XFS_IS_CORRUPT(mp, *has_more != 1)) if (XFS_IS_CORRUPT(mp, *has_more != 1))
return -EFSCORRUPTED; return -EFSCORRUPTED;
iwag->lastino = XFS_AGINO_TO_INO(mp, agno, iwag->lastino = XFS_AGINO_TO_INO(mp, pag->pag_agno,
irec->ir_startino + XFS_INODES_PER_CHUNK - 1); irec->ir_startino + XFS_INODES_PER_CHUNK - 1);
/* /*
...@@ -345,7 +347,6 @@ xfs_iwalk_ag_start( ...@@ -345,7 +347,6 @@ xfs_iwalk_ag_start(
STATIC int STATIC int
xfs_iwalk_run_callbacks( xfs_iwalk_run_callbacks(
struct xfs_iwalk_ag *iwag, struct xfs_iwalk_ag *iwag,
xfs_agnumber_t agno,
struct xfs_btree_cur **curpp, struct xfs_btree_cur **curpp,
struct xfs_buf **agi_bpp, struct xfs_buf **agi_bpp,
int *has_more) int *has_more)
...@@ -376,7 +377,7 @@ xfs_iwalk_run_callbacks( ...@@ -376,7 +377,7 @@ xfs_iwalk_run_callbacks(
return 0; return 0;
/* ...and recreate the cursor just past where we left off. */ /* ...and recreate the cursor just past where we left off. */
error = xfs_inobt_cur(mp, tp, agno, XFS_BTNUM_INO, curpp, agi_bpp); error = xfs_inobt_cur(mp, tp, iwag->pag, XFS_BTNUM_INO, curpp, agi_bpp);
if (error) if (error)
return error; return error;
...@@ -390,17 +391,17 @@ xfs_iwalk_ag( ...@@ -390,17 +391,17 @@ xfs_iwalk_ag(
{ {
struct xfs_mount *mp = iwag->mp; struct xfs_mount *mp = iwag->mp;
struct xfs_trans *tp = iwag->tp; struct xfs_trans *tp = iwag->tp;
struct xfs_perag *pag = iwag->pag;
struct xfs_buf *agi_bp = NULL; struct xfs_buf *agi_bp = NULL;
struct xfs_btree_cur *cur = NULL; struct xfs_btree_cur *cur = NULL;
xfs_agnumber_t agno;
xfs_agino_t agino; xfs_agino_t agino;
int has_more; int has_more;
int error = 0; int error = 0;
/* Set up our cursor at the right place in the inode btree. */ /* Set up our cursor at the right place in the inode btree. */
agno = XFS_INO_TO_AGNO(mp, iwag->startino); ASSERT(pag->pag_agno == XFS_INO_TO_AGNO(mp, iwag->startino));
agino = XFS_INO_TO_AGINO(mp, iwag->startino); agino = XFS_INO_TO_AGINO(mp, iwag->startino);
error = xfs_iwalk_ag_start(iwag, agno, agino, &cur, &agi_bp, &has_more); error = xfs_iwalk_ag_start(iwag, agino, &cur, &agi_bp, &has_more);
while (!error && has_more) { while (!error && has_more) {
struct xfs_inobt_rec_incore *irec; struct xfs_inobt_rec_incore *irec;
...@@ -417,7 +418,7 @@ xfs_iwalk_ag( ...@@ -417,7 +418,7 @@ xfs_iwalk_ag(
break; break;
/* Make sure that we always move forward. */ /* Make sure that we always move forward. */
rec_fsino = XFS_AGINO_TO_INO(mp, agno, irec->ir_startino); rec_fsino = XFS_AGINO_TO_INO(mp, pag->pag_agno, irec->ir_startino);
if (iwag->lastino != NULLFSINO && if (iwag->lastino != NULLFSINO &&
XFS_IS_CORRUPT(mp, iwag->lastino >= rec_fsino)) { XFS_IS_CORRUPT(mp, iwag->lastino >= rec_fsino)) {
error = -EFSCORRUPTED; error = -EFSCORRUPTED;
...@@ -438,7 +439,7 @@ xfs_iwalk_ag( ...@@ -438,7 +439,7 @@ xfs_iwalk_ag(
* walking the inodes. * walking the inodes.
*/ */
if (iwag->iwalk_fn) if (iwag->iwalk_fn)
xfs_iwalk_ichunk_ra(mp, agno, irec); xfs_iwalk_ichunk_ra(mp, pag, irec);
/* /*
* If there's space in the buffer for more records, increment * If there's space in the buffer for more records, increment
...@@ -458,15 +459,14 @@ xfs_iwalk_ag( ...@@ -458,15 +459,14 @@ xfs_iwalk_ag(
* we would be if we had been able to increment like above. * we would be if we had been able to increment like above.
*/ */
ASSERT(has_more); ASSERT(has_more);
error = xfs_iwalk_run_callbacks(iwag, agno, &cur, &agi_bp, error = xfs_iwalk_run_callbacks(iwag, &cur, &agi_bp, &has_more);
&has_more);
} }
if (iwag->nr_recs == 0 || error) if (iwag->nr_recs == 0 || error)
goto out; goto out;
/* Walk the unprocessed records in the cache. */ /* Walk the unprocessed records in the cache. */
error = xfs_iwalk_run_callbacks(iwag, agno, &cur, &agi_bp, &has_more); error = xfs_iwalk_run_callbacks(iwag, &cur, &agi_bp, &has_more);
out: out:
xfs_iwalk_del_inobt(tp, &cur, &agi_bp, error); xfs_iwalk_del_inobt(tp, &cur, &agi_bp, error);
...@@ -555,6 +555,7 @@ xfs_iwalk( ...@@ -555,6 +555,7 @@ xfs_iwalk(
.pwork = XFS_PWORK_SINGLE_THREADED, .pwork = XFS_PWORK_SINGLE_THREADED,
.lastino = NULLFSINO, .lastino = NULLFSINO,
}; };
struct xfs_perag *pag;
xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, startino); xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, startino);
int error; int error;
...@@ -565,15 +566,19 @@ xfs_iwalk( ...@@ -565,15 +566,19 @@ xfs_iwalk(
if (error) if (error)
return error; return error;
for (; agno < mp->m_sb.sb_agcount; agno++) { for_each_perag_from(mp, agno, pag) {
iwag.pag = pag;
error = xfs_iwalk_ag(&iwag); error = xfs_iwalk_ag(&iwag);
if (error) if (error)
break; break;
iwag.startino = XFS_AGINO_TO_INO(mp, agno + 1, 0); iwag.startino = XFS_AGINO_TO_INO(mp, agno + 1, 0);
if (flags & XFS_INOBT_WALK_SAME_AG) if (flags & XFS_INOBT_WALK_SAME_AG)
break; break;
iwag.pag = NULL;
} }
if (iwag.pag)
xfs_perag_put(pag);
xfs_iwalk_free(&iwag); xfs_iwalk_free(&iwag);
return error; return error;
} }
...@@ -598,6 +603,7 @@ xfs_iwalk_ag_work( ...@@ -598,6 +603,7 @@ xfs_iwalk_ag_work(
error = xfs_iwalk_ag(iwag); error = xfs_iwalk_ag(iwag);
xfs_iwalk_free(iwag); xfs_iwalk_free(iwag);
out: out:
xfs_perag_put(iwag->pag);
kmem_free(iwag); kmem_free(iwag);
return error; return error;
} }
...@@ -617,6 +623,7 @@ xfs_iwalk_threaded( ...@@ -617,6 +623,7 @@ xfs_iwalk_threaded(
void *data) void *data)
{ {
struct xfs_pwork_ctl pctl; struct xfs_pwork_ctl pctl;
struct xfs_perag *pag;
xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, startino); xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, startino);
int error; int error;
...@@ -627,7 +634,7 @@ xfs_iwalk_threaded( ...@@ -627,7 +634,7 @@ xfs_iwalk_threaded(
if (error) if (error)
return error; return error;
for (; agno < mp->m_sb.sb_agcount; agno++) { for_each_perag_from(mp, agno, pag) {
struct xfs_iwalk_ag *iwag; struct xfs_iwalk_ag *iwag;
if (xfs_pwork_ctl_want_abort(&pctl)) if (xfs_pwork_ctl_want_abort(&pctl))
...@@ -635,17 +642,25 @@ xfs_iwalk_threaded( ...@@ -635,17 +642,25 @@ xfs_iwalk_threaded(
iwag = kmem_zalloc(sizeof(struct xfs_iwalk_ag), 0); iwag = kmem_zalloc(sizeof(struct xfs_iwalk_ag), 0);
iwag->mp = mp; iwag->mp = mp;
/*
* perag is being handed off to async work, so take another
* reference for the async work to release.
*/
atomic_inc(&pag->pag_ref);
iwag->pag = pag;
iwag->iwalk_fn = iwalk_fn; iwag->iwalk_fn = iwalk_fn;
iwag->data = data; iwag->data = data;
iwag->startino = startino; iwag->startino = startino;
iwag->sz_recs = xfs_iwalk_prefetch(inode_records); iwag->sz_recs = xfs_iwalk_prefetch(inode_records);
iwag->lastino = NULLFSINO; iwag->lastino = NULLFSINO;
xfs_pwork_queue(&pctl, &iwag->pwork); xfs_pwork_queue(&pctl, &iwag->pwork);
startino = XFS_AGINO_TO_INO(mp, agno + 1, 0); startino = XFS_AGINO_TO_INO(mp, pag->pag_agno + 1, 0);
if (flags & XFS_INOBT_WALK_SAME_AG) if (flags & XFS_INOBT_WALK_SAME_AG)
break; break;
} }
if (pag)
xfs_perag_put(pag);
if (polled) if (polled)
xfs_pwork_poll(&pctl); xfs_pwork_poll(&pctl);
return xfs_pwork_destroy(&pctl); return xfs_pwork_destroy(&pctl);
...@@ -715,6 +730,7 @@ xfs_inobt_walk( ...@@ -715,6 +730,7 @@ xfs_inobt_walk(
.pwork = XFS_PWORK_SINGLE_THREADED, .pwork = XFS_PWORK_SINGLE_THREADED,
.lastino = NULLFSINO, .lastino = NULLFSINO,
}; };
struct xfs_perag *pag;
xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, startino); xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, startino);
int error; int error;
...@@ -725,15 +741,19 @@ xfs_inobt_walk( ...@@ -725,15 +741,19 @@ xfs_inobt_walk(
if (error) if (error)
return error; return error;
for (; agno < mp->m_sb.sb_agcount; agno++) { for_each_perag_from(mp, agno, pag) {
iwag.pag = pag;
error = xfs_iwalk_ag(&iwag); error = xfs_iwalk_ag(&iwag);
if (error) if (error)
break; break;
iwag.startino = XFS_AGINO_TO_INO(mp, agno + 1, 0); iwag.startino = XFS_AGINO_TO_INO(mp, pag->pag_agno + 1, 0);
if (flags & XFS_INOBT_WALK_SAME_AG) if (flags & XFS_INOBT_WALK_SAME_AG)
break; break;
iwag.pag = NULL;
} }
if (iwag.pag)
xfs_perag_put(pag);
xfs_iwalk_free(&iwag); xfs_iwalk_free(&iwag);
return error; return error;
} }
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "xfs_icache.h" #include "xfs_icache.h"
#include "xfs_error.h" #include "xfs_error.h"
#include "xfs_buf_item.h" #include "xfs_buf_item.h"
#include "xfs_ag.h"
#define BLK_AVG(blk1, blk2) ((blk1+blk2) >> 1) #define BLK_AVG(blk1, blk2) ((blk1+blk2) >> 1)
...@@ -2741,21 +2742,17 @@ STATIC void ...@@ -2741,21 +2742,17 @@ STATIC void
xlog_recover_process_iunlinks( xlog_recover_process_iunlinks(
struct xlog *log) struct xlog *log)
{ {
xfs_mount_t *mp; struct xfs_mount *mp = log->l_mp;
xfs_agnumber_t agno; struct xfs_perag *pag;
xfs_agi_t *agi; xfs_agnumber_t agno;
struct xfs_buf *agibp; struct xfs_agi *agi;
xfs_agino_t agino; struct xfs_buf *agibp;
int bucket; xfs_agino_t agino;
int error; int bucket;
int error;
mp = log->l_mp;
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { for_each_perag(mp, agno, pag) {
/* error = xfs_read_agi(mp, NULL, pag->pag_agno, &agibp);
* Find the agi for this ag.
*/
error = xfs_read_agi(mp, NULL, agno, &agibp);
if (error) { if (error) {
/* /*
* AGI is b0rked. Don't process it. * AGI is b0rked. Don't process it.
...@@ -2781,7 +2778,7 @@ xlog_recover_process_iunlinks( ...@@ -2781,7 +2778,7 @@ xlog_recover_process_iunlinks(
agino = be32_to_cpu(agi->agi_unlinked[bucket]); agino = be32_to_cpu(agi->agi_unlinked[bucket]);
while (agino != NULLAGINO) { while (agino != NULLAGINO) {
agino = xlog_recover_process_one_iunlink(mp, agino = xlog_recover_process_one_iunlink(mp,
agno, agino, bucket); pag->pag_agno, agino, bucket);
cond_resched(); cond_resched();
} }
} }
...@@ -3493,27 +3490,28 @@ xlog_recover_cancel( ...@@ -3493,27 +3490,28 @@ xlog_recover_cancel(
*/ */
STATIC void STATIC void
xlog_recover_check_summary( xlog_recover_check_summary(
struct xlog *log) struct xlog *log)
{ {
xfs_mount_t *mp; struct xfs_mount *mp = log->l_mp;
struct xfs_buf *agfbp; struct xfs_perag *pag;
struct xfs_buf *agibp; struct xfs_buf *agfbp;
xfs_agnumber_t agno; struct xfs_buf *agibp;
uint64_t freeblks; xfs_agnumber_t agno;
uint64_t itotal; uint64_t freeblks;
uint64_t ifree; uint64_t itotal;
int error; uint64_t ifree;
int error;
mp = log->l_mp; mp = log->l_mp;
freeblks = 0LL; freeblks = 0LL;
itotal = 0LL; itotal = 0LL;
ifree = 0LL; ifree = 0LL;
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { for_each_perag(mp, agno, pag) {
error = xfs_read_agf(mp, NULL, agno, 0, &agfbp); error = xfs_read_agf(mp, NULL, pag->pag_agno, 0, &agfbp);
if (error) { if (error) {
xfs_alert(mp, "%s agf read failed agno %d error %d", xfs_alert(mp, "%s agf read failed agno %d error %d",
__func__, agno, error); __func__, pag->pag_agno, error);
} else { } else {
struct xfs_agf *agfp = agfbp->b_addr; struct xfs_agf *agfp = agfbp->b_addr;
...@@ -3522,10 +3520,10 @@ xlog_recover_check_summary( ...@@ -3522,10 +3520,10 @@ xlog_recover_check_summary(
xfs_buf_relse(agfbp); xfs_buf_relse(agfbp);
} }
error = xfs_read_agi(mp, NULL, agno, &agibp); error = xfs_read_agi(mp, NULL, pag->pag_agno, &agibp);
if (error) { if (error) {
xfs_alert(mp, "%s agi read failed agno %d error %d", xfs_alert(mp, "%s agi read failed agno %d error %d",
__func__, agno, error); __func__, pag->pag_agno, error);
} else { } else {
struct xfs_agi *agi = agibp->b_addr; struct xfs_agi *agi = agibp->b_addr;
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "xfs_extent_busy.h" #include "xfs_extent_busy.h"
#include "xfs_health.h" #include "xfs_health.h"
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_ag.h"
static DEFINE_MUTEX(xfs_uuid_table_mutex); static DEFINE_MUTEX(xfs_uuid_table_mutex);
static int xfs_uuid_table_size; static int xfs_uuid_table_size;
...@@ -119,41 +120,6 @@ xfs_uuid_unmount( ...@@ -119,41 +120,6 @@ xfs_uuid_unmount(
mutex_unlock(&xfs_uuid_table_mutex); mutex_unlock(&xfs_uuid_table_mutex);
} }
STATIC void
__xfs_free_perag(
struct rcu_head *head)
{
struct xfs_perag *pag = container_of(head, struct xfs_perag, rcu_head);
ASSERT(!delayed_work_pending(&pag->pag_blockgc_work));
ASSERT(atomic_read(&pag->pag_ref) == 0);
kmem_free(pag);
}
/*
* Free up the per-ag resources associated with the mount structure.
*/
STATIC void
xfs_free_perag(
xfs_mount_t *mp)
{
xfs_agnumber_t agno;
struct xfs_perag *pag;
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
spin_lock(&mp->m_perag_lock);
pag = radix_tree_delete(&mp->m_perag_tree, agno);
spin_unlock(&mp->m_perag_lock);
ASSERT(pag);
ASSERT(atomic_read(&pag->pag_ref) == 0);
cancel_delayed_work_sync(&pag->pag_blockgc_work);
xfs_iunlink_destroy(pag);
xfs_buf_hash_destroy(pag);
call_rcu(&pag->rcu_head, __xfs_free_perag);
}
}
/* /*
* Check size of device based on the (data/realtime) block count. * Check size of device based on the (data/realtime) block count.
* Note: this check is used by the growfs code as well as mount. * Note: this check is used by the growfs code as well as mount.
...@@ -172,96 +138,6 @@ xfs_sb_validate_fsb_count( ...@@ -172,96 +138,6 @@ xfs_sb_validate_fsb_count(
return 0; return 0;
} }
int
xfs_initialize_perag(
xfs_mount_t *mp,
xfs_agnumber_t agcount,
xfs_agnumber_t *maxagi)
{
xfs_agnumber_t index;
xfs_agnumber_t first_initialised = NULLAGNUMBER;
xfs_perag_t *pag;
int error = -ENOMEM;
/*
* Walk the current per-ag tree so we don't try to initialise AGs
* that already exist (growfs case). Allocate and insert all the
* AGs we don't find ready for initialisation.
*/
for (index = 0; index < agcount; index++) {
pag = xfs_perag_get(mp, index);
if (pag) {
xfs_perag_put(pag);
continue;
}
pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL);
if (!pag) {
error = -ENOMEM;
goto out_unwind_new_pags;
}
pag->pag_agno = index;
pag->pag_mount = mp;
spin_lock_init(&pag->pag_ici_lock);
INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
error = xfs_buf_hash_init(pag);
if (error)
goto out_free_pag;
init_waitqueue_head(&pag->pagb_wait);
spin_lock_init(&pag->pagb_lock);
pag->pagb_count = 0;
pag->pagb_tree = RB_ROOT;
error = radix_tree_preload(GFP_NOFS);
if (error)
goto out_hash_destroy;
spin_lock(&mp->m_perag_lock);
if (radix_tree_insert(&mp->m_perag_tree, index, pag)) {
WARN_ON_ONCE(1);
spin_unlock(&mp->m_perag_lock);
radix_tree_preload_end();
error = -EEXIST;
goto out_hash_destroy;
}
spin_unlock(&mp->m_perag_lock);
radix_tree_preload_end();
/* first new pag is fully initialized */
if (first_initialised == NULLAGNUMBER)
first_initialised = index;
error = xfs_iunlink_init(pag);
if (error)
goto out_hash_destroy;
spin_lock_init(&pag->pag_state_lock);
}
index = xfs_set_inode_alloc(mp, agcount);
if (maxagi)
*maxagi = index;
mp->m_ag_prealloc_blocks = xfs_prealloc_blocks(mp);
return 0;
out_hash_destroy:
xfs_buf_hash_destroy(pag);
out_free_pag:
kmem_free(pag);
out_unwind_new_pags:
/* unwind any prior newly initialized pags */
for (index = first_initialised; index < agcount; index++) {
pag = radix_tree_delete(&mp->m_perag_tree, index);
if (!pag)
break;
xfs_buf_hash_destroy(pag);
xfs_iunlink_destroy(pag);
kmem_free(pag);
}
return error;
}
/* /*
* xfs_readsb * xfs_readsb
* *
......
...@@ -12,6 +12,7 @@ struct xfs_mru_cache; ...@@ -12,6 +12,7 @@ struct xfs_mru_cache;
struct xfs_ail; struct xfs_ail;
struct xfs_quotainfo; struct xfs_quotainfo;
struct xfs_da_geometry; struct xfs_da_geometry;
struct xfs_perag;
/* dynamic preallocation free space thresholds, 5% down to 1% */ /* dynamic preallocation free space thresholds, 5% down to 1% */
enum { enum {
...@@ -297,117 +298,12 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d) ...@@ -297,117 +298,12 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d)
return (xfs_agblock_t) do_div(ld, mp->m_sb.sb_agblocks); return (xfs_agblock_t) do_div(ld, mp->m_sb.sb_agblocks);
} }
/* per-AG block reservation data structures*/ int xfs_buf_hash_init(struct xfs_perag *pag);
struct xfs_ag_resv { void xfs_buf_hash_destroy(struct xfs_perag *pag);
/* number of blocks originally reserved here */
xfs_extlen_t ar_orig_reserved;
/* number of blocks reserved here */
xfs_extlen_t ar_reserved;
/* number of blocks originally asked for */
xfs_extlen_t ar_asked;
};
/*
* Per-ag incore structure, copies of information in agf and agi, to improve the
* performance of allocation group selection.
*/
typedef struct xfs_perag {
struct xfs_mount *pag_mount; /* owner filesystem */
xfs_agnumber_t pag_agno; /* AG this structure belongs to */
atomic_t pag_ref; /* perag reference count */
char pagf_init; /* this agf's entry is initialized */
char pagi_init; /* this agi's entry is initialized */
char pagf_metadata; /* the agf is preferred to be metadata */
char pagi_inodeok; /* The agi is ok for inodes */
uint8_t pagf_levels[XFS_BTNUM_AGF];
/* # of levels in bno & cnt btree */
bool pagf_agflreset; /* agfl requires reset before use */
uint32_t pagf_flcount; /* count of blocks in freelist */
xfs_extlen_t pagf_freeblks; /* total free blocks */
xfs_extlen_t pagf_longest; /* longest free space */
uint32_t pagf_btreeblks; /* # of blocks held in AGF btrees */
xfs_agino_t pagi_freecount; /* number of free inodes */
xfs_agino_t pagi_count; /* number of allocated inodes */
/*
* Inode allocation search lookup optimisation.
* If the pagino matches, the search for new inodes
* doesn't need to search the near ones again straight away
*/
xfs_agino_t pagl_pagino;
xfs_agino_t pagl_leftrec;
xfs_agino_t pagl_rightrec;
/*
* Bitsets of per-ag metadata that have been checked and/or are sick.
* Callers should hold pag_state_lock before accessing this field.
*/
uint16_t pag_checked;
uint16_t pag_sick;
spinlock_t pag_state_lock;
spinlock_t pagb_lock; /* lock for pagb_tree */
struct rb_root pagb_tree; /* ordered tree of busy extents */
unsigned int pagb_gen; /* generation count for pagb_tree */
wait_queue_head_t pagb_wait; /* woken when pagb_gen changes */
atomic_t pagf_fstrms; /* # of filestreams active in this AG */
spinlock_t pag_ici_lock; /* incore inode cache lock */
struct radix_tree_root pag_ici_root; /* incore inode cache root */
int pag_ici_reclaimable; /* reclaimable inodes */
unsigned long pag_ici_reclaim_cursor; /* reclaim restart point */
/* buffer cache index */
spinlock_t pag_buf_lock; /* lock for pag_buf_hash */
struct rhashtable pag_buf_hash;
/* for rcu-safe freeing */
struct rcu_head rcu_head;
int pagb_count; /* pagb slots in use */
/* Blocks reserved for all kinds of metadata. */
struct xfs_ag_resv pag_meta_resv;
/* Blocks reserved for the reverse mapping btree. */
struct xfs_ag_resv pag_rmapbt_resv;
/* background prealloc block trimming */
struct delayed_work pag_blockgc_work;
/* reference count */
uint8_t pagf_refcount_level;
/*
* Unlinked inode information. This incore information reflects
* data stored in the AGI, so callers must hold the AGI buffer lock
* or have some other means to control concurrency.
*/
struct rhashtable pagi_unlinked_hash;
} xfs_perag_t;
static inline struct xfs_ag_resv *
xfs_perag_resv(
struct xfs_perag *pag,
enum xfs_ag_resv_type type)
{
switch (type) {
case XFS_AG_RESV_METADATA:
return &pag->pag_meta_resv;
case XFS_AG_RESV_RMAPBT:
return &pag->pag_rmapbt_resv;
default:
return NULL;
}
}
int xfs_buf_hash_init(xfs_perag_t *pag);
void xfs_buf_hash_destroy(xfs_perag_t *pag);
extern void xfs_uuid_table_free(void); extern void xfs_uuid_table_free(void);
extern uint64_t xfs_default_resblks(xfs_mount_t *mp); extern uint64_t xfs_default_resblks(xfs_mount_t *mp);
extern int xfs_mountfs(xfs_mount_t *mp); extern int xfs_mountfs(xfs_mount_t *mp);
extern int xfs_initialize_perag(xfs_mount_t *mp, xfs_agnumber_t agcount,
xfs_agnumber_t *maxagi);
extern void xfs_unmountfs(xfs_mount_t *); extern void xfs_unmountfs(xfs_mount_t *);
extern int xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta, extern int xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta,
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_icache.h" #include "xfs_icache.h"
#include "xfs_error.h" #include "xfs_error.h"
#include "xfs_ag.h"
#include "xfs_ialloc.h"
/* /*
* The global quota manager. There is only one of these for the entire * The global quota manager. There is only one of these for the entire
...@@ -787,8 +789,12 @@ xfs_qm_qino_alloc( ...@@ -787,8 +789,12 @@ xfs_qm_qino_alloc(
return error; return error;
if (need_alloc) { if (need_alloc) {
error = xfs_dir_ialloc(&init_user_ns, &tp, NULL, S_IFREG, 1, 0, xfs_ino_t ino;
0, false, ipp);
error = xfs_dialloc(&tp, 0, S_IFREG, &ino);
if (!error)
error = xfs_init_new_inode(&init_user_ns, tp, NULL, ino,
S_IFREG, 1, 0, 0, false, ipp);
if (error) { if (error) {
xfs_trans_cancel(tp); xfs_trans_cancel(tp);
return error; return error;
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include "xfs_quota.h" #include "xfs_quota.h"
#include "xfs_reflink.h" #include "xfs_reflink.h"
#include "xfs_iomap.h" #include "xfs_iomap.h"
#include "xfs_sb.h" #include "xfs_ag.h"
#include "xfs_ag_resv.h" #include "xfs_ag_resv.h"
/* /*
...@@ -144,7 +144,7 @@ xfs_reflink_find_shared( ...@@ -144,7 +144,7 @@ xfs_reflink_find_shared(
if (error) if (error)
return error; return error;
cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno); cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agbp->b_pag);
error = xfs_refcount_find_shared(cur, agbno, aglen, fbno, flen, error = xfs_refcount_find_shared(cur, agbno, aglen, fbno, flen,
find_end_of_shared); find_end_of_shared);
...@@ -755,16 +755,19 @@ int ...@@ -755,16 +755,19 @@ int
xfs_reflink_recover_cow( xfs_reflink_recover_cow(
struct xfs_mount *mp) struct xfs_mount *mp)
{ {
struct xfs_perag *pag;
xfs_agnumber_t agno; xfs_agnumber_t agno;
int error = 0; int error = 0;
if (!xfs_sb_version_hasreflink(&mp->m_sb)) if (!xfs_sb_version_hasreflink(&mp->m_sb))
return 0; return 0;
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { for_each_perag(mp, agno, pag) {
error = xfs_refcount_recover_cow_leftovers(mp, agno); error = xfs_refcount_recover_cow_leftovers(mp, pag);
if (error) if (error) {
xfs_perag_put(pag);
break; break;
}
} }
return error; return error;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "xfs_bmap_item.h" #include "xfs_bmap_item.h"
#include "xfs_reflink.h" #include "xfs_reflink.h"
#include "xfs_pwork.h" #include "xfs_pwork.h"
#include "xfs_ag.h"
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/fs_context.h> #include <linux/fs_context.h>
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "xfs_trans_space.h" #include "xfs_trans_space.h"
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_ialloc.h"
/* ----- Kernel only functions below ----- */ /* ----- Kernel only functions below ----- */
int int
...@@ -161,6 +162,7 @@ xfs_symlink( ...@@ -161,6 +162,7 @@ xfs_symlink(
struct xfs_dquot *gdqp = NULL; struct xfs_dquot *gdqp = NULL;
struct xfs_dquot *pdqp = NULL; struct xfs_dquot *pdqp = NULL;
uint resblks; uint resblks;
xfs_ino_t ino;
*ipp = NULL; *ipp = NULL;
...@@ -223,8 +225,11 @@ xfs_symlink( ...@@ -223,8 +225,11 @@ xfs_symlink(
/* /*
* Allocate an inode for the symlink. * Allocate an inode for the symlink.
*/ */
error = xfs_dir_ialloc(mnt_userns, &tp, dp, S_IFLNK | (mode & ~S_IFMT), error = xfs_dialloc(&tp, dp->i_ino, S_IFLNK, &ino);
1, 0, prid, false, &ip); if (!error)
error = xfs_init_new_inode(mnt_userns, tp, dp, ino,
S_IFLNK | (mode & ~S_IFMT), 1, 0, prid,
false, &ip);
if (error) if (error)
goto out_trans_cancel; goto out_trans_cancel;
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include "xfs_fsmap.h" #include "xfs_fsmap.h"
#include "xfs_btree_staging.h" #include "xfs_btree_staging.h"
#include "xfs_icache.h" #include "xfs_icache.h"
#include "xfs_ag.h"
#include "xfs_ag_resv.h"
/* /*
* We include this last to have the helpers above available for the trace * We include this last to have the helpers above available for the trace
......
...@@ -3730,7 +3730,7 @@ TRACE_EVENT(xfs_btree_commit_afakeroot, ...@@ -3730,7 +3730,7 @@ TRACE_EVENT(xfs_btree_commit_afakeroot,
TP_fast_assign( TP_fast_assign(
__entry->dev = cur->bc_mp->m_super->s_dev; __entry->dev = cur->bc_mp->m_super->s_dev;
__entry->btnum = cur->bc_btnum; __entry->btnum = cur->bc_btnum;
__entry->agno = cur->bc_ag.agno; __entry->agno = cur->bc_ag.pag->pag_agno;
__entry->agbno = cur->bc_ag.afake->af_root; __entry->agbno = cur->bc_ag.afake->af_root;
__entry->levels = cur->bc_ag.afake->af_levels; __entry->levels = cur->bc_ag.afake->af_levels;
__entry->blocks = cur->bc_ag.afake->af_blocks; __entry->blocks = cur->bc_ag.afake->af_blocks;
...@@ -3845,7 +3845,7 @@ TRACE_EVENT(xfs_btree_bload_block, ...@@ -3845,7 +3845,7 @@ TRACE_EVENT(xfs_btree_bload_block,
__entry->agno = XFS_FSB_TO_AGNO(cur->bc_mp, fsb); __entry->agno = XFS_FSB_TO_AGNO(cur->bc_mp, fsb);
__entry->agbno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsb); __entry->agbno = XFS_FSB_TO_AGBNO(cur->bc_mp, fsb);
} else { } else {
__entry->agno = cur->bc_ag.agno; __entry->agno = cur->bc_ag.pag->pag_agno;
__entry->agbno = be32_to_cpu(ptr->s); __entry->agbno = be32_to_cpu(ptr->s);
} }
__entry->nr_records = nr_records; __entry->nr_records = nr_records;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册