xfs: realtime rmap and reflink
Subsystems (2)
Hi Carlos,
Reviews have completed for the code that adds reverse mapping and reflink to the realtime device. With these changes, the realtime volume finally reaches feature parity with the data device! This is the base for building more functionality into xfs, such as the zoned storage support that Christoph posted last week. Since we're now past 6.13-rc4, I seek to have these patches merged for 6.14, after spending eight years on development.
Since patchbomb v6.1 I've added Christoph's review tags, and folded in the documentation updates requested during review.
The first patchset are bug fixes for 6.13. Could these be merged asap?
The second and third patchsets are all cleanups and refactoring so that we can fully support having btrees rooted in an inode's data fork. This is necessary because the generic btree code only supports using the immediate area as an internal tree node -- conversion from extents to bmbt format only happens when there are too many leaf records to fit in the immediate area. Therefore, we need to remodel it to support storing records in the immediate area. We also need to be able to reserve space for future btree expansion, so the second patchset enables tracking per-inode reservations from the free space.
The fourth patchset ports reverse mapping btree to the realtime device, which mainly consists of constructing a btree in an inode, linking the inode into the metadata directory tree, and updating the log items to handle rt rmap update log intent items.
The fifth patchset ports the refcount btree, block sharing, and copy on write to the realtime device.
Please have a look at the git tree links for code changes:
https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux.git/log/?h=realtime-reflink_2024-12-23
https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=realtime-reflink_2024-12-23
https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfstests-dev.git/log/?h=realtime-reflink_2024-12-19
(fstests is still behind because I haven't rebased atop the parallel fstests work)
--D
PATCH 1/5 xfs: bug fixes for 6.13
Hi all,
Bug fixes for 6.13.
If you're going to start using this code, I strongly recommend pulling from my git trees, which are linked below.
This has been running on the djcloud for months with no problems. Enjoy! Comments and questions are, as always, welcome.
--D
kernel git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-linux.git/log/?h=xfs-6.13-fixes
xfsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=xfs-6.13-fixes
---
Commits in this patchset:
* xfs: don't over-report free space or inodes in statvfs
* xfs: release the dquot buf outside of qli_lock
--- fs/xfs/xfs_dquot.c | 12 ++++++++---- fs/xfs/xfs_qm_bhv.c | 27 +++++++++++++++++---------- 2 files changed, 25 insertions(+), 14 deletions(-)
PATCH 1/2 xfs: don't over-report free space or inodes in statvfs
From: Darrick J. Wong <[email protected]>
Emmanual Florac reports a strange occurrence when project quota limits are enabled, free space is lower than the remaining quota, and someone runs statvfs:
# mkfs.xfs -f /dev/sda # mount /dev/sda /mnt -o prjquota # xfs_quota -x -c 'limit -p bhard=2G 55' /mnt # mkdir /mnt/dir # xfs_io -c 'chproj 55' -c 'chattr +P' -c 'stat -vvvv' /mnt/dir # fallocate -l 19g /mnt/a # df /mnt /mnt/dir Filesystem Size Used Avail Use% Mounted on /dev/sda 20G 20G 345M 99% /mnt /dev/sda 2.0G 0 2.0G 0% /mnt
I think the bug here is that xfs_fill_statvfs_from_dquot unconditionally assigns to f_bfree without checking that the filesystem has enough free space to fill the remaining project quota. However, this is a longstanding behavior of xfs so it's unclear what to do here.
--- fs/xfs/xfs_qm_bhv.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-)
fs/xfs/xfs_qm_bhv.c +17 -10
@@ -32,21 +32,28 @@ xfs_fill_statvfs_from_dquot( limit = blkres->softlimit ? blkres->softlimit : blkres->hardlimit; -if (limit && statp->f_blocks > limit) { - statp->f_blocks = limit; - statp->f_bfree = statp->f_bavail = - (statp->f_blocks > blkres->reserved) ? - (statp->f_blocks - blkres->reserved) :0 ; +if (limit) { +uint64_t remaining =0 ; + +if (limit > blkres->reserved) + remaining = limit - blkres->reserved; + + statp->f_blocks =min (statp->f_blocks, limit); + statp->f_bfree =min (statp->f_bfree, remaining); + statp->f_bavail =min (statp->f_bavail, remaining); } limit = dqp->q_ino.softlimit ? dqp->q_ino.softlimit : dqp->q_ino.hardlimit; -if (limit && statp->f_files > limit) { - statp->f_files = limit; - statp->f_ffree = - (statp->f_files > dqp->q_ino.reserved) ? - (statp->f_files - dqp->q_ino.reserved) :0 ; +if (limit) { +uint64_t remaining =0 ; + +if (limit > dqp->q_ino.reserved) + remaining = limit - dqp->q_ino.reserved; + + statp->f_files =min (statp->f_files, limit); + statp->f_ffree =min (statp->f_ffree, remaining); } }
PATCH 2/2 xfs: release the dquot buf outside of qli_lock
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Lai Yi reported a lockdep complaint about circular locking:
Chain exists of: &lp->qli_lock --> &bch->bc_lock --> &l->lock Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(&l->lock);
lock(&bch->bc_lock);
lock(&l->lock); lock(&lp->qli_lock);
I /think/ the problem here is that xfs_dquot_attach_buf during quotacheck will release the buffer while it's holding the qli_lock. Because this is a cached buffer, xfs_buf_rele_cached takes b_lock before decrementing b_hold. Other threads have taught lockdep that a locking dependency chain is bp->b_lock -> bch->bc_lock -> l(ru)->lock; and that another chain is l(ru)->lock -> lp->qli_lock. Hence we do not want to take b_lock while holding qli_lock.
--- fs/xfs/xfs_dquot.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
fs/xfs/xfs_dquot.c +8 -4
@@ -1315,7 +1315,8 @@ xfs_dquot_read_buf(/* * Attach a dquot buffer to this dquot to avoid allocating a buffer during a -* dqflush, since dqflush can be called from reclaim context. +* dqflush, since dqflush can be called from reclaim context. Caller must hold +* the dqlock. */ int xfs_dquot_attach_buf(
@@ -1336,13 +1337,16 @@ xfs_dquot_attach_buf(return error;/* -* Attach the dquot to the buffer so that the AIL does not have -* to read the dquot buffer to push this item. +* Hold the dquot buffer so that we retain our ref to it after +* detaching it from the transaction, then give that ref to the +* dquot log item so that the AIL does not have to read the +* dquot buffer to push this item. */ xfs_buf_hold (bp); +xfs_trans_brelse (tp, bp); +spin_lock (&qlip->qli_lock); lip->li_buf = bp; -xfs_trans_brelse (tp, bp); } qlip->qli_dirty = true;spin_unlock (&qlip->qli_lock);
PATCH 2/5 xfs: refactor btrees to support records in inode root
In reply to Darrick J. WongHi all,
Amend the btree code to support storing btree rcords in the inode root, because the current bmbt code does not support this.
If you're going to start using this code, I strongly recommend pulling from my git trees, which are linked below.
This has been running on the djcloud for months with no problems. Enjoy! Comments and questions are, as always, welcome.
--D
kernel git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-linux.git/log/?h=btree-ifork-records
xfsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=btree-ifork-records
---
Commits in this patchset:
* xfs: tidy up xfs_iroot_realloc
* xfs: refactor the inode fork memory allocation functions
* xfs: make xfs_iroot_realloc take the new numrecs instead of deltas
* xfs: make xfs_iroot_realloc a bmap btree function
* xfs: tidy up xfs_bmap_broot_realloc a bit
* xfs: hoist the node iroot update code out of xfs_btree_new_iroot
* xfs: hoist the node iroot update code out of xfs_btree_kill_iroot
* xfs: support storing records in the inode core root
--- fs/xfs/libxfs/xfs_bmap.c | 7 - fs/xfs/libxfs/xfs_bmap_btree.c | 111 ++++++++++++ fs/xfs/libxfs/xfs_bmap_btree.h | 3 fs/xfs/libxfs/xfs_btree.c | 333 ++++++++++++++++++++++++++++--------- fs/xfs/libxfs/xfs_btree.h | 18 ++ fs/xfs/libxfs/xfs_btree_staging.c | 9 + fs/xfs/libxfs/xfs_inode_fork.c | 170 ++++++------------- fs/xfs/libxfs/xfs_inode_fork.h | 6 + 8 files changed, 445 insertions(+), 212 deletions(-)
PATCH 1/8 xfs: tidy up xfs_iroot_realloc
From: Darrick J. Wong <[email protected]>
Tidy up this function a bit before we start refactoring the memory handling and move the function to the bmbt code.
--- fs/xfs/libxfs/xfs_inode_fork.c | 83 +++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 43 deletions(-)
fs/xfs/libxfs/xfs_inode_fork.c +40 -43
@@ -382,33 +382,32 @@ xfs_iformat_attr_fork(*/ void xfs_iroot_realloc ( -xfs_inode_t *ip, +struct xfs_inode *ip,int rec_diff,int whichfork) {struct xfs_mount *mp = ip->i_mount; -int cur_max; -struct xfs_ifork *ifp; +struct xfs_ifork *ifp =xfs_ifork_ptr (ip, whichfork);struct xfs_btree_block *new_broot; -int new_max; -size_t new_size;char *np;char *op; +size_t new_size; +short old_size = ifp->if_broot_bytes; +int cur_max; +int new_max;/* * Handle the degenerate case quietly. */ -if (rec_diff ==0 ) { +if (rec_diff ==0 )return ; - } - ifp =xfs_ifork_ptr (ip, whichfork);if (rec_diff >0 ) {/* * If there wasn't any memory allocated before, just * allocate it now and get out. */ -if (ifp->if_broot_bytes ==0 ) { +if (old_size ==0 ) { new_size =xfs_bmap_broot_space_calc (mp, rec_diff); ifp->if_broot =kmalloc (new_size,GFP_KERNEL | __GFP_NOFAIL);
@@ -422,13 +421,13 @@ xfs_iroot_realloc(* location. The records don't change location because * they are kept butted up against the btree block header. */ - cur_max =xfs_bmbt_maxrecs (mp, ifp->if_broot_bytes, false); + cur_max =xfs_bmbt_maxrecs (mp, old_size, false); new_max = cur_max + rec_diff; new_size =xfs_bmap_broot_space_calc (mp, new_max); ifp->if_broot =krealloc (ifp->if_broot, new_size,GFP_KERNEL | __GFP_NOFAIL); op = (char *)xfs_bmap_broot_ptr_addr (mp, ifp->if_broot,1 , - ifp->if_broot_bytes); + old_size); np = (char *)xfs_bmap_broot_ptr_addr (mp, ifp->if_broot,1 , (int )new_size); ifp->if_broot_bytes = (int )new_size;
@@ -443,52 +442,50 @@ xfs_iroot_realloc(* if_broot buffer. It must already exist. If we go to zero * records, just get rid of the root and clear the status bit. */ -ASSERT ((ifp->if_broot !=NULL ) && (ifp->if_broot_bytes >0 )); - cur_max =xfs_bmbt_maxrecs (mp, ifp->if_broot_bytes, false); +ASSERT (ifp->if_broot !=NULL && old_size >0 ); + cur_max =xfs_bmbt_maxrecs (mp, old_size, false); new_max = cur_max + rec_diff;ASSERT (new_max >=0 );if (new_max >0 ) new_size =xfs_bmap_broot_space_calc (mp, new_max);else new_size =0 ; -if (new_size >0 ) { - new_broot =kmalloc (new_size,GFP_KERNEL | __GFP_NOFAIL); -/* -* First copy over the btree block header. -*/ -memcpy (new_broot, ifp->if_broot, -xfs_bmbt_block_len (ip->i_mount)); - }else { - new_broot =NULL ; +if (new_size ==0 ) { + ifp->if_broot =NULL ; + ifp->if_broot_bytes =0 ; +return ; }/* -* Only copy the keys and pointers if there are any. +* Shrink the btree root by allocating a smaller object and copying the +* fields from the old object to the new object. krealloc does nothing +* if we realloc downwards. */ -if (new_max >0 ) { -/* -* First copy the keys. -*/ - op = (char *)xfs_bmbt_key_addr (mp, ifp->if_broot,1 ); - np = (char *)xfs_bmbt_key_addr (mp, new_broot,1 ); -memcpy (np, op, new_max * (uint )sizeof (xfs_bmbt_key_t)); + new_broot =kmalloc (new_size,GFP_KERNEL | __GFP_NOFAIL); +/* +* First copy over the btree block header. +*/ +memcpy (new_broot, ifp->if_broot,xfs_bmbt_block_len (ip->i_mount)); + +/* +* First copy the keys. +*/ + op = (char *)xfs_bmbt_key_addr (mp, ifp->if_broot,1 ); + np = (char *)xfs_bmbt_key_addr (mp, new_broot,1 ); +memcpy (np, op, new_max * (uint )sizeof (xfs_bmbt_key_t)); + +/* +* Then copy the pointers. +*/ + op = (char *)xfs_bmap_broot_ptr_addr (mp, ifp->if_broot,1 , old_size); + np = (char *)xfs_bmap_broot_ptr_addr (mp, new_broot,1 , (int )new_size); +memcpy (np, op, new_max * (uint )sizeof (xfs_fsblock_t)); -/* -* Then copy the pointers. -*/ - op = (char *)xfs_bmap_broot_ptr_addr (mp, ifp->if_broot,1 , - ifp->if_broot_bytes); - np = (char *)xfs_bmap_broot_ptr_addr (mp, new_broot,1 , - (int )new_size); -memcpy (np, op, new_max * (uint )sizeof (xfs_fsblock_t)); - }kfree (ifp->if_broot); ifp->if_broot = new_broot; ifp->if_broot_bytes = (int )new_size; -if (ifp->if_broot) -ASSERT (xfs_bmap_bmdr_space (ifp->if_broot) <= -xfs_inode_fork_size (ip, whichfork)); -return ; +ASSERT (xfs_bmap_bmdr_space (ifp->if_broot) <= +xfs_inode_fork_size (ip, whichfork)); }
PATCH 2/8 xfs: refactor the inode fork memory allocation functions
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Hoist the code that allocates, frees, and reallocates if_broot into a single xfs_iroot_krealloc function. Eventually we're going to push xfs_iroot_realloc into the btree ops structure to handle multiple inode-rooted btrees, but first let's separate out the bits that should stay in xfs_inode_fork.c.
--- fs/xfs/libxfs/xfs_inode_fork.c | 116 +++++++++++++++++++++++++++------------- fs/xfs/libxfs/xfs_inode_fork.h | 5 ++ 2 files changed, 82 insertions(+), 39 deletions(-)
fs/xfs/libxfs/xfs_inode_fork.c +77 -39
@@ -178,7 +178,7 @@ xfs_iformat_btree(struct xfs_mount *mp = ip->i_mount;xfs_bmdr_block_t *dfp;struct xfs_ifork *ifp; -/* REFERENCED */ +struct xfs_btree_block *broot;int nrecs;int size;int level;
@@ -211,16 +211,13 @@ xfs_iformat_btree(return -EFSCORRUPTED ; } - ifp->if_broot_bytes = size; - ifp->if_broot =kmalloc (size, -GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_NOFAIL); -ASSERT (ifp->if_broot !=NULL ); + broot =xfs_broot_alloc (ifp, size);/* * Copy and convert from the on-disk structure * to the in-memory structure. */ xfs_bmdr_to_bmbt (ip, dfp,XFS_DFORK_SIZE (dip, ip->i_mount, whichfork), - ifp->if_broot, size); + broot, size); ifp->if_bytes =0 ; ifp->if_data =NULL ;
@@ -362,6 +359,69 @@ xfs_iformat_attr_fork(return error; } +/* +* Allocate the if_broot component of an inode fork so that it is @new_size +* bytes in size, using __GFP_NOLOCKDEP like all the other code that +* initializes a broot during inode load. Returns if_broot. +*/ +struct xfs_btree_block * +xfs_broot_alloc ( +struct xfs_ifork *ifp, +size_t new_size) +{ +ASSERT (ifp->if_broot ==NULL ); + + ifp->if_broot =kmalloc (new_size, +GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_NOFAIL); + ifp->if_broot_bytes = new_size; +return ifp->if_broot; +} + +/* +* Reallocate the if_broot component of an inode fork so that it is @new_size +* bytes in size. Returns if_broot. +*/ +struct xfs_btree_block * +xfs_broot_realloc ( +struct xfs_ifork *ifp, +size_t new_size) +{ +/* No size change? No action needed. */ +if (new_size == ifp->if_broot_bytes) +return ifp->if_broot; + +/* New size is zero, free it. */ +if (new_size ==0 ) { + ifp->if_broot_bytes =0 ; +kfree (ifp->if_broot); + ifp->if_broot =NULL ; +return NULL ; + } + +/* +* Shrinking the iroot means we allocate a new smaller object and copy +* it. We don't trust krealloc not to nop on realloc-down. +*/ +if (ifp->if_broot_bytes >0 && ifp->if_broot_bytes > new_size) { +struct xfs_btree_block *old_broot = ifp->if_broot; + + ifp->if_broot =kmalloc (new_size,GFP_KERNEL | __GFP_NOFAIL); + ifp->if_broot_bytes = new_size; +memcpy (ifp->if_broot, old_broot, new_size); +kfree (old_broot); +return ifp->if_broot; + } + +/* +* Growing the iroot means we can krealloc. This may get us the same +* object. +*/ + ifp->if_broot =krealloc (ifp->if_broot, new_size, +GFP_KERNEL | __GFP_NOFAIL); + ifp->if_broot_bytes = new_size; +return ifp->if_broot; +} +/* * Reallocate the space for if_broot based on the number of records * being added or deleted as indicated in rec_diff. Move the records
@@ -388,7 +448,6 @@ xfs_iroot_realloc( {struct xfs_mount *mp = ip->i_mount;struct xfs_ifork *ifp =xfs_ifork_ptr (ip, whichfork); -struct xfs_btree_block *new_broot;char *np;char *op;size_t new_size;
@@ -409,9 +468,7 @@ xfs_iroot_realloc(*/ if (old_size ==0 ) { new_size =xfs_bmap_broot_space_calc (mp, rec_diff); - ifp->if_broot =kmalloc (new_size, -GFP_KERNEL | __GFP_NOFAIL); - ifp->if_broot_bytes = (int )new_size; +xfs_broot_realloc (ifp, new_size);return ; }
@@ -424,13 +481,12 @@ xfs_iroot_realloc( cur_max =xfs_bmbt_maxrecs (mp, old_size, false); new_max = cur_max + rec_diff; new_size =xfs_bmap_broot_space_calc (mp, new_max); - ifp->if_broot =krealloc (ifp->if_broot, new_size, -GFP_KERNEL | __GFP_NOFAIL); + +xfs_broot_realloc (ifp, new_size); op = (char *)xfs_bmap_broot_ptr_addr (mp, ifp->if_broot,1 , old_size); np = (char *)xfs_bmap_broot_ptr_addr (mp, ifp->if_broot,1 , (int )new_size); - ifp->if_broot_bytes = (int )new_size;ASSERT (xfs_bmap_bmdr_space (ifp->if_broot) <=xfs_inode_fork_size (ip, whichfork));memmove (np, op, cur_max * (uint )sizeof (xfs_fsblock_t));
@@ -451,39 +507,21 @@ xfs_iroot_realloc(else new_size =0 ;if (new_size ==0 ) { - ifp->if_broot =NULL ; - ifp->if_broot_bytes =0 ; +xfs_broot_realloc (ifp,0 );return ; }/* -* Shrink the btree root by allocating a smaller object and copying the -* fields from the old object to the new object. krealloc does nothing -* if we realloc downwards. -*/ - new_broot =kmalloc (new_size,GFP_KERNEL | __GFP_NOFAIL); -/* -* First copy over the btree block header. -*/ -memcpy (new_broot, ifp->if_broot,xfs_bmbt_block_len (ip->i_mount)); - -/* -* First copy the keys. -*/ - op = (char *)xfs_bmbt_key_addr (mp, ifp->if_broot,1 ); - np = (char *)xfs_bmbt_key_addr (mp, new_broot,1 ); -memcpy (np, op, new_max * (uint )sizeof (xfs_bmbt_key_t)); - -/* -* Then copy the pointers. +* Shrink the btree root by moving the bmbt pointers, since they are +* not butted up against the btree block header, then reallocating +* broot. */ op = (char *)xfs_bmap_broot_ptr_addr (mp, ifp->if_broot,1 , old_size); - np = (char *)xfs_bmap_broot_ptr_addr (mp, new_broot,1 , (int )new_size); -memcpy (np, op, new_max * (uint )sizeof (xfs_fsblock_t)); + np = (char *)xfs_bmap_broot_ptr_addr (mp, ifp->if_broot,1 , + (int )new_size); +memmove (np, op, new_max * (uint )sizeof (xfs_fsblock_t)); -kfree (ifp->if_broot); - ifp->if_broot = new_broot; - ifp->if_broot_bytes = (int )new_size; +xfs_broot_realloc (ifp, new_size);ASSERT (xfs_bmap_bmdr_space (ifp->if_broot) <=xfs_inode_fork_size (ip, whichfork)); }
fs/xfs/libxfs/xfs_inode_fork.h +5 -0
@@ -170,6 +170,11 @@ void xfs_iflush_fork(struct xfs_inode *, struct xfs_dinode *,void xfs_idestroy_fork (struct xfs_ifork *ifp);void *xfs_idata_realloc (struct xfs_inode *ip,int64_t byte_diff,int whichfork); +struct xfs_btree_block *xfs_broot_alloc (struct xfs_ifork *ifp, +size_t new_size); +struct xfs_btree_block *xfs_broot_realloc (struct xfs_ifork *ifp, +size_t new_size); +void xfs_iroot_realloc (struct xfs_inode *,int ,int );int xfs_iread_extents (struct xfs_trans *,struct xfs_inode *,int ); int xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *,
PATCH 3/8 xfs: make xfs_iroot_realloc take the new numrecs instead of deltas
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Change the calling signature of xfs_iroot_realloc to take the ifork and the new number of records in the btree block, not a diff against the current number. This will make the callsites easier to understand.
Note that this function is misnamed because it is very specific to the single type of inode-rooted btree supported. This will be addressed in a subsequent patch.
Return the new btree root to reduce the amount of code clutter.
--- fs/xfs/libxfs/xfs_bmap.c | 7 +-- fs/xfs/libxfs/xfs_btree.c | 25 ++++-------- fs/xfs/libxfs/xfs_inode_fork.c | 83 ++++++++++++++++++---------------------- fs/xfs/libxfs/xfs_inode_fork.h | 3 + 4 files changed, 51 insertions(+), 67 deletions(-)
fs/xfs/libxfs/xfs_bmap.c +3 -4
@@ -615,7 +615,7 @@ xfs_bmap_btree_to_extents(xfs_trans_binval (tp, cbp);if (cur->bc_levels[0 ].bp == cbp) cur->bc_levels[0 ].bp =NULL ; -xfs_iroot_realloc (ip,-1 , whichfork); +xfs_iroot_realloc (ip, whichfork,0 );ASSERT (ifp->if_broot ==NULL ); ifp->if_format =XFS_DINODE_FMT_EXTENTS ; *logflagsp |=XFS_ILOG_CORE |xfs_ilog_fext (whichfork);
@@ -659,12 +659,11 @@ xfs_bmap_extents_to_btree(* Make space in the inode incore. This needs to be undone if we fail * to expand the root. */ -xfs_iroot_realloc (ip,1 , whichfork); + block =xfs_iroot_realloc (ip, whichfork,1 );/* * Fill in the root. */ - block = ifp->if_broot;xfs_bmbt_init_block (ip, block,NULL ,1 ,1 );/* * Need a cursor. Can't allocate until bb_level is filled in.
@@ -746,7 +745,7 @@ xfs_bmap_extents_to_btree( out_unreserve_dquot:xfs_trans_mod_dquot_byino (tp, ip,XFS_TRANS_DQ_BCOUNT ,-1L ); out_root_realloc: -xfs_iroot_realloc (ip,-1 , whichfork); +xfs_iroot_realloc (ip, whichfork,0 ); ifp->if_format =XFS_DINODE_FMT_EXTENTS ;ASSERT (ifp->if_broot ==NULL );xfs_btree_del_cursor (cur,XFS_BTREE_ERROR );
fs/xfs/libxfs/xfs_btree.c +9 -16
@@ -3161,9 +3161,7 @@ xfs_btree_new_iroot(xfs_btree_copy_ptrs (cur, pp, &nptr,1 ); -xfs_iroot_realloc (cur->bc_ino.ip, -1 -xfs_btree_get_numrecs (cblock), - cur->bc_ino.whichfork); +xfs_iroot_realloc (cur->bc_ino.ip, cur->bc_ino.whichfork,1 );xfs_btree_setbuf (cur, level, cbp);
@@ -3347,7 +3345,8 @@ xfs_btree_make_block_unfull(if (numrecs < cur->bc_ops->get_dmaxrecs (cur, level)) {/* A root block that can be made bigger. */ -xfs_iroot_realloc (ip,1 , cur->bc_ino.whichfork); +xfs_iroot_realloc (ip, cur->bc_ino.whichfork, + numrecs +1 ); *stat =1 ; }else {/* A root block that needs replacing */
@@ -3705,9 +3704,7 @@ STATIC intxfs_btree_kill_iroot ( struct xfs_btree_cur *cur) { -int whichfork = cur->bc_ino.whichfork;struct xfs_inode *ip = cur->bc_ino.ip; -struct xfs_ifork *ifp =xfs_ifork_ptr (ip, whichfork);struct xfs_btree_block *block;struct xfs_btree_block *cblock;union xfs_btree_key *kp;
@@ -3716,7 +3713,6 @@ xfs_btree_kill_iroot(union xfs_btree_ptr *cpp;struct xfs_buf *cbp;int level; -int index;int numrecs;int error;#ifdef DEBUG
@@ -3762,14 +3758,10 @@ xfs_btree_kill_iroot(ASSERT (xfs_btree_ptr_is_null (cur, &ptr));#endif - index = numrecs - cur->bc_ops->get_maxrecs (cur, level); -if (index) { -xfs_iroot_realloc (cur->bc_ino.ip, index, - cur->bc_ino.whichfork); - block = ifp->if_broot; - } + block =xfs_iroot_realloc (cur->bc_ino.ip, cur->bc_ino.whichfork, + numrecs); -be16_add_cpu (&block->bb_numrecs, index); + block->bb_numrecs =be16_to_cpu (numrecs);ASSERT (block->bb_numrecs == cblock->bb_numrecs); kp =xfs_btree_key_addr (cur,1 , block);
@@ -3949,10 +3941,11 @@ xfs_btree_delrec(/* * We're at the root level. First, shrink the root block in-memory. * Try to get rid of the next level down. If we can't then there's -* nothing left to do. +* nothing left to do. numrecs was decremented above. */ if (xfs_btree_at_iroot (cur, level)) { -xfs_iroot_realloc (cur->bc_ino.ip,-1 , cur->bc_ino.whichfork); +xfs_iroot_realloc (cur->bc_ino.ip, cur->bc_ino.whichfork, + numrecs); error =xfs_btree_kill_iroot (cur);if (error)
fs/xfs/libxfs/xfs_inode_fork.c +37 -46
137 lines not on this page · raw message
fs/xfs/libxfs/xfs_inode_fork.h +2 -1
@@ -175,7 +175,8 @@ struct xfs_btree_block *xfs_broot_alloc(struct xfs_ifork *ifp,struct xfs_btree_block *xfs_broot_realloc (struct xfs_ifork *ifp,size_t new_size); -void xfs_iroot_realloc (struct xfs_inode *,int ,int ); +struct xfs_btree_block *xfs_iroot_realloc (struct xfs_inode *ip,int whichfork, +unsigned int new_numrecs);int xfs_iread_extents (struct xfs_trans *,struct xfs_inode *,int );int xfs_iextents_copy (struct xfs_inode *,struct xfs_bmbt_rec *,int );
PATCH 4/8 xfs: make xfs_iroot_realloc a bmap btree function
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Move the inode fork btree root reallocation function part of the btree ops because it's now mostly bmbt-specific code.
--- fs/xfs/libxfs/xfs_bmap.c | 6 +- fs/xfs/libxfs/xfs_bmap_btree.c | 104 ++++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_bmap_btree.h | 3 + fs/xfs/libxfs/xfs_btree.c | 11 ++-- fs/xfs/libxfs/xfs_btree.h | 16 ++++++ fs/xfs/libxfs/xfs_inode_fork.c | 96 ------------------------------------- fs/xfs/libxfs/xfs_inode_fork.h | 2 - 7 files changed, 130 insertions(+), 108 deletions(-)
fs/xfs/libxfs/xfs_bmap.c +3 -3
@@ -615,7 +615,7 @@ xfs_bmap_btree_to_extents(xfs_trans_binval (tp, cbp);if (cur->bc_levels[0 ].bp == cbp) cur->bc_levels[0 ].bp =NULL ; -xfs_iroot_realloc (ip, whichfork,0 ); +xfs_bmap_broot_realloc (ip, whichfork,0 );ASSERT (ifp->if_broot ==NULL ); ifp->if_format =XFS_DINODE_FMT_EXTENTS ; *logflagsp |=XFS_ILOG_CORE |xfs_ilog_fext (whichfork);
@@ -659,7 +659,7 @@ xfs_bmap_extents_to_btree(* Make space in the inode incore. This needs to be undone if we fail * to expand the root. */ - block =xfs_iroot_realloc (ip, whichfork,1 ); + block =xfs_bmap_broot_realloc (ip, whichfork,1 );/* * Fill in the root.
@@ -745,7 +745,7 @@ xfs_bmap_extents_to_btree( out_unreserve_dquot:xfs_trans_mod_dquot_byino (tp, ip,XFS_TRANS_DQ_BCOUNT ,-1L ); out_root_realloc: -xfs_iroot_realloc (ip, whichfork,0 ); +xfs_bmap_broot_realloc (ip, whichfork,0 ); ifp->if_format =XFS_DINODE_FMT_EXTENTS ;ASSERT (ifp->if_broot ==NULL );xfs_btree_del_cursor (cur,XFS_BTREE_ERROR );
fs/xfs/libxfs/xfs_bmap_btree.c +104 -0
116 lines not on this page · raw message
fs/xfs/libxfs/xfs_bmap_btree.h +3 -0
@@ -198,4 +198,7 @@ xfs_bmap_bmdr_space(struct xfs_btree_block *bb) return xfs_bmdr_space_calc(be16_to_cpu(bb->bb_numrecs)); } +struct xfs_btree_block *xfs_bmap_broot_realloc (struct xfs_inode *ip, +int whichfork,unsigned int new_numrecs); +#endif /* __XFS_BMAP_BTREE_H__ */
fs/xfs/libxfs/xfs_btree.c +4 -7
@@ -3161,7 +3161,7 @@ xfs_btree_new_iroot(xfs_btree_copy_ptrs (cur, pp, &nptr,1 ); -xfs_iroot_realloc (cur->bc_ino.ip, cur->bc_ino.whichfork,1 ); + cur->bc_ops->broot_realloc (cur,1 );xfs_btree_setbuf (cur, level, cbp);
@@ -3345,8 +3345,7 @@ xfs_btree_make_block_unfull(if (numrecs < cur->bc_ops->get_dmaxrecs (cur, level)) {/* A root block that can be made bigger. */ -xfs_iroot_realloc (ip, cur->bc_ino.whichfork, - numrecs +1 ); + cur->bc_ops->broot_realloc (cur, numrecs +1 ); *stat =1 ; }else {/* A root block that needs replacing */
@@ -3758,8 +3757,7 @@ xfs_btree_kill_iroot(ASSERT (xfs_btree_ptr_is_null (cur, &ptr));#endif - block =xfs_iroot_realloc (cur->bc_ino.ip, cur->bc_ino.whichfork, - numrecs); + block = cur->bc_ops->broot_realloc (cur, numrecs); block->bb_numrecs =be16_to_cpu (numrecs);ASSERT (block->bb_numrecs == cblock->bb_numrecs);
@@ -3944,8 +3942,7 @@ xfs_btree_delrec(* nothing left to do. numrecs was decremented above. */ if (xfs_btree_at_iroot (cur, level)) { -xfs_iroot_realloc (cur->bc_ino.ip, cur->bc_ino.whichfork, - numrecs); + cur->bc_ops->broot_realloc (cur, numrecs); error =xfs_btree_kill_iroot (cur);if (error)
fs/xfs/libxfs/xfs_btree.h +16 -0
@@ -213,6 +213,22 @@ struct xfs_btree_ops {const union xfs_btree_key *key1, const union xfs_btree_key *key2, const union xfs_btree_key *mask); + +/* +* Reallocate the space for if_broot to fit the number of records. +* Move the records and pointers in if_broot to fit the new size. When +* shrinking this will eliminate holes between the records and pointers +* created by the caller. When growing this will create holes to be +* filled in by the caller. +* +* The caller must not request to add more records than would fit in +* the on-disk inode root. If the if_broot is currently NULL, then if +* we are adding records, one will be allocated. The caller must also +* not request that the number of records go below zero, although it +* can go to zero. +*/ +struct xfs_btree_block *(*broot_realloc)(struct xfs_btree_cur *cur, +unsigned int new_numrecs); };/* btree geometry flags */
fs/xfs/libxfs/xfs_inode_fork.c +0 -96
102 lines not on this page · raw message
fs/xfs/libxfs/xfs_inode_fork.h +0 -2
@@ -175,8 +175,6 @@ struct xfs_btree_block *xfs_broot_alloc(struct xfs_ifork *ifp,struct xfs_btree_block *xfs_broot_realloc (struct xfs_ifork *ifp,size_t new_size); -struct xfs_btree_block *xfs_iroot_realloc (struct xfs_inode *ip,int whichfork, -unsigned int new_numrecs);int xfs_iread_extents (struct xfs_trans *,struct xfs_inode *,int );int xfs_iextents_copy (struct xfs_inode *,struct xfs_bmbt_rec *,int );
PATCH 5/8 xfs: tidy up xfs_bmap_broot_realloc a bit
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Hoist out the code that migrates broot pointers during a resize operation to avoid code duplication and streamline the caller. Also use the correct bmbt pointer type for the sizeof operation.
--- fs/xfs/libxfs/xfs_bmap_btree.c | 43 +++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 18 deletions(-)
fs/xfs/libxfs/xfs_bmap_btree.c +25 -18
@@ -516,6 +516,22 @@ xfs_bmbt_keys_contiguous( be64_to_cpu(key2->bmbt.br_startoff)); } +static inline void +xfs_bmbt_move_ptrs ( +struct xfs_mount *mp, +struct xfs_btree_block *broot, +short old_size, +size_t new_size, +unsigned int numrecs) +{ +void *dptr; +void *sptr; + + sptr =xfs_bmap_broot_ptr_addr (mp, broot,1 , old_size); + dptr =xfs_bmap_broot_ptr_addr (mp, broot,1 , new_size); +memmove (dptr, sptr, numrecs *sizeof (xfs_bmbt_ptr_t)); +} +/* * Reallocate the space for if_broot based on the number of records. Move the * records and pointers in if_broot to fit the new size. When shrinking this
@@ -541,8 +557,7 @@ xfs_bmap_broot_realloc( {struct xfs_mount *mp = ip->i_mount;struct xfs_ifork *ifp =xfs_ifork_ptr (ip, whichfork); -char *np; -char *op; +struct xfs_btree_block *broot;unsigned int new_size;unsigned int old_size = ifp->if_broot_bytes;
@@ -577,15 +592,11 @@ xfs_bmap_broot_realloc(* they are kept butted up against the btree block header. */ old_numrecs =xfs_bmbt_maxrecs (mp, old_size, false); -xfs_broot_realloc (ifp, new_size); - op = (char *)xfs_bmap_broot_ptr_addr (mp, ifp->if_broot,1 , - old_size); - np = (char *)xfs_bmap_broot_ptr_addr (mp, ifp->if_broot,1 , - (int )new_size); -ASSERT (xfs_bmap_bmdr_space (ifp->if_broot) <= + broot =xfs_broot_realloc (ifp, new_size); +ASSERT (xfs_bmap_bmdr_space (broot) <=xfs_inode_fork_size (ip, whichfork)); -memmove (np, op, old_numrecs * (uint )sizeof (xfs_fsblock_t)); -return ifp->if_broot; +xfs_bmbt_move_ptrs (mp, broot, old_size, new_size, old_numrecs); +return broot; }/*
@@ -599,15 +610,11 @@ xfs_bmap_broot_realloc(* not butted up against the btree block header, then reallocating * broot. */ - op = (char *)xfs_bmap_broot_ptr_addr (mp, ifp->if_broot,1 , old_size); - np = (char *)xfs_bmap_broot_ptr_addr (mp, ifp->if_broot,1 , - (int )new_size); -memmove (np, op, new_numrecs * (uint )sizeof (xfs_fsblock_t)); - -xfs_broot_realloc (ifp, new_size); -ASSERT (xfs_bmap_bmdr_space (ifp->if_broot) <= +xfs_bmbt_move_ptrs (mp, ifp->if_broot, old_size, new_size, new_numrecs); + broot =xfs_broot_realloc (ifp, new_size); +ASSERT (xfs_bmap_bmdr_space (broot) <=xfs_inode_fork_size (ip, whichfork)); -return ifp->if_broot; +return broot; } static struct xfs_btree_block *
PATCH 6/8 xfs: hoist the node iroot update code out of xfs_btree_new_iroot
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
In preparation for allowing records in an inode btree root, hoist the code that copies keyptrs from an existing node root into a child block to a separate function. Note that the new function explicitly computes the keys of the new child block and stores that in the root block; while the bmap btree could rely on leaving the key alone, realtime rmap needs to set the new high key.
--- fs/xfs/libxfs/xfs_btree.c | 117 +++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 41 deletions(-)
fs/xfs/libxfs/xfs_btree.c +76 -41
@@ -3078,6 +3078,78 @@ xfs_btree_split(#define xfs_btree_split __xfs_btree_split#endif /* __KERNEL__ */ +/* +* Move the keys and pointers from a root block to a separate block. +* +* Since the keyptr size does not change, all we have to do is increase the +* tree height, copy the keyptrs to the new internal node (cblock), shrink +* the root, and copy the pointers there. +*/ +STATIC int +xfs_btree_promote_node_iroot ( +struct xfs_btree_cur *cur, +struct xfs_btree_block *block, +int level, +struct xfs_buf *cbp, +union xfs_btree_ptr *cptr, +struct xfs_btree_block *cblock) +{ +union xfs_btree_key *ckp; +union xfs_btree_key *kp; +union xfs_btree_ptr *cpp; +union xfs_btree_ptr *pp; +int i; +int error; +int numrecs =xfs_btree_get_numrecs (block); + +/* +* Increase tree height, adjusting the root block level to match. +* We cannot change the root btree node size until we've copied the +* block contents to the new child block. +*/ +be16_add_cpu (&block->bb_level,1 ); + cur->bc_nlevels++; + cur->bc_levels[level +1 ].ptr =1 ; + +/* +* Adjust the root btree record count, then copy the keys from the old +* root to the new child block. +*/ +xfs_btree_set_numrecs (block,1 ); + kp =xfs_btree_key_addr (cur,1 , block); + ckp =xfs_btree_key_addr (cur,1 , cblock); +xfs_btree_copy_keys (cur, ckp, kp, numrecs); + +/* Check the pointers and copy them to the new child block. */ + pp =xfs_btree_ptr_addr (cur,1 , block); + cpp =xfs_btree_ptr_addr (cur,1 , cblock); +for (i =0 ; i < numrecs; i++) { + error =xfs_btree_debug_check_ptr (cur, pp, i, level); +if (error) +return error; + } +xfs_btree_copy_ptrs (cur, cpp, pp, numrecs); + +/* +* Set the first keyptr to point to the new child block, then shrink +* the memory buffer for the root block. +*/ + error =xfs_btree_debug_check_ptr (cur, cptr,0 , level); +if (error) +return error; +xfs_btree_copy_ptrs (cur, pp, cptr,1 ); +xfs_btree_get_keys (cur, cblock, kp); + + cur->bc_ops->broot_realloc (cur,1 ); + +/* Attach the new block to the cursor and log it. */ +xfs_btree_setbuf (cur, level, cbp); +xfs_btree_log_block (cur, cbp,XFS_BB_ALL_BITS ); +xfs_btree_log_keys (cur, cbp,1 , numrecs); +xfs_btree_log_ptrs (cur, cbp,1 , numrecs); +return 0 ; +} +/* * Copy the old inode root contents into a real block and make the * broot point to it.
@@ -3091,14 +3163,10 @@ xfs_btree_new_iroot(struct xfs_buf *cbp;/* buffer for cblock */ struct xfs_btree_block *block;/* btree block */ struct xfs_btree_block *cblock;/* child btree block */ -union xfs_btree_key *ckp;/* child key pointer */ -union xfs_btree_ptr *cpp;/* child ptr pointer */ -union xfs_btree_key *kp;/* pointer to btree key */ -union xfs_btree_ptr *pp;/* pointer to block addr */ +union xfs_btree_ptr *pp;union xfs_btree_ptr nptr;/* new block addr */ int level;/* btree level */ int error;/* error return code */ -int i;/* loop counter */ XFS_BTREE_STATS_INC (cur, newroot);
@@ -3136,45 +3204,12 @@ xfs_btree_new_iroot( cblock->bb_u.s.bb_blkno = bno; } -be16_add_cpu (&block->bb_level,1 ); -xfs_btree_set_numrecs (block,1 ); - cur->bc_nlevels++; -ASSERT (cur->bc_nlevels <= cur->bc_maxlevels); - cur->bc_levels[level +1 ].ptr =1 ; - - kp =xfs_btree_key_addr (cur,1 , block); - ckp =xfs_btree_key_addr (cur,1 , cblock); -xfs_btree_copy_keys (cur, ckp, kp,xfs_btree_get_numrecs (cblock)); - - cpp =xfs_btree_ptr_addr (cur,1 , cblock); -for (i =0 ; i <be16_to_cpu (cblock->bb_numrecs); i++) { - error =xfs_btree_debug_check_ptr (cur, pp, i, level); -if (error) - goto error0; - } - -xfs_btree_copy_ptrs (cur, cpp, pp,xfs_btree_get_numrecs (cblock)); - - error =xfs_btree_debug_check_ptr (cur, &nptr,0 , level); + error =xfs_btree_promote_node_iroot (cur, block, level, cbp, &nptr, + cblock);if (error) goto error0; -xfs_btree_copy_ptrs (cur, pp, &nptr,1 ); - - cur->bc_ops->broot_realloc (cur,1 ); - -xfs_btree_setbuf (cur, level, cbp); - -/* -* Do all this logging at the end so that -* the root is at the right level. -*/ -xfs_btree_log_block (cur, cbp,XFS_BB_ALL_BITS ); -xfs_btree_log_keys (cur, cbp,1 ,be16_to_cpu (cblock->bb_numrecs)); -xfs_btree_log_ptrs (cur, cbp,1 ,be16_to_cpu (cblock->bb_numrecs)); - - *logflags |= -XFS_ILOG_CORE |xfs_ilog_fbroot (cur->bc_ino.whichfork); + *logflags |=XFS_ILOG_CORE |xfs_ilog_fbroot (cur->bc_ino.whichfork); *stat =1 ;return 0 ; error0:
PATCH 7/8 xfs: hoist the node iroot update code out of xfs_btree_kill_iroot
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
In preparation for allowing records in an inode btree root, hoist the code that copies keyptrs from an existing node child into the root block to a separate function. Remove some unnecessary conditionals and clean up a few function calls in the new function. Note that this change reorders the ->free_block call with respect to the change in bc_nlevels to make it easier to support inode root leaf blocks in the next patch.
--- fs/xfs/libxfs/xfs_btree.c | 84 +++++++++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 27 deletions(-)
fs/xfs/libxfs/xfs_btree.c +57 -27
@@ -3726,6 +3726,60 @@ xfs_btree_insert(return error; } +/* +* Move the keyptrs from a child node block to the root block. +* +* Since the keyptr size does not change, all we have to do is increase the +* tree height, copy the keyptrs to the new internal node (cblock), shrink +* the root, and copy the pointers there. +*/ +STATIC int +xfs_btree_demote_node_child ( +struct xfs_btree_cur *cur, +struct xfs_btree_block *cblock, +int level, +int numrecs) +{ +struct xfs_btree_block *block; +union xfs_btree_key *ckp; +union xfs_btree_key *kp; +union xfs_btree_ptr *cpp; +union xfs_btree_ptr *pp; +int i; +int error; + +/* +* Adjust the root btree node size and the record count to match the +* doomed child so that we can copy the keyptrs ahead of changing the +* tree shape. +*/ + block = cur->bc_ops->broot_realloc (cur, numrecs); + +xfs_btree_set_numrecs (block, numrecs); +ASSERT (block->bb_numrecs == cblock->bb_numrecs); + +/* Copy keys from the doomed block. */ + kp =xfs_btree_key_addr (cur,1 , block); + ckp =xfs_btree_key_addr (cur,1 , cblock); +xfs_btree_copy_keys (cur, kp, ckp, numrecs); + +/* Copy pointers from the doomed block. */ + pp =xfs_btree_ptr_addr (cur,1 , block); + cpp =xfs_btree_ptr_addr (cur,1 , cblock); +for (i =0 ; i < numrecs; i++) { + error =xfs_btree_debug_check_ptr (cur, cpp, i, level -1 ); +if (error) +return error; + } +xfs_btree_copy_ptrs (cur, pp, cpp, numrecs); + +/* Decrease tree height, adjusting the root block level to match. */ + cur->bc_levels[level -1 ].bp =NULL ; +be16_add_cpu (&block->bb_level,-1 ); + cur->bc_nlevels--; +return 0 ; +} +/* * Try to merge a non-leaf block back into the inode root. *
@@ -3741,10 +3795,6 @@ xfs_btree_kill_iroot(struct xfs_inode *ip = cur->bc_ino.ip;struct xfs_btree_block *block;struct xfs_btree_block *cblock; -union xfs_btree_key *kp; -union xfs_btree_key *ckp; -union xfs_btree_ptr *pp; -union xfs_btree_ptr *cpp;struct xfs_buf *cbp;int level;int numrecs;
@@ -3752,7 +3802,6 @@ xfs_btree_kill_iroot(#ifdef DEBUG union xfs_btree_ptr ptr;#endif -int i;ASSERT (cur->bc_ops->type ==XFS_BTREE_TYPE_INODE );ASSERT (cur->bc_nlevels >1 );
@@ -3792,35 +3841,16 @@ xfs_btree_kill_iroot(ASSERT (xfs_btree_ptr_is_null (cur, &ptr));#endif - block = cur->bc_ops->broot_realloc (cur, numrecs); - - block->bb_numrecs =be16_to_cpu (numrecs); -ASSERT (block->bb_numrecs == cblock->bb_numrecs); - - kp =xfs_btree_key_addr (cur,1 , block); - ckp =xfs_btree_key_addr (cur,1 , cblock); -xfs_btree_copy_keys (cur, kp, ckp, numrecs); - - pp =xfs_btree_ptr_addr (cur,1 , block); - cpp =xfs_btree_ptr_addr (cur,1 , cblock); - -for (i =0 ; i < numrecs; i++) { - error =xfs_btree_debug_check_ptr (cur, cpp, i, level -1 ); -if (error) -return error; - } - -xfs_btree_copy_ptrs (cur, pp, cpp, numrecs); + error =xfs_btree_demote_node_child (cur, cblock, level, numrecs); +if (error) +return error; error =xfs_btree_free_block (cur, cbp);if (error)return error; - cur->bc_levels[level -1 ].bp =NULL ; -be16_add_cpu (&block->bb_level,-1 );xfs_trans_log_inode (cur->bc_tp, ip,XFS_ILOG_CORE |xfs_ilog_fbroot (cur->bc_ino.whichfork)); - cur->bc_nlevels--; out0:return 0 ; }
PATCH 8/8 xfs: support storing records in the inode core root
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Add the necessary flags and code so that we can support storing leaf records in the inode root block of a btree. This hasn't been necessary before, but the realtime rmapbt will need to be able to do this.
--- fs/xfs/libxfs/xfs_btree.c | 138 ++++++++++++++++++++++++++++++++++--- fs/xfs/libxfs/xfs_btree.h | 2 - fs/xfs/libxfs/xfs_btree_staging.c | 9 ++ 3 files changed, 132 insertions(+), 17 deletions(-)
fs/xfs/libxfs/xfs_btree.c +125 -13
@@ -1537,12 +1537,16 @@ xfs_btree_log_recs( int first, int last) { +if (!bp) { +xfs_trans_log_inode (cur->bc_tp, cur->bc_ino.ip, +xfs_ilog_fbroot (cur->bc_ino.whichfork)); +return ; + }xfs_trans_buf_set_type (cur->bc_tp, bp,XFS_BLFT_BTREE_BUF );xfs_trans_log_buf (cur->bc_tp, bp,xfs_btree_rec_offset (cur, first),xfs_btree_rec_offset (cur, last +1 ) -1 ); - }/*
@@ -3078,6 +3082,59 @@ xfs_btree_split(#define xfs_btree_split __xfs_btree_split#endif /* __KERNEL__ */ +/* Move the records from a root leaf block to a separate block. */ +STATIC void +xfs_btree_promote_leaf_iroot ( +struct xfs_btree_cur *cur, +struct xfs_btree_block *block, +struct xfs_buf *cbp, +union xfs_btree_ptr *cptr, +struct xfs_btree_block *cblock) +{ +union xfs_btree_rec *rp; +union xfs_btree_rec *crp; +union xfs_btree_key *kp; +union xfs_btree_ptr *pp; +struct xfs_btree_block *broot; +int numrecs =xfs_btree_get_numrecs (block); + +/* Copy the records from the leaf broot into the new child block. */ + rp =xfs_btree_rec_addr (cur,1 , block); + crp =xfs_btree_rec_addr (cur,1 , cblock); +xfs_btree_copy_recs (cur, crp, rp, numrecs); + +/* +* Increment the tree height. +* +* Trickery here: The amount of memory that we need per record for the +* ifork's btree root block may change when we convert the broot from a +* leaf to a node block. Free the existing leaf broot so that nobody +* thinks we need to migrate node pointers when we realloc the broot +* buffer after bumping nlevels. +*/ + cur->bc_ops->broot_realloc (cur,0 ); + cur->bc_nlevels++; + cur->bc_levels[1 ].ptr =1 ; + +/* +* Allocate a new node broot and initialize it to point to the new +* child block. +*/ + broot = cur->bc_ops->broot_realloc (cur,1 ); +xfs_btree_init_block (cur->bc_mp, broot, cur->bc_ops, + cur->bc_nlevels -1 ,1 , cur->bc_ino.ip->i_ino); + + pp =xfs_btree_ptr_addr (cur,1 , broot); + kp =xfs_btree_key_addr (cur,1 , broot); +xfs_btree_copy_ptrs (cur, pp, cptr,1 ); +xfs_btree_get_keys (cur, cblock, kp); + +/* Attach the new block to the cursor and log it. */ +xfs_btree_setbuf (cur,0 , cbp); +xfs_btree_log_block (cur, cbp,XFS_BB_ALL_BITS ); +xfs_btree_log_recs (cur, cbp,1 , numrecs); +} +/* * Move the keys and pointers from a root block to a separate block. *
@@ -3163,7 +3220,7 @@ xfs_btree_new_iroot(struct xfs_buf *cbp;/* buffer for cblock */ struct xfs_btree_block *block;/* btree block */ struct xfs_btree_block *cblock;/* child btree block */ -union xfs_btree_ptr *pp; +union xfs_btree_ptr aptr;union xfs_btree_ptr nptr;/* new block addr */ int level;/* btree level */ int error;/* error return code */
@@ -3175,10 +3232,15 @@ xfs_btree_new_iroot( level = cur->bc_nlevels -1 ; block =xfs_btree_get_iroot (cur); - pp =xfs_btree_ptr_addr (cur,1 , block); +ASSERT (level >0 || (cur->bc_ops->geom_flags &XFS_BTGEO_IROOT_RECORDS )); +if (level >0 ) + aptr = *xfs_btree_ptr_addr (cur,1 , block); +else + aptr.l =cpu_to_be64 (XFS_INO_TO_FSB (cur->bc_mp, + cur->bc_ino.ip->i_ino));/* Allocate the new block. If we can't do it, we're toast. Give up. */ - error =xfs_btree_alloc_block (cur, pp, &nptr, stat); + error =xfs_btree_alloc_block (cur, &aptr, &nptr, stat);if (error) goto error0;if (*stat ==0 )
@@ -3204,10 +3266,14 @@ xfs_btree_new_iroot( cblock->bb_u.s.bb_blkno = bno; } - error =xfs_btree_promote_node_iroot (cur, block, level, cbp, &nptr, - cblock); -if (error) - goto error0; +if (level >0 ) { + error =xfs_btree_promote_node_iroot (cur, block, level, cbp, + &nptr, cblock); +if (error) + goto error0; + }else { +xfs_btree_promote_leaf_iroot (cur, block, cbp, &nptr, cblock); + } *logflags |=XFS_ILOG_CORE |xfs_ilog_fbroot (cur->bc_ino.whichfork); *stat =1 ;
@@ -3726,6 +3792,43 @@ xfs_btree_insert(return error; } +/* Move the records from a child leaf block to the root block. */ +STATIC void +xfs_btree_demote_leaf_child ( +struct xfs_btree_cur *cur, +struct xfs_btree_block *cblock, +int numrecs) +{ +union xfs_btree_rec *rp; +union xfs_btree_rec *crp; +struct xfs_btree_block *broot; + +/* +* Decrease the tree height. +* +* Trickery here: The amount of memory that we need per record for the +* ifork's btree root block may change when we convert the broot from a +* node to a leaf. Free the old node broot so that we can get a fresh +* leaf broot. +*/ + cur->bc_ops->broot_realloc (cur,0 ); + cur->bc_nlevels--; + +/* +* Allocate a new leaf broot and copy the records from the old child. +* Detach the old child from the cursor. +*/ + broot = cur->bc_ops->broot_realloc (cur, numrecs); +xfs_btree_init_block (cur->bc_mp, broot, cur->bc_ops,0 , numrecs, + cur->bc_ino.ip->i_ino); + + rp =xfs_btree_rec_addr (cur,1 , broot); + crp =xfs_btree_rec_addr (cur,1 , cblock); +xfs_btree_copy_recs (cur, rp, crp, numrecs); + + cur->bc_levels[0 ].bp =NULL ; +} +/* * Move the keyptrs from a child node block to the root block. *
@@ -3804,14 +3907,19 @@ xfs_btree_kill_iroot(#endif ASSERT (cur->bc_ops->type ==XFS_BTREE_TYPE_INODE ); -ASSERT (cur->bc_nlevels >1 ); +ASSERT ((cur->bc_ops->geom_flags &XFS_BTGEO_IROOT_RECORDS ) || + cur->bc_nlevels >1 );/* * Don't deal with the root block needs to be a leaf case. * We're just going to turn the thing back into extents anyway. */ level = cur->bc_nlevels -1 ; -if (level ==1 ) +if (level ==1 && !(cur->bc_ops->geom_flags &XFS_BTGEO_IROOT_RECORDS )) + goto out0; + +/* If we're already a leaf, jump out. */ +if (level ==0 ) goto out0;/*
@@ -3841,9 +3949,13 @@ xfs_btree_kill_iroot(ASSERT (xfs_btree_ptr_is_null (cur, &ptr));#endif - error =xfs_btree_demote_node_child (cur, cblock, level, numrecs); -if (error) -return error; +if (level >1 ) { + error =xfs_btree_demote_node_child (cur, cblock, level, + numrecs); +if (error) +return error; + }else +xfs_btree_demote_leaf_child (cur, cblock, numrecs); error =xfs_btree_free_block (cur, cbp);if (error)
fs/xfs/libxfs/xfs_btree.h +1 -1
@@ -233,7 +233,7 @@ struct xfs_btree_ops {/* btree geometry flags */ #define XFS_BTGEO_OVERLAPPING (1U << 0)/* overlapping intervals */ - +#define XFS_BTGEO_IROOT_RECORDS (1U << 1)/* iroot can store records */ union xfs_btree_irec {struct xfs_alloc_rec_incore a;
fs/xfs/libxfs/xfs_btree_staging.c +6 -3
@@ -573,6 +573,7 @@ xfs_btree_bload_compute_geometry( struct xfs_btree_bload *bbl, uint64_t nr_records) { +const struct xfs_btree_ops *ops = cur->bc_ops;uint64_t nr_blocks =0 ;uint64_t nr_this_level;
@@ -599,7 +600,7 @@ xfs_btree_bload_compute_geometry(xfs_btree_bload_level_geometry (cur, bbl, level, nr_this_level, &avg_per_block, &level_blocks, &dontcare64); -if (cur->bc_ops->type ==XFS_BTREE_TYPE_INODE ) { +if (ops->type ==XFS_BTREE_TYPE_INODE ) {/* * If all the items we want to store at this level * would fit in the inode root block, then we have our
@@ -607,7 +608,9 @@ xfs_btree_bload_compute_geometry(* * Note that bmap btrees forbid records in the root. */ -if (level !=0 && nr_this_level <= avg_per_block) { +if ((level !=0 || + (ops->geom_flags &XFS_BTGEO_IROOT_RECORDS )) && + nr_this_level <= avg_per_block) { nr_blocks++;break ; }
@@ -658,7 +661,7 @@ xfs_btree_bload_compute_geometry(return -EOVERFLOW ; bbl->btree_height = cur->bc_nlevels; -if (cur->bc_ops->type ==XFS_BTREE_TYPE_INODE ) +if (ops->type ==XFS_BTREE_TYPE_INODE ) bbl->nr_blocks = nr_blocks -1 ;else bbl->nr_blocks = nr_blocks;
PATCH 3/5 xfs: enable in-core block reservation for rt metadata
In reply to Darrick J. WongHi all,
In preparation for adding reverse mapping and refcounting to the realtime device, enhance the metadir code to reserve free space for btree shape changes as delayed allocation blocks.
This enables us to pre-allocate space for the rmap and refcount btrees in the same manner as we do for the data device counterparts, which is how we avoid ENOSPC failures when space is low but we've already committed to a COW operation.
If you're going to start using this code, I strongly recommend pulling from my git trees, which are linked below.
This has been running on the djcloud for months with no problems. Enjoy! Comments and questions are, as always, welcome.
--D
kernel git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-linux.git/log/?h=reserve-rt-metadata-space
xfsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=reserve-rt-metadata-space
---
Commits in this patchset:
* xfs: prepare to reuse the dquot pointer space in struct xfs_inode
* xfs: allow inode-based btrees to reserve space in the data device
--- fs/xfs/libxfs/xfs_ag_resv.c | 3 + fs/xfs/libxfs/xfs_attr.c | 4 - fs/xfs/libxfs/xfs_bmap.c | 4 - fs/xfs/libxfs/xfs_errortag.h | 4 + fs/xfs/libxfs/xfs_metadir.c | 4 + fs/xfs/libxfs/xfs_metafile.c | 205 ++++++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_metafile.h | 11 ++ fs/xfs/libxfs/xfs_types.h | 7 + fs/xfs/scrub/tempfile.c | 1 fs/xfs/xfs_dquot.h | 3 + fs/xfs/xfs_error.c | 3 + fs/xfs/xfs_exchrange.c | 3 + fs/xfs/xfs_fsops.c | 17 +++ fs/xfs/xfs_inode.h | 16 +++ fs/xfs/xfs_mount.c | 10 ++ fs/xfs/xfs_mount.h | 1 fs/xfs/xfs_qm.c | 2 fs/xfs/xfs_quota.h | 5 - fs/xfs/xfs_rtalloc.c | 21 ++++ fs/xfs/xfs_rtalloc.h | 5 + fs/xfs/xfs_trace.h | 45 +++++++++ fs/xfs/xfs_trans.c | 4 + fs/xfs/xfs_trans_dquot.c | 8 +- 23 files changed, 367 insertions(+), 19 deletions(-)
PATCH 1/2 xfs: prepare to reuse the dquot pointer space in struct xfs_inode
From: Darrick J. Wong <[email protected]>
Files participating in the metadata directory tree are not accounted to the quota subsystem. Therefore, the i_[ugp]dquot pointers in struct xfs_inode are never used and should always be NULL.
In the next patch we want to add a u64 count of fs blocks reserved for metadata btree expansion, but we don't want every inode in the fs to pay the memory price for this feature. The intent is to union those three pointers with the u64 counter, but for that to work we must guard against all access to the dquot pointers for metadata files.
--- fs/xfs/libxfs/xfs_attr.c | 4 +--- fs/xfs/libxfs/xfs_bmap.c | 4 +--- fs/xfs/scrub/tempfile.c | 1 + fs/xfs/xfs_dquot.h | 3 +++ fs/xfs/xfs_exchrange.c | 3 +++ fs/xfs/xfs_inode.h | 10 +++++++--- fs/xfs/xfs_qm.c | 2 ++ fs/xfs/xfs_quota.h | 5 ----- fs/xfs/xfs_trans.c | 4 ++++ fs/xfs/xfs_trans_dquot.c | 8 ++++---- 10 files changed, 26 insertions(+), 18 deletions(-)
fs/xfs/libxfs/xfs_attr.c +1 -3
@@ -1004,9 +1004,7 @@ xfs_attr_add_fork(unsigned int blks;/* space reservation */ int error;/* error return value */ -if (xfs_is_metadir_inode (ip)) -ASSERT (XFS_IS_DQDETACHED (ip)); -else +if (!xfs_is_metadir_inode (ip))ASSERT (!XFS_NOT_DQATTACHED (mp, ip)); blks =XFS_ADDAFORK_SPACE_RES (mp);
fs/xfs/libxfs/xfs_bmap.c +1 -3
@@ -1042,9 +1042,7 @@ xfs_bmap_add_attrfork(int error;/* error return value */ xfs_assert_ilocked (ip,XFS_ILOCK_EXCL ); -if (xfs_is_metadir_inode (ip)) -ASSERT (XFS_IS_DQDETACHED (ip)); -else +if (!xfs_is_metadir_inode (ip))ASSERT (!XFS_NOT_DQATTACHED (mp, ip));ASSERT (!xfs_inode_has_attr_fork (ip));
fs/xfs/scrub/tempfile.c +1 -0
@@ -749,6 +749,7 @@ xrep_tempexch_reserve_quota(* or the two inodes have the same dquots. */ if (!XFS_IS_QUOTA_ON (tp->t_mountp) || req->ip1 == req->ip2 || +xfs_is_metadir_inode (req->ip1) || (req->ip1->i_udquot == req->ip2->i_udquot && req->ip1->i_gdquot == req->ip2->i_gdquot && req->ip1->i_pdquot == req->ip2->i_pdquot))
fs/xfs/xfs_dquot.h +3 -0
@@ -160,6 +160,9 @@ static inline struct xfs_dquot *xfs_inode_dquot( struct xfs_inode *ip, xfs_dqtype_t type) { + if (xfs_is_metadir_inode(ip)) + return NULL; +switch (type) {case XFS_DQTYPE_USER :return ip->i_udquot;
fs/xfs/xfs_exchrange.c +3 -0
@@ -119,6 +119,9 @@ xfs_exchrange_reserve_quota(int ip1_error =0 ;int error; +ASSERT (!xfs_is_metadir_inode (req->ip1)); +ASSERT (!xfs_is_metadir_inode (req->ip2)); +/* * Don't bother with a quota reservation if we're not enforcing them * or the two inodes have the same dquots.
fs/xfs/xfs_inode.h +7 -3
@@ -25,9 +25,13 @@ struct xfs_dquot; typedef struct xfs_inode { /* Inode linking and identification information. */ struct xfs_mount *i_mount; /* fs mount struct ptr */ - struct xfs_dquot *i_udquot; /* user dquot */ - struct xfs_dquot *i_gdquot; /* group dquot */ - struct xfs_dquot *i_pdquot; /* project dquot */ + union { + struct { + struct xfs_dquot *i_udquot; /* user dquot */ + struct xfs_dquot *i_gdquot; /* group dquot */ + struct xfs_dquot *i_pdquot; /* project dquot */ + }; + }; /* Inode location stuff */ xfs_ino_t i_ino; /* inode number (agno/agino)*/
fs/xfs/xfs_qm.c +2 -0
@@ -428,6 +428,8 @@ voidxfs_qm_dqdetach ( xfs_inode_t *ip) { +if (xfs_is_metadir_inode (ip)) +return ;if (!(ip->i_udquot || ip->i_gdquot || ip->i_pdquot))return ;
fs/xfs/xfs_quota.h +0 -5
@@ -29,11 +29,6 @@ struct xfs_buf; (XFS_IS_GQUOTA_ON(mp) && (ip)->i_gdquot == NULL) || \ (XFS_IS_PQUOTA_ON(mp) && (ip)->i_pdquot == NULL)) -#define XFS_IS_DQDETACHED (ip) \ - ((ip)->i_udquot == NULL && \ - (ip)->i_gdquot == NULL && \ - (ip)->i_pdquot == NULL) -#define XFS_QM_NEED_QUOTACHECK (mp) \ ((XFS_IS_UQUOTA_ON(mp) && \ (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD) == 0) || \
fs/xfs/xfs_trans.c +4 -0
@@ -1266,6 +1266,9 @@ xfs_trans_alloc_ichange(xfs_ilock (ip,XFS_ILOCK_EXCL );xfs_trans_ijoin (tp, ip,XFS_ILOCK_EXCL ); +if (xfs_is_metadir_inode (ip)) + goto out; + error =xfs_qm_dqattach_locked (ip, false);if (error) {/* Caller should have allocated the dquots! */
@@ -1334,6 +1337,7 @@ xfs_trans_alloc_ichange( goto out_cancel; } +out: *tpp = tp;return 0 ;
fs/xfs/xfs_trans_dquot.c +4 -4
@@ -156,7 +156,8 @@ xfs_trans_mod_ino_dquot(unsigned int field, int64_t delta) { -ASSERT (!xfs_is_metadir_inode (ip) ||XFS_IS_DQDETACHED (ip)); + if (xfs_is_metadir_inode(ip)) + return;xfs_trans_mod_dquot (tp ,dqp ,field ,delta );
@@ -246,11 +247,10 @@ xfs_trans_mod_dquot_byino(xfs_mount_t *mp = tp->t_mountp;if (!XFS_IS_QUOTA_ON (mp) || -xfs_is_quota_inode (&mp->m_sb, ip->i_ino)) +xfs_is_quota_inode (&mp->m_sb, ip->i_ino) || +xfs_is_metadir_inode (ip))return ; -ASSERT (!xfs_is_metadir_inode (ip) ||XFS_IS_DQDETACHED (ip)); -if (XFS_IS_UQUOTA_ON (mp) && ip->i_udquot)xfs_trans_mod_ino_dquot (tp, ip, ip->i_udquot, field, delta);if (XFS_IS_GQUOTA_ON (mp) && ip->i_gdquot)
PATCH 2/2 xfs: allow inode-based btrees to reserve space in the data device
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Create a new space reservation scheme so that btree metadata for the realtime volume can reserve space in the data device to avoid space underruns.
Back when we were testing the rmap and refcount btrees for the data device, people observed occasional shutdowns when xfs_btree_split was called for either of those two btrees. This happened when certain operations (mostly writeback ioends) created new rmap or refcount records, which would expand the size of the btree. If there were no free blocks available the allocation would fail and the split would shut down the filesystem.
I considered pre-reserving blocks for btree expansion at the time of a write() call, but there wasn't any good way to attach the reservations to an inode and keep them there all the way to ioend processing. Unlike delalloc reservations which have that indlen mechanism, there's no way to do that for mapped extents; and indlen blocks are given back during the delalloc -> unwritten transition.
The solution was to reserve sufficient blocks for rmap/refcount btree expansion at mount time. This is what the XFS_AG_RESV_* flags provide; any expansion of those two btrees can come from the pre-reserved space.
This patch brings that pre-reservation ability to inode-rooted btrees so that the rt rmap and refcount btrees can also save room for future expansion.
--- fs/xfs/libxfs/xfs_ag_resv.c | 3 + fs/xfs/libxfs/xfs_errortag.h | 4 + fs/xfs/libxfs/xfs_metadir.c | 4 + fs/xfs/libxfs/xfs_metafile.c | 205 ++++++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_metafile.h | 11 ++ fs/xfs/libxfs/xfs_types.h | 7 + fs/xfs/xfs_error.c | 3 + fs/xfs/xfs_fsops.c | 17 +++ fs/xfs/xfs_inode.h | 6 + fs/xfs/xfs_mount.c | 10 ++ fs/xfs/xfs_mount.h | 1 fs/xfs/xfs_rtalloc.c | 21 ++++ fs/xfs/xfs_rtalloc.h | 5 + fs/xfs/xfs_trace.h | 45 +++++++++ 14 files changed, 341 insertions(+), 1 deletion(-)
fs/xfs/libxfs/xfs_ag_resv.c +3 -0
@@ -114,6 +114,7 @@ xfs_ag_resv_needed(case XFS_AG_RESV_RMAPBT : len -=xfs_perag_resv (pag, type)->ar_reserved;break ; +case XFS_AG_RESV_METAFILE :case XFS_AG_RESV_NONE :/* empty */ break ;
@@ -347,6 +348,7 @@ xfs_ag_resv_alloc_extent(switch (type) {case XFS_AG_RESV_AGFL : +case XFS_AG_RESV_METAFILE :return ;case XFS_AG_RESV_METADATA :case XFS_AG_RESV_RMAPBT :
@@ -389,6 +391,7 @@ xfs_ag_resv_free_extent(switch (type) {case XFS_AG_RESV_AGFL : +case XFS_AG_RESV_METAFILE :return ;case XFS_AG_RESV_METADATA :case XFS_AG_RESV_RMAPBT :
fs/xfs/libxfs/xfs_errortag.h +3 -1
@@ -64,7 +64,8 @@#define XFS_ERRTAG_WB_DELAY_MS 42#define XFS_ERRTAG_WRITE_DELAY_MS 43#define XFS_ERRTAG_EXCHMAPS_FINISH_ONE 44 -#define XFS_ERRTAG_MAX 45 +#define XFS_ERRTAG_METAFILE_RESV_CRITICAL 45 +#define XFS_ERRTAG_MAX 46/* * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -113,5 +114,6 @@#define XFS_RANDOM_WB_DELAY_MS 3000#define XFS_RANDOM_WRITE_DELAY_MS 3000#define XFS_RANDOM_EXCHMAPS_FINISH_ONE 1 +#define XFS_RANDOM_METAFILE_RESV_CRITICAL 4#endif /* __XFS_ERRORTAG_H_ */
fs/xfs/libxfs/xfs_metadir.c +4 -0
@@ -29,6 +29,10 @@#include "xfs_dir2_priv.h" #include "xfs_parent.h" #include "xfs_health.h" +#include "xfs_errortag.h" +#include "xfs_error.h" +#include "xfs_btree.h" +#include "xfs_alloc.h" /* * Metadata Directory Tree
fs/xfs/libxfs/xfs_metafile.c +205 -0
214 lines not on this page · raw message
fs/xfs/libxfs/xfs_metafile.h +11 -0
@@ -21,6 +21,17 @@ void xfs_metafile_set_iflag(struct xfs_trans *tp, struct xfs_inode *ip, enum xfs_metafile_type metafile_type);void xfs_metafile_clear_iflag (struct xfs_trans *tp,struct xfs_inode *ip); +/* Space reservations for metadata inodes. */ +struct xfs_alloc_arg ; + +bool xfs_metafile_resv_critical (struct xfs_inode *ip); +void xfs_metafile_resv_alloc_space (struct xfs_inode *ip, +struct xfs_alloc_arg *args); +void xfs_metafile_resv_free_space (struct xfs_inode *ip,struct xfs_trans *tp, +xfs_filblks_t len); +void xfs_metafile_resv_free (struct xfs_inode *ip); +int xfs_metafile_resv_init (struct xfs_inode *ip,xfs_filblks_t ask); +/* Code specific to kernel/userspace; must be provided externally. */ int xfs_trans_metafile_iget(struct xfs_trans *tp, xfs_ino_t ino,
fs/xfs/libxfs/xfs_types.h +7 -0
@@ -202,6 +202,13 @@ enum xfs_ag_resv_type {* altering fdblocks. If you think you need this you're wrong. */ XFS_AG_RESV_IGNORE , + +/* +* This allocation activity is being done on behalf of a metadata file. +* These files maintain their own permanent space reservations and are +* required to adjust fdblocks using the xfs_metafile_resv_* helpers. +*/ + XFS_AG_RESV_METAFILE, };/* Results of scanning a btree keyspace to check occupancy. */
fs/xfs/xfs_error.c +3 -0
@@ -63,6 +63,7 @@ static unsigned int xfs_errortag_random_default[] = {XFS_RANDOM_WB_DELAY_MS ,XFS_RANDOM_WRITE_DELAY_MS ,XFS_RANDOM_EXCHMAPS_FINISH_ONE , + XFS_RANDOM_METAFILE_RESV_CRITICAL, }; struct xfs_errortag_attr {
@@ -181,6 +182,7 @@ XFS_ERRORTAG_ATTR_RW(attr_leaf_to_node, XFS_ERRTAG_ATTR_LEAF_TO_NODE);XFS_ERRORTAG_ATTR_RW (wb_delay_ms,XFS_ERRTAG_WB_DELAY_MS );XFS_ERRORTAG_ATTR_RW (write_delay_ms,XFS_ERRTAG_WRITE_DELAY_MS );XFS_ERRORTAG_ATTR_RW (exchmaps_finish_one,XFS_ERRTAG_EXCHMAPS_FINISH_ONE ); +XFS_ERRORTAG_ATTR_RW (metafile_resv_crit,XFS_ERRTAG_METAFILE_RESV_CRITICAL );static struct attribute *xfs_errortag_attrs[] = {XFS_ERRORTAG_ATTR_LIST (noerror),
@@ -227,6 +229,7 @@ static struct attribute *xfs_errortag_attrs[] = {XFS_ERRORTAG_ATTR_LIST (wb_delay_ms),XFS_ERRORTAG_ATTR_LIST (write_delay_ms),XFS_ERRORTAG_ATTR_LIST (exchmaps_finish_one), +XFS_ERRORTAG_ATTR_LIST (metafile_resv_crit),NULL , };ATTRIBUTE_GROUPS (xfs_errortag);
fs/xfs/xfs_fsops.c +17 -0
@@ -21,6 +21,7 @@#include "xfs_ag.h" #include "xfs_ag_resv.h" #include "xfs_trace.h" +#include "xfs_rtalloc.h" /* * Write new AG headers to disk. Non-transactional, but need to be
@@ -541,6 +542,19 @@ xfs_fs_reserve_ag_blocks(xfs_warn (mp,"Error %d reserving per-AG metadata reserve pool." , error);xfs_force_shutdown (mp,SHUTDOWN_CORRUPT_INCORE ); +return error; + } + +if (xfs_has_realtime (mp)) { + err2 =xfs_rt_resv_init (mp); +if (err2 && err2 != -ENOSPC ) { +xfs_warn (mp, +"Error %d reserving realtime metadata reserve pool." , err2); +xfs_force_shutdown (mp,SHUTDOWN_CORRUPT_INCORE ); + } + +if (err2 && !error) + error = err2; }return error;
@@ -555,6 +569,9 @@ xfs_fs_unreserve_ag_blocks( {struct xfs_perag *pag =NULL ; +if (xfs_has_realtime (mp)) +xfs_rt_resv_free (mp); +while ((pag =xfs_perag_next (mp, pag)))xfs_ag_resv_free (pag); }
fs/xfs/xfs_inode.h +6 -0
@@ -31,6 +31,12 @@ typedef struct xfs_inode {struct xfs_dquot *i_gdquot;/* group dquot */ struct xfs_dquot *i_pdquot;/* project dquot */ }; + +/* +* Space that has been set aside to accomodate expansions of a +* metadata btree rooted in this file. +*/ +uint64_t i_meta_resv_asked; };/* Inode location stuff */
fs/xfs/xfs_mount.c +10 -0
@@ -650,6 +650,15 @@ xfs_agbtree_compute_maxlevels( mp->m_agbtree_maxlevels =max (levels, mp->m_refc_maxlevels); } +/* Compute maximum possible height for realtime btree types for this fs. */ +static inline void +xfs_rtbtree_compute_maxlevels ( +struct xfs_mount *mp) +{ +/* This will be filled in later. */ + mp->m_rtbtree_maxlevels =0 ; +} +/* * This function does the following on an initial mount of a file system: * - reads the superblock from disk and init the mount struct
@@ -721,6 +730,7 @@ xfs_mountfs(xfs_refcountbt_compute_maxlevels (mp);xfs_agbtree_compute_maxlevels (mp); +xfs_rtbtree_compute_maxlevels (mp);/* * Check if sb_agblocks is aligned at stripe boundary. If sb_agblocks
fs/xfs/xfs_mount.h +1 -0
@@ -165,6 +165,7 @@ typedef struct xfs_mount {uint m_rmap_maxlevels;/* max rmap btree levels */ uint m_refc_maxlevels;/* max refcount btree level */ unsigned int m_agbtree_maxlevels;/* max level of all AG btrees */ +unsigned int m_rtbtree_maxlevels;/* max level of all rt btrees */ xfs_extlen_t m_ag_prealloc_blocks;/* reserved ag blocks */ uint m_alloc_set_aside;/* space we can't use */ uint m_ag_max_usable;/* max space per AG */
fs/xfs/xfs_rtalloc.c +21 -0
@@ -1344,6 +1344,12 @@ xfs_growfs_rt(if (!error) error = error2; + +/* Reset the rt metadata btree space reservations. */ +xfs_rt_resv_free (mp); + error2 =xfs_rt_resv_init (mp); +if (error2 && error2 != -ENOSPC ) + error = error2; } out_unlock:
@@ -1487,6 +1493,21 @@ xfs_rtalloc_reinit_frextents(return 0 ; } +/* Free space reservations for rt metadata inodes. */ +void +xfs_rt_resv_free ( +struct xfs_mount *mp) +{ +} + +/* Reserve space for rt metadata inodes' space expansion. */ +int +xfs_rt_resv_init ( +struct xfs_mount *mp) +{ +return 0 ; +} +/* * Read in the bmbt of an rt metadata inode so that we never have to load them * at runtime. This enables the use of shared ILOCKs for rtbitmap scans. Use
fs/xfs/xfs_rtalloc.h +5 -0
@@ -34,6 +34,9 @@ int /* error */xfs_rtmount_inodes ( struct xfs_mount *mp); /* file system mount structure */ +void xfs_rt_resv_free (struct xfs_mount *mp); +int xfs_rt_resv_init (struct xfs_mount *mp); +/* * Grow the realtime area of the filesystem. */
@@ -60,6 +63,8 @@ xfs_rtmount_init( }# define xfs_rtmount_inodes (m) (((mp)->m_sb.sb_rblocks == 0)? 0 : (-ENOSYS))# define xfs_rtunmount_inodes (m) +# define xfs_rt_resv_free (mp) ((void)0) +# define xfs_rt_resv_init (mp) (0)#endif /* CONFIG_XFS_RT */ #endif /* __XFS_RTALLOC_H__ */
fs/xfs/xfs_trace.h +45 -0
51 lines not on this page · raw message
PATCH 4/5 xfs: realtime reverse-mapping support
In reply to Darrick J. WongHi all,
This is the latest revision of a patchset that adds to XFS kernel support for reverse mapping for the realtime device. This time around I've fixed some of the bitrot that I've noticed over the past few months, and most notably have converted rtrmapbt to use the metadata inode directory feature instead of burning more space in the superblock.
At the beginning of the set are patches to implement storing B+tree leaves in an inode root, since the realtime rmapbt is rooted in an inode, unlike the regular rmapbt which is rooted in an AG block. Prior to this, the only btree that could be rooted in the inode fork was the block mapping btree; if all the extent records fit in the inode, format would be switched from 'btree' to 'extents'.
The next few patches enhance the reverse mapping routines to handle the parts that are specific to rtgroups -- adding the new btree type, adding a new log intent item type, and wiring up the metadata directory tree entries.
Finally, implement GETFSMAP with the rtrmapbt and scrub functionality for the rtrmapbt and rtbitmap and online fsck functionality.
If you're going to start using this code, I strongly recommend pulling from my git trees, which are linked below.
This has been running on the djcloud for months with no problems. Enjoy! Comments and questions are, as always, welcome.
--D
kernel git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-linux.git/log/?h=realtime-rmap
xfsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=realtime-rmap
fstests git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=realtime-rmap
xfsdocs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-documentation.git/log/?h=realtime-rmap
---
Commits in this patchset:
* xfs: add some rtgroup inode helpers
* xfs: prepare rmap btree cursor tracepoints for realtime
* xfs: simplify the xfs_rmap_{alloc,free}_extent calling conventions
* xfs: introduce realtime rmap btree ondisk definitions
* xfs: realtime rmap btree transaction reservations
* xfs: add realtime rmap btree operations
* xfs: prepare rmap functions to deal with rtrmapbt
* xfs: add a realtime flag to the rmap update log redo items
* xfs: support recovering rmap intent items targetting realtime extents
* xfs: pretty print metadata file types in error messages
* xfs: support file data forks containing metadata btrees
* xfs: add realtime reverse map inode to metadata directory
* xfs: add metadata reservations for realtime rmap btrees
* xfs: wire up a new metafile type for the realtime rmap
* xfs: wire up rmap map and unmap to the realtime rmapbt
* xfs: create routine to allocate and initialize a realtime rmap btree inode
* xfs: wire up getfsmap to the realtime reverse mapping btree
* xfs: check that the rtrmapbt maxlevels doesn't increase when growing fs
* xfs: report realtime rmap btree corruption errors to the health system
* xfs: allow queued realtime intents to drain before scrubbing
* xfs: scrub the realtime rmapbt
* xfs: cross-reference realtime bitmap to realtime rmapbt scrubber
* xfs: cross-reference the realtime rmapbt
* xfs: scan rt rmap when we're doing an intense rmap check of bmbt mappings
* xfs: scrub the metadir path of rt rmap btree files
* xfs: walk the rt reverse mapping tree when rebuilding rmap
* xfs: online repair of realtime file bmaps
* xfs: repair inodes that have realtime extents
* xfs: repair rmap btree inodes
* xfs: online repair of realtime bitmaps for a realtime group
* xfs: support repairing metadata btrees rooted in metadir inodes
* xfs: online repair of the realtime rmap btree
* xfs: create a shadow rmap btree during realtime rmap repair
* xfs: hook live realtime rmap operations during a repair operation
* xfs: don't shut down the filesystem for media failures beyond end of log
* xfs: react to fsdax failure notifications on the rt device
* xfs: enable realtime rmap btree
--- fs/xfs/Makefile | 3 fs/xfs/libxfs/xfs_btree.c | 73 +++ fs/xfs/libxfs/xfs_btree.h | 8 fs/xfs/libxfs/xfs_btree_mem.c | 1 fs/xfs/libxfs/xfs_btree_staging.c | 1 fs/xfs/libxfs/xfs_defer.h | 1 fs/xfs/libxfs/xfs_exchmaps.c | 4 fs/xfs/libxfs/xfs_format.h | 28 + fs/xfs/libxfs/xfs_fs.h | 7 fs/xfs/libxfs/xfs_health.h | 4 fs/xfs/libxfs/xfs_inode_buf.c | 32 + fs/xfs/libxfs/xfs_inode_fork.c | 25 + fs/xfs/libxfs/xfs_log_format.h | 6 fs/xfs/libxfs/xfs_log_recover.h | 2 fs/xfs/libxfs/xfs_metafile.c | 18 + fs/xfs/libxfs/xfs_metafile.h | 2 fs/xfs/libxfs/xfs_ondisk.h | 2 fs/xfs/libxfs/xfs_refcount.c | 6 fs/xfs/libxfs/xfs_rmap.c | 171 +++++- fs/xfs/libxfs/xfs_rmap.h | 12 fs/xfs/libxfs/xfs_rtbitmap.c | 2 fs/xfs/libxfs/xfs_rtbitmap.h | 9 fs/xfs/libxfs/xfs_rtgroup.c | 53 +- fs/xfs/libxfs/xfs_rtgroup.h | 49 ++ fs/xfs/libxfs/xfs_rtrmap_btree.c | 1011 +++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_rtrmap_btree.h | 210 ++++++++ fs/xfs/libxfs/xfs_sb.c | 6 fs/xfs/libxfs/xfs_shared.h | 14 + fs/xfs/libxfs/xfs_trans_resv.c | 12 fs/xfs/libxfs/xfs_trans_space.h | 13 fs/xfs/scrub/alloc_repair.c | 5 fs/xfs/scrub/bmap.c | 108 +++- fs/xfs/scrub/bmap_repair.c | 129 +++++ fs/xfs/scrub/common.c | 160 ++++++ fs/xfs/scrub/common.h | 23 + fs/xfs/scrub/health.c | 1 fs/xfs/scrub/inode.c | 10 fs/xfs/scrub/inode_repair.c | 136 +++++ fs/xfs/scrub/metapath.c | 3 fs/xfs/scrub/newbt.c | 42 ++ fs/xfs/scrub/newbt.h | 1 fs/xfs/scrub/reap.c | 41 ++ fs/xfs/scrub/reap.h | 2 fs/xfs/scrub/repair.c | 191 +++++++ fs/xfs/scrub/repair.h | 17 + fs/xfs/scrub/rgsuper.c | 6 fs/xfs/scrub/rmap_repair.c | 84 +++ fs/xfs/scrub/rtbitmap.c | 75 ++- fs/xfs/scrub/rtbitmap.h | 55 ++ fs/xfs/scrub/rtbitmap_repair.c | 429 +++++++++++++++- fs/xfs/scrub/rtrmap.c | 271 ++++++++++ fs/xfs/scrub/rtrmap_repair.c | 903 +++++++++++++++++++++++++++++++++ fs/xfs/scrub/rtsummary.c | 17 - fs/xfs/scrub/rtsummary_repair.c | 3 fs/xfs/scrub/scrub.c | 11 fs/xfs/scrub/scrub.h | 14 + fs/xfs/scrub/stats.c | 1 fs/xfs/scrub/tempexch.h | 2 fs/xfs/scrub/tempfile.c | 20 - fs/xfs/scrub/trace.c | 1 fs/xfs/scrub/trace.h | 228 ++++++++ fs/xfs/xfs_buf.c | 1 fs/xfs/xfs_buf_item_recover.c | 4 fs/xfs/xfs_drain.c | 20 - fs/xfs/xfs_drain.h | 7 fs/xfs/xfs_fsmap.c | 174 ++++++ fs/xfs/xfs_fsops.c | 11 fs/xfs/xfs_health.c | 1 fs/xfs/xfs_inode.c | 19 + fs/xfs/xfs_inode_item.c | 2 fs/xfs/xfs_inode_item_recover.c | 44 +- fs/xfs/xfs_log_recover.c | 2 fs/xfs/xfs_mount.c | 5 fs/xfs/xfs_mount.h | 9 fs/xfs/xfs_notify_failure.c | 230 +++++--- fs/xfs/xfs_notify_failure.h | 11 fs/xfs/xfs_qm.c | 8 fs/xfs/xfs_rmap_item.c | 216 +++++++- fs/xfs/xfs_rtalloc.c | 82 ++- fs/xfs/xfs_rtalloc.h | 10 fs/xfs/xfs_stats.c | 4 fs/xfs/xfs_stats.h | 2 fs/xfs/xfs_super.c | 6 fs/xfs/xfs_super.h | 1 fs/xfs/xfs_trace.h | 104 ++-- 85 files changed, 5381 insertions(+), 366 deletions(-) create mode 100644 fs/xfs/libxfs/xfs_rtrmap_btree.c create mode 100644 fs/xfs/libxfs/xfs_rtrmap_btree.h create mode 100644 fs/xfs/scrub/rtrmap.c create mode 100644 fs/xfs/scrub/rtrmap_repair.c create mode 100644 fs/xfs/xfs_notify_failure.h
PATCH 1/37 xfs: add some rtgroup inode helpers
From: Darrick J. Wong <[email protected]>
Create some simple helpers to reduce the amount of typing whenever we access rtgroup inodes. Conversion was done with this spatch and some minor reformatting:
@@
expression rtg;
@@
- rtg->rtg_inodes[XFS_RTGI_BITMAP]
+ rtg_bitmap(rtg)
@@
expression rtg;
@@
- rtg->rtg_inodes[XFS_RTGI_SUMMARY]
+ rtg_summary(rtg)
and the CLI command:
$ spatch --sp-file /tmp/moo.cocci --dir fs/xfs/ --use-gitgrep --in-place
--- fs/xfs/libxfs/xfs_rtbitmap.c | 2 +- fs/xfs/libxfs/xfs_rtgroup.c | 18 ++++++++---------- fs/xfs/libxfs/xfs_rtgroup.h | 10 ++++++++++ fs/xfs/scrub/rtbitmap.c | 7 +++---- fs/xfs/scrub/rtsummary.c | 12 +++++------- fs/xfs/xfs_qm.c | 8 ++++---- fs/xfs/xfs_rtalloc.c | 10 +++++----- 7 files changed, 36 insertions(+), 31 deletions(-)
fs/xfs/libxfs/xfs_rtbitmap.c +1 -1
@@ -1055,7 +1055,7 @@ xfs_rtfree_extent( xfs_rtxlen_t len) /* length of extent freed */ {struct xfs_mount *mp = tp->t_mountp; -struct xfs_inode *rbmip = rtg->rtg_inodes[XFS_RTGI_BITMAP ]; +struct xfs_inode *rbmip =rtg_bitmap (rtg);struct xfs_rtalloc_args args = { .mp = mp, .tp = tp,
fs/xfs/libxfs/xfs_rtgroup.c +8 -10
@@ -197,10 +197,10 @@ xfs_rtgroup_lock(* Lock both realtime free space metadata inodes for a freespace * update. */ -xfs_ilock (rtg->rtg_inodes[XFS_RTGI_BITMAP ],XFS_ILOCK_EXCL ); -xfs_ilock (rtg->rtg_inodes[XFS_RTGI_SUMMARY ],XFS_ILOCK_EXCL ); +xfs_ilock (rtg_bitmap (rtg),XFS_ILOCK_EXCL ); +xfs_ilock (rtg_summary (rtg),XFS_ILOCK_EXCL ); }else if (rtglock_flags &XFS_RTGLOCK_BITMAP_SHARED ) { -xfs_ilock (rtg->rtg_inodes[XFS_RTGI_BITMAP ],XFS_ILOCK_SHARED ); +xfs_ilock (rtg_bitmap (rtg),XFS_ILOCK_SHARED ); } }
@@ -215,10 +215,10 @@ xfs_rtgroup_unlock( !(rtglock_flags & XFS_RTGLOCK_BITMAP));if (rtglock_flags &XFS_RTGLOCK_BITMAP ) { -xfs_iunlock (rtg->rtg_inodes[XFS_RTGI_SUMMARY ],XFS_ILOCK_EXCL ); -xfs_iunlock (rtg->rtg_inodes[XFS_RTGI_BITMAP ],XFS_ILOCK_EXCL ); +xfs_iunlock (rtg_summary (rtg),XFS_ILOCK_EXCL ); +xfs_iunlock (rtg_bitmap (rtg),XFS_ILOCK_EXCL ); }else if (rtglock_flags &XFS_RTGLOCK_BITMAP_SHARED ) { -xfs_iunlock (rtg->rtg_inodes[XFS_RTGI_BITMAP ],XFS_ILOCK_SHARED ); +xfs_iunlock (rtg_bitmap (rtg),XFS_ILOCK_SHARED ); } }
@@ -236,10 +236,8 @@ xfs_rtgroup_trans_join(ASSERT (!(rtglock_flags &XFS_RTGLOCK_BITMAP_SHARED ));if (rtglock_flags &XFS_RTGLOCK_BITMAP ) { -xfs_trans_ijoin (tp, rtg->rtg_inodes[XFS_RTGI_BITMAP ], -XFS_ILOCK_EXCL ); -xfs_trans_ijoin (tp, rtg->rtg_inodes[XFS_RTGI_SUMMARY ], -XFS_ILOCK_EXCL ); +xfs_trans_ijoin (tp,rtg_bitmap (rtg),XFS_ILOCK_EXCL ); +xfs_trans_ijoin (tp,rtg_summary (rtg),XFS_ILOCK_EXCL ); } }
fs/xfs/libxfs/xfs_rtgroup.h +10 -0
@@ -64,6 +64,16 @@ static inline xfs_rgnumber_t rtg_rgno(const struct xfs_rtgroup *rtg)return rtg->rtg_group.xg_gno; } +static inline struct xfs_inode *rtg_bitmap (const struct xfs_rtgroup *rtg) +{ +return rtg->rtg_inodes[XFS_RTGI_BITMAP ]; +} + +static inline struct xfs_inode *rtg_summary (const struct xfs_rtgroup *rtg) +{ +return rtg->rtg_inodes[XFS_RTGI_SUMMARY ]; +} +/* Passive rtgroup references */ static inline struct xfs_rtgroup * xfs_rtgroup_get(
fs/xfs/scrub/rtbitmap.c +3 -4
@@ -49,8 +49,7 @@ xchk_setup_rtbitmap(if (error)return error; - error =xchk_install_live_inode (sc, - sc->sr.rtg->rtg_inodes[XFS_RTGI_BITMAP ]); + error =xchk_install_live_inode (sc,rtg_bitmap (sc->sr.rtg));if (error)return error;
@@ -146,7 +145,7 @@ xchk_rtbitmap( {struct xfs_mount *mp = sc->mp;struct xfs_rtgroup *rtg = sc->sr.rtg; -struct xfs_inode *rbmip = rtg->rtg_inodes[XFS_RTGI_BITMAP ]; +struct xfs_inode *rbmip =rtg_bitmap (rtg);struct xchk_rtbitmap *rtb = sc->buf;int error;
@@ -215,7 +214,7 @@ xchk_xref_is_used_rt_space( xfs_extlen_t len) {struct xfs_rtgroup *rtg = sc->sr.rtg; -struct xfs_inode *rbmip = rtg->rtg_inodes[XFS_RTGI_BITMAP ]; +struct xfs_inode *rbmip =rtg_bitmap (rtg);xfs_rtxnum_t startext;xfs_rtxnum_t endext;bool is_free;
fs/xfs/scrub/rtsummary.c +5 -7
@@ -81,8 +81,7 @@ xchk_setup_rtsummary(if (error)return error; - error =xchk_install_live_inode (sc, - sc->sr.rtg->rtg_inodes[XFS_RTGI_SUMMARY ]); + error =xchk_install_live_inode (sc,rtg_summary (sc->sr.rtg));if (error)return error;
@@ -191,8 +190,7 @@ xchk_rtsum_record_free( rtlen =xfs_rtxlen_to_extlen (mp, rec->ar_extcount);if (!xfs_verify_rtbext (mp, rtbno, rtlen)) { -xchk_ino_xref_set_corrupt (sc, - rtg->rtg_inodes[XFS_RTGI_BITMAP ]->i_ino); +xchk_ino_xref_set_corrupt (sc,rtg_bitmap (rtg)->i_ino);return -EFSCORRUPTED ; }
@@ -218,7 +216,7 @@ xchk_rtsum_compute(/* If the bitmap size doesn't match the computed size, bail. */ if (XFS_FSB_TO_B (mp,xfs_rtbitmap_blockcount (mp)) != - rtg->rtg_inodes[XFS_RTGI_BITMAP ]->i_disk_size) +rtg_bitmap (rtg)->i_disk_size)return -EFSCORRUPTED ;return xfs_rtalloc_query_all (rtg, sc->tp, xchk_rtsum_record_free, sc);
@@ -310,8 +308,8 @@ xchk_rtsummary( {struct xfs_mount *mp = sc->mp;struct xfs_rtgroup *rtg = sc->sr.rtg; -struct xfs_inode *rbmip = rtg->rtg_inodes[XFS_RTGI_BITMAP ]; -struct xfs_inode *rsumip = rtg->rtg_inodes[XFS_RTGI_SUMMARY ]; +struct xfs_inode *rbmip =rtg_bitmap (rtg); +struct xfs_inode *rsumip =rtg_summary (rtg);struct xchk_rtsummary *rts = sc->buf;int error;
fs/xfs/xfs_qm.c +4 -4
@@ -230,10 +230,10 @@ xfs_qm_unmount_rt(if (!rtg)return ; -if (rtg->rtg_inodes[XFS_RTGI_BITMAP ]) -xfs_qm_dqdetach (rtg->rtg_inodes[XFS_RTGI_BITMAP ]); -if (rtg->rtg_inodes[XFS_RTGI_SUMMARY ]) -xfs_qm_dqdetach (rtg->rtg_inodes[XFS_RTGI_SUMMARY ]); +if (rtg_bitmap (rtg)) +xfs_qm_dqdetach (rtg_bitmap (rtg)); +if (rtg_summary (rtg)) +xfs_qm_dqdetach (rtg_summary (rtg));xfs_rtgroup_rele (rtg); }
fs/xfs/xfs_rtalloc.c +5 -5
@@ -856,8 +856,8 @@ xfs_growfs_rt_bmblock( xfs_fileoff_t bmbno) {struct xfs_mount *mp =rtg_mount (rtg); -struct xfs_inode *rbmip = rtg->rtg_inodes[XFS_RTGI_BITMAP ]; -struct xfs_inode *rsumip = rtg->rtg_inodes[XFS_RTGI_SUMMARY ]; +struct xfs_inode *rbmip =rtg_bitmap (rtg); +struct xfs_inode *rsumip =rtg_summary (rtg);struct xfs_rtalloc_args args = { .mp = mp, .rtg = rtg,
@@ -1041,8 +1041,8 @@ xfs_growfs_rt_alloc_blocks( xfs_extlen_t *nrbmblocks) {struct xfs_mount *mp =rtg_mount (rtg); -struct xfs_inode *rbmip = rtg->rtg_inodes[XFS_RTGI_BITMAP ]; -struct xfs_inode *rsumip = rtg->rtg_inodes[XFS_RTGI_SUMMARY ]; +struct xfs_inode *rbmip =rtg_bitmap (rtg); +struct xfs_inode *rsumip =rtg_summary (rtg);xfs_extlen_t orbmblocks =0 ;xfs_extlen_t orsumblocks =0 ;struct xfs_mount *nmp;
@@ -1622,7 +1622,7 @@ xfs_rtpick_extent( xfs_rtxlen_t len) /* allocation length (rtextents) */ {struct xfs_mount *mp =rtg_mount (rtg); -struct xfs_inode *rbmip = rtg->rtg_inodes[XFS_RTGI_BITMAP ]; +struct xfs_inode *rbmip =rtg_bitmap (rtg);xfs_rtxnum_t b =0 ;/* result rtext */ int log2;/* log of sequence number */ uint64_t resid;/* residual after log removed */
PATCH 2/37 xfs: prepare rmap btree cursor tracepoints for realtime
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Rework the rmap btree cursor tracepoints in preparation to handle the realtime rmap btree cursor. Mostly this involves renaming the field to "gbno" and extracting the group number from the cursor.
--- fs/xfs/xfs_rmap_item.c | 4 +- fs/xfs/xfs_trace.h | 82 +++++++++++++++++++++++++----------------------- 2 files changed, 44 insertions(+), 42 deletions(-)
fs/xfs/xfs_rmap_item.c +2 -2
@@ -351,10 +351,10 @@ xfs_rmap_defer_add( {struct xfs_mount *mp = tp->t_mountp; -trace_xfs_rmap_defer (mp, ri); - ri->ri_group =xfs_group_intent_get (mp, ri->ri_bmap.br_startblock,XG_TYPE_AG ); + +trace_xfs_rmap_defer (mp, ri);xfs_defer_add (tp, &ri->ri_list, &xfs_rmap_update_defer_type); }
fs/xfs/xfs_trace.h +42 -40
201 lines not on this page · raw message
PATCH 3/37 xfs: simplify the xfs_rmap_{alloc,free}_extent calling conventions
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Simplify the calling conventions by allowing callers to pass a fsbno (xfs_fsblock_t) directly into these functions, since we're just going to set it in a struct anyway.
--- fs/xfs/libxfs/xfs_refcount.c | 6 ++---- fs/xfs/libxfs/xfs_rmap.c | 12 +++++------- fs/xfs/libxfs/xfs_rmap.h | 8 ++++---- fs/xfs/scrub/alloc_repair.c | 5 +++-- 4 files changed, 14 insertions(+), 17 deletions(-)
fs/xfs/libxfs/xfs_refcount.c +2 -4
@@ -1831,8 +1831,7 @@ xfs_refcount_alloc_cow_extent(__xfs_refcount_add (tp,XFS_REFCOUNT_ALLOC_COW , fsb, len);/* Add rmap entry */ -xfs_rmap_alloc_extent (tp,XFS_FSB_TO_AGNO (mp, fsb), -XFS_FSB_TO_AGBNO (mp, fsb), len,XFS_RMAP_OWN_COW ); +xfs_rmap_alloc_extent (tp, fsb, len,XFS_RMAP_OWN_COW ); }/* Forget a CoW staging event in the refcount btree. */
@@ -1848,8 +1847,7 @@ xfs_refcount_free_cow_extent(return ;/* Remove rmap entry */ -xfs_rmap_free_extent (tp,XFS_FSB_TO_AGNO (mp, fsb), -XFS_FSB_TO_AGBNO (mp, fsb), len,XFS_RMAP_OWN_COW ); +xfs_rmap_free_extent (tp, fsb, len,XFS_RMAP_OWN_COW );__xfs_refcount_add (tp,XFS_REFCOUNT_FREE_COW , fsb, len); }
fs/xfs/libxfs/xfs_rmap.c +5 -7
@@ -525,7 +525,7 @@ xfs_rmap_free_check_owner(struct xfs_btree_cur *cur, uint64_t ltoff, struct xfs_rmap_irec *rec, - xfs_filblks_t len, + xfs_extlen_t len, uint64_t owner, uint64_t offset, unsigned int flags)
@@ -2729,8 +2729,7 @@ xfs_rmap_convert_extent(void xfs_rmap_alloc_extent (struct xfs_trans *tp, -xfs_agnumber_t agno, -xfs_agblock_t bno, +xfs_fsblock_t fsbno,xfs_extlen_t len,uint64_t owner) {
@@ -2739,7 +2738,7 @@ xfs_rmap_alloc_extent(if (!xfs_rmap_update_is_needed (tp->t_mountp,XFS_DATA_FORK ))return ; - bmap.br_startblock =XFS_AGB_TO_FSB (tp->t_mountp, agno, bno); + bmap.br_startblock = fsbno; bmap.br_blockcount = len; bmap.br_startoff =0 ; bmap.br_state =XFS_EXT_NORM ;
@@ -2751,8 +2750,7 @@ xfs_rmap_alloc_extent(void xfs_rmap_free_extent (struct xfs_trans *tp, -xfs_agnumber_t agno, -xfs_agblock_t bno, +xfs_fsblock_t fsbno,xfs_extlen_t len,uint64_t owner) {
@@ -2761,7 +2759,7 @@ xfs_rmap_free_extent(if (!xfs_rmap_update_is_needed (tp->t_mountp,XFS_DATA_FORK ))return ; - bmap.br_startblock =XFS_AGB_TO_FSB (tp->t_mountp, agno, bno); + bmap.br_startblock = fsbno; bmap.br_blockcount = len; bmap.br_startoff =0 ; bmap.br_state =XFS_EXT_NORM ;
fs/xfs/libxfs/xfs_rmap.h +4 -4
@@ -184,10 +184,10 @@ void xfs_rmap_unmap_extent(struct xfs_trans *tp, struct xfs_inode *ip,void xfs_rmap_convert_extent (struct xfs_mount *mp,struct xfs_trans *tp,struct xfs_inode *ip,int whichfork,struct xfs_bmbt_irec *imap); -void xfs_rmap_alloc_extent (struct xfs_trans *tp,xfs_agnumber_t agno, -xfs_agblock_t bno,xfs_extlen_t len,uint64_t owner); -void xfs_rmap_free_extent (struct xfs_trans *tp,xfs_agnumber_t agno, -xfs_agblock_t bno,xfs_extlen_t len,uint64_t owner); +void xfs_rmap_alloc_extent (struct xfs_trans *tp,xfs_fsblock_t fsbno, +xfs_extlen_t len,uint64_t owner); +void xfs_rmap_free_extent (struct xfs_trans *tp,xfs_fsblock_t fsbno, +xfs_extlen_t len,uint64_t owner);int xfs_rmap_finish_one (struct xfs_trans *tp,struct xfs_rmap_intent *ri,struct xfs_btree_cur **pcur);
fs/xfs/scrub/alloc_repair.c +3 -2
@@ -542,8 +542,9 @@ xrep_abt_dispose_one(/* Add a deferred rmap for each extent we used. */ if (resv->used >0 ) -xfs_rmap_alloc_extent (sc->tp,pag_agno (pag), resv->agbno, - resv->used,XFS_RMAP_OWN_AG ); +xfs_rmap_alloc_extent (sc->tp, +xfs_agbno_to_fsb (pag, resv->agbno), resv->used, +XFS_RMAP_OWN_AG );/* * For each reserved btree block we didn't use, add it to the free
PATCH 4/37 xfs: introduce realtime rmap btree ondisk definitions
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Add the ondisk structure definitions for realtime rmap btrees. The realtime rmap btree will be rooted from a hidden inode so it needs to have a separate btree block magic and pointer format.
Next, add everything needed to read, write and manipulate rmap btree blocks. This prepares the way for connecting the btree operations implementation, though embedding the rtrmap btree root in the inode comes later in the series.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_btree.c | 5 + fs/xfs/libxfs/xfs_format.h | 10 + fs/xfs/libxfs/xfs_ondisk.h | 1 fs/xfs/libxfs/xfs_rtrmap_btree.c | 271 ++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_rtrmap_btree.h | 82 +++++++++++ fs/xfs/libxfs/xfs_sb.c | 6 + fs/xfs/libxfs/xfs_shared.h | 7 + fs/xfs/xfs_mount.c | 5 - fs/xfs/xfs_mount.h | 9 + fs/xfs/xfs_stats.c | 3 fs/xfs/xfs_stats.h | 1 12 files changed, 398 insertions(+), 3 deletions(-) create mode 100644 fs/xfs/libxfs/xfs_rtrmap_btree.c create mode 100644 fs/xfs/libxfs/xfs_rtrmap_btree.h
fs/xfs/Makefile +1 -0
@@ -51,6 +51,7 @@ xfs-y += $(addprefix libxfs/, \ xfs_rmap_btree.o \ xfs_refcount.o \ xfs_refcount_btree.o \ + xfs_rtrmap_btree.o \ xfs_sb.o \ xfs_symlink_remote.o \ xfs_trans_inode.o \
fs/xfs/libxfs/xfs_btree.c +5 -0
@@ -30,6 +30,7 @@#include "xfs_health.h" #include "xfs_buf_mem.h" #include "xfs_btree_mem.h" +#include "xfs_rtrmap_btree.h" /* * Btree magic numbers.
@@ -5525,6 +5526,9 @@ xfs_btree_init_cur_caches(void)if (error) goto err; error =xfs_refcountbt_init_cur_cache (); +if (error) + goto err; + error =xfs_rtrmapbt_init_cur_cache ();if (error) goto err;
@@ -5543,6 +5547,7 @@ xfs_btree_destroy_cur_caches(void)xfs_bmbt_destroy_cur_cache ();xfs_rmapbt_destroy_cur_cache ();xfs_refcountbt_destroy_cur_cache (); +xfs_rtrmapbt_destroy_cur_cache (); }/* Move the btree cursor before the first record. */
fs/xfs/libxfs/xfs_format.h +10 -0
@@ -1725,6 +1725,16 @@ typedef __be32 xfs_rmap_ptr_t; XFS_FIBT_BLOCK(mp) + 1 : \ XFS_IBT_BLOCK(mp) + 1) +/* +* Realtime Reverse mapping btree format definitions +* +* This is a btree for reverse mapping records for realtime volumes +*/ +#define XFS_RTRMAP_CRC_MAGIC 0x4d415052/* 'MAPR' */ + +/* inode-based btree pointer type */ +typedef __be64 xfs_rtrmap_ptr_t ; +/* * Reference Count Btree format definitions *
fs/xfs/libxfs/xfs_ondisk.h +1 -0
@@ -83,6 +83,7 @@ xfs_check_ondisk_structs(void) XFS_CHECK_STRUCT_SIZE(union xfs_rtword_raw, 4); XFS_CHECK_STRUCT_SIZE(union xfs_suminfo_raw, 4); XFS_CHECK_STRUCT_SIZE(struct xfs_rtbuf_blkinfo, 48); +XFS_CHECK_STRUCT_SIZE (xfs_rtrmap_ptr_t,8 );/* * m68k has problems with struct xfs_attr_leaf_name_remote, but we pad
fs/xfs/libxfs/xfs_rtrmap_btree.c new file +271 -0
271 lines not on this page · raw message
fs/xfs/libxfs/xfs_rtrmap_btree.h new file +82 -0
82 lines not on this page · raw message
fs/xfs/libxfs/xfs_sb.c +6 -0
@@ -28,6 +28,7 @@#include "xfs_rtbitmap.h" #include "xfs_exchrange.h" #include "xfs_rtgroup.h" +#include "xfs_rtrmap_btree.h" /* * Physical superblock buffer manipulations. Shared with libxfs in userspace.
@@ -1215,6 +1216,11 @@ xfs_sb_mount_common( mp->m_rmap_mnr[0 ] = mp->m_rmap_mxr[0 ] /2 ; mp->m_rmap_mnr[1 ] = mp->m_rmap_mxr[1 ] /2 ; + mp->m_rtrmap_mxr[0 ] =xfs_rtrmapbt_maxrecs (mp, sbp->sb_blocksize, true); + mp->m_rtrmap_mxr[1 ] =xfs_rtrmapbt_maxrecs (mp, sbp->sb_blocksize, false); + mp->m_rtrmap_mnr[0 ] = mp->m_rtrmap_mxr[0 ] /2 ; + mp->m_rtrmap_mnr[1 ] = mp->m_rtrmap_mxr[1 ] /2 ; + mp->m_refc_mxr[0 ] =xfs_refcountbt_maxrecs (mp, sbp->sb_blocksize, true); mp->m_refc_mxr[1 ] =xfs_refcountbt_maxrecs (mp, sbp->sb_blocksize, false); mp->m_refc_mnr[0 ] = mp->m_refc_mxr[0 ] /2 ;
fs/xfs/libxfs/xfs_shared.h +7 -0
@@ -42,6 +42,7 @@ extern const struct xfs_buf_ops xfs_rtbitmap_buf_ops;extern const struct xfs_buf_ops xfs_rtsummary_buf_ops;extern const struct xfs_buf_ops xfs_rtbuf_ops;extern const struct xfs_buf_ops xfs_rtsb_buf_ops; +extern const struct xfs_buf_ops xfs_rtrmapbt_buf_ops;extern const struct xfs_buf_ops xfs_sb_buf_ops;extern const struct xfs_buf_ops xfs_sb_quiet_buf_ops;extern const struct xfs_buf_ops xfs_symlink_buf_ops;
@@ -55,6 +56,7 @@ extern const struct xfs_btree_ops xfs_bmbt_ops;extern const struct xfs_btree_ops xfs_refcountbt_ops;extern const struct xfs_btree_ops xfs_rmapbt_ops;extern const struct xfs_btree_ops xfs_rmapbt_mem_ops; +extern const struct xfs_btree_ops xfs_rtrmapbt_ops;static inline bool xfs_btree_is_bno (const struct xfs_btree_ops *ops) {
@@ -100,6 +102,11 @@ static inline bool xfs_btree_is_mem_rmap(const struct xfs_btree_ops *ops)# define xfs_btree_is_mem_rmap (...) (false)#endif +static inline bool xfs_btree_is_rtrmap (const struct xfs_btree_ops *ops) +{ +return ops == &xfs_rtrmapbt_ops; +} +/* log size calculation functions */ int xfs_log_calc_unit_res (struct xfs_mount *mp,int unit_bytes);int xfs_log_calc_minimum_size (struct xfs_mount *);
fs/xfs/xfs_mount.c +3 -2
@@ -37,6 +37,7 @@#include "xfs_rtbitmap.h" #include "xfs_metafile.h" #include "xfs_rtgroup.h" +#include "xfs_rtrmap_btree.h" #include "scrub/stats.h" static DEFINE_MUTEX (xfs_uuid_table_mutex);
@@ -655,8 +656,7 @@ static inline voidxfs_rtbtree_compute_maxlevels ( struct xfs_mount *mp) { -/* This will be filled in later. */ - mp->m_rtbtree_maxlevels =0 ; + mp->m_rtbtree_maxlevels = mp->m_rtrmap_maxlevels; }/*
@@ -727,6 +727,7 @@ xfs_mountfs(xfs_bmap_compute_maxlevels (mp,XFS_ATTR_FORK );xfs_mount_setup_inode_geom (mp);xfs_rmapbt_compute_maxlevels (mp); +xfs_rtrmapbt_compute_maxlevels (mp);xfs_refcountbt_compute_maxlevels (mp);xfs_agbtree_compute_maxlevels (mp);
fs/xfs/xfs_mount.h +9 -0
@@ -158,11 +158,14 @@ typedef struct xfs_mount {uint m_bmap_dmnr[2 ];/* min bmap btree records */ uint m_rmap_mxr[2 ];/* max rmap btree records */ uint m_rmap_mnr[2 ];/* min rmap btree records */ +uint m_rtrmap_mxr[2 ];/* max rtrmap btree records */ +uint m_rtrmap_mnr[2 ];/* min rtrmap btree records */ uint m_refc_mxr[2 ];/* max refc btree records */ uint m_refc_mnr[2 ];/* min refc btree records */ uint m_alloc_maxlevels;/* max alloc btree levels */ uint m_bm_maxlevels[2 ];/* max bmap btree levels */ uint m_rmap_maxlevels;/* max rmap btree levels */ +uint m_rtrmap_maxlevels;/* max rtrmap btree level */ uint m_refc_maxlevels;/* max refcount btree level */ unsigned int m_agbtree_maxlevels;/* max level of all AG btrees */ unsigned int m_rtbtree_maxlevels;/* max level of all rt btrees */
@@ -399,6 +402,12 @@ static inline bool xfs_has_rtsb(struct xfs_mount *mp)return xfs_has_rtgroups (mp) &&xfs_has_realtime (mp); } +static inline bool xfs_has_rtrmapbt (struct xfs_mount *mp) +{ +return xfs_has_rtgroups (mp) &&xfs_has_realtime (mp) && +xfs_has_rmapbt (mp); +} +/* * Some features are always on for v5 file systems, allow the compiler to * eliminiate dead code when building without v4 support.
fs/xfs/xfs_stats.c +2 -1
@@ -52,7 +52,8 @@ int xfs_stats_format(struct xfsstats __percpu *stats, char *buf) { "rmapbt", xfsstats_offset(xs_refcbt_2) }, { "refcntbt", xfsstats_offset(xs_rmap_mem_2) }, { "rmapbt_mem", xfsstats_offset(xs_rcbag_2) }, - { "rcbagbt", xfsstats_offset(xs_qm_dqreclaims)}, + { "rcbagbt", xfsstats_offset(xs_rtrmap_2) }, + { "rtrmapbt", xfsstats_offset(xs_qm_dqreclaims)},/* we print both series of quota information together */ { "qm", xfsstats_offset(xs_xstrat_bytes)}, };
fs/xfs/xfs_stats.h +1 -0
@@ -127,6 +127,7 @@ struct __xfsstats {uint32_t xs_refcbt_2[__XBTS_MAX];uint32_t xs_rmap_mem_2[__XBTS_MAX];uint32_t xs_rcbag_2[__XBTS_MAX]; +uint32_t xs_rtrmap_2[__XBTS_MAX];uint32_t xs_qm_dqreclaims;uint32_t xs_qm_dqreclaim_misses;uint32_t xs_qm_dquot_dups;
PATCH 5/37 xfs: realtime rmap btree transaction reservations
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Make sure that there's enough log reservation to handle mapping and unmapping realtime extents. We have to reserve enough space to handle a split in the rtrmapbt to add the record and a second split in the regular rmapbt to record the rtrmapbt split.
--- fs/xfs/libxfs/xfs_exchmaps.c | 4 +++- fs/xfs/libxfs/xfs_trans_resv.c | 12 ++++++++++-- fs/xfs/libxfs/xfs_trans_space.h | 13 +++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-)
fs/xfs/libxfs/xfs_exchmaps.c +3 -1
@@ -662,7 +662,9 @@ xfs_exchmaps_rmapbt_blocks(if (!xfs_has_rmapbt (mp))return 0 ;if (XFS_IS_REALTIME_INODE (req->ip1)) -return 0 ; +return howmany_64 (req->nr_exchanges, +XFS_MAX_CONTIG_RTRMAPS_PER_BLOCK (mp)) * +XFS_RTRMAPADD_SPACE_RES (mp);return howmany_64 (req->nr_exchanges, XFS_MAX_CONTIG_RMAPS_PER_BLOCK(mp)) *
fs/xfs/libxfs/xfs_trans_resv.c +10 -2
@@ -213,7 +213,9 @@ xfs_calc_inode_chunk_res(* Per-extent log reservation for the btree changes involved in freeing or * allocating a realtime extent. We have to be able to log as many rtbitmap * blocks as needed to mark inuse XFS_BMBT_MAX_EXTLEN blocks' worth of realtime -* extents, as well as the realtime summary block. +* extents, as well as the realtime summary block (t1). Realtime rmap btree +* operations happen in a second transaction, so factor in a couple of rtrmapbt +* splits (t2). */ static unsigned int xfs_rtalloc_block_count(
@@ -222,10 +224,16 @@ xfs_rtalloc_block_count( {unsigned int rtbmp_blocks;xfs_rtxlen_t rtxlen; +unsigned int t1, t2 =0 ; rtxlen =xfs_extlen_to_rtxlen (mp,XFS_MAX_BMBT_EXTLEN ); rtbmp_blocks =xfs_rtbitmap_blockcount_len (mp, rtxlen); -return (rtbmp_blocks +1 ) * num_ops; + t1 = (rtbmp_blocks +1 ) * num_ops; + +if (xfs_has_rmapbt (mp)) + t2 = num_ops * (2 * mp->m_rtrmap_maxlevels -1 ); + +return max (t1, t2); }/*
fs/xfs/libxfs/xfs_trans_space.h +13 -0
@@ -14,6 +14,19 @@#define XFS_MAX_CONTIG_BMAPS_PER_BLOCK (mp) \ (((mp)->m_bmap_dmxr[0]) - ((mp)->m_bmap_dmnr[0])) +/* Worst case number of realtime rmaps that can be held in a block. */ +#define XFS_MAX_CONTIG_RTRMAPS_PER_BLOCK (mp) \ + (((mp)->m_rtrmap_mxr[0]) - ((mp)->m_rtrmap_mnr[0])) + +/* Adding one realtime rmap could split every level to the top of the tree. */ +#define XFS_RTRMAPADD_SPACE_RES (mp) ((mp)->m_rtrmap_maxlevels) + +/* Blocks we might need to add "b" realtime rmaps to a tree. */ +#define XFS_NRTRMAPADD_SPACE_RES (mp, b) \ + ((((b) + XFS_MAX_CONTIG_RTRMAPS_PER_BLOCK(mp) - 1) / \ + XFS_MAX_CONTIG_RTRMAPS_PER_BLOCK(mp)) * \ + XFS_RTRMAPADD_SPACE_RES(mp)) +/* Worst case number of rmaps that can be held in a block. */ #define XFS_MAX_CONTIG_RMAPS_PER_BLOCK (mp) \ (((mp)->m_rmap_mxr[0]) - ((mp)->m_rmap_mnr[0]))
PATCH 6/37 xfs: add realtime rmap btree operations
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Implement the generic btree operations needed to manipulate rtrmap btree blocks. This is different from the regular rmapbt in that we allocate space from the filesystem at large, and are neither constrained to the free space nor any particular AG.
--- fs/xfs/libxfs/xfs_btree.c | 68 ++++++++++ fs/xfs/libxfs/xfs_btree.h | 6 + fs/xfs/libxfs/xfs_rtrmap_btree.c | 271 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+)
fs/xfs/libxfs/xfs_btree.c +68 -0
@@ -31,6 +31,10 @@#include "xfs_buf_mem.h" #include "xfs_btree_mem.h" #include "xfs_rtrmap_btree.h" +#include "xfs_bmap.h" +#include "xfs_rmap.h" +#include "xfs_quota.h" +#include "xfs_metafile.h" /* * Btree magic numbers.
@@ -5576,3 +5580,67 @@ xfs_btree_goto_left_edge(return 0 ; } + +/* Allocate a block for an inode-rooted metadata btree. */ +int +xfs_btree_alloc_metafile_block ( +struct xfs_btree_cur *cur, +const union xfs_btree_ptr *start, +union xfs_btree_ptr *new, +int *stat) +{ +struct xfs_alloc_arg args = { + .mp = cur->bc_mp, + .tp = cur->bc_tp, + .resv =XFS_AG_RESV_METAFILE , + .minlen =1 , + .maxlen =1 , + .prod =1 , + }; +struct xfs_inode *ip = cur->bc_ino.ip; +int error; + +ASSERT (xfs_is_metadir_inode (ip)); + +xfs_rmap_ino_bmbt_owner (&args.oinfo, ip->i_ino, cur->bc_ino.whichfork); + error =xfs_alloc_vextent_start_ag (&args, +XFS_INO_TO_FSB (cur->bc_mp, ip->i_ino)); +if (error) +return error; +if (args.fsbno ==NULLFSBLOCK ) { + *stat =0 ; +return 0 ; + } +ASSERT (args.len ==1 ); + +xfs_metafile_resv_alloc_space (ip, &args); + + new->l =cpu_to_be64 (args.fsbno); + *stat =1 ; +return 0 ; +} + +/* Free a block from an inode-rooted metadata btree. */ +int +xfs_btree_free_metafile_block ( +struct xfs_btree_cur *cur, +struct xfs_buf *bp) +{ +struct xfs_owner_info oinfo; +struct xfs_mount *mp = cur->bc_mp; +struct xfs_inode *ip = cur->bc_ino.ip; +struct xfs_trans *tp = cur->bc_tp; +xfs_fsblock_t fsbno =XFS_DADDR_TO_FSB (mp,xfs_buf_daddr (bp)); +int error; + +ASSERT (xfs_is_metadir_inode (ip)); + +xfs_rmap_ino_bmbt_owner (&oinfo, ip->i_ino, cur->bc_ino.whichfork); + error =xfs_free_extent_later (tp, fsbno,1 , &oinfo,XFS_AG_RESV_METAFILE , +0 ); +if (error) +return error; + +xfs_metafile_resv_free_space (ip, tp,1 ); +return 0 ; +}
fs/xfs/libxfs/xfs_btree.h +6 -0
@@ -703,4 +703,10 @@ xfs_btree_at_iroot( level == cur->bc_nlevels - 1; } +int xfs_btree_alloc_metafile_block (struct xfs_btree_cur *cur, +const union xfs_btree_ptr *start,union xfs_btree_ptr *newp, +int *stat); +int xfs_btree_free_metafile_block (struct xfs_btree_cur *cur, +struct xfs_buf *bp); +#endif /* __XFS_BTREE_H__ */
fs/xfs/libxfs/xfs_rtrmap_btree.c +271 -0
302 lines not on this page · raw message
PATCH 7/37 xfs: prepare rmap functions to deal with rtrmapbt
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Prepare the high-level rmap functions to deal with the new realtime rmapbt and its slightly different conventions. Provide the ability to talk to either rmapbt or rtrmapbt formats from the same high level code.
--- fs/xfs/libxfs/xfs_rmap.c | 63 +++++++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_rmap.h | 3 ++ fs/xfs/libxfs/xfs_rtgroup.h | 26 ++++++++++++++++++ 3 files changed, 92 insertions(+)
fs/xfs/libxfs/xfs_rmap.c +63 -0
@@ -25,6 +25,7 @@#include "xfs_ag.h" #include "xfs_health.h" #include "xfs_rmap_item.h" +#include "xfs_rtgroup.h" struct kmem_cache *xfs_rmap_intent_cache;
@@ -264,11 +265,69 @@ xfs_rmap_check_irec(return NULL ; } +static xfs_failaddr_t +xfs_rtrmap_check_meta_irec ( +struct xfs_rtgroup *rtg, +const struct xfs_rmap_irec *irec) +{ +struct xfs_mount *mp =rtg_mount (rtg); + +if (irec->rm_offset !=0 ) +return __this_address; +if (irec->rm_flags &XFS_RMAP_UNWRITTEN ) +return __this_address; + +switch (irec->rm_owner) { +case XFS_RMAP_OWN_FS : +if (irec->rm_startblock !=0 ) +return __this_address; +if (irec->rm_blockcount != mp->m_sb.sb_rextsize) +return __this_address; +return NULL ; +default : +return __this_address; + } + +return NULL ; +} + +static xfs_failaddr_t +xfs_rtrmap_check_inode_irec ( +struct xfs_rtgroup *rtg, +const struct xfs_rmap_irec *irec) +{ +struct xfs_mount *mp =rtg_mount (rtg); + +if (!xfs_verify_ino (mp, irec->rm_owner)) +return __this_address; +if (!xfs_verify_rgbext (rtg, irec->rm_startblock, irec->rm_blockcount)) +return __this_address; +if (!xfs_verify_fileext (mp, irec->rm_offset, irec->rm_blockcount)) +return __this_address; +return NULL ; +} + +xfs_failaddr_t +xfs_rtrmap_check_irec ( +struct xfs_rtgroup *rtg, +const struct xfs_rmap_irec *irec) +{ +if (irec->rm_blockcount ==0 ) +return __this_address; +if (irec->rm_flags & (XFS_RMAP_BMBT_BLOCK |XFS_RMAP_ATTR_FORK )) +return __this_address; +if (XFS_RMAP_NON_INODE_OWNER (irec->rm_owner)) +return xfs_rtrmap_check_meta_irec (rtg, irec); +return xfs_rtrmap_check_inode_irec (rtg, irec); +} +static inline xfs_failaddr_t xfs_rmap_check_btrec (struct xfs_btree_cur *cur,const struct xfs_rmap_irec *irec) { +if (xfs_btree_is_rtrmap (cur->bc_ops)) +return xfs_rtrmap_check_irec (to_rtg (cur->bc_group), irec);return xfs_rmap_check_irec (to_perag (cur->bc_group), irec); }
@@ -283,6 +342,10 @@ xfs_rmap_complain_bad_rec(if (xfs_btree_is_mem_rmap (cur->bc_ops))xfs_warn (mp,"In-Memory Reverse Mapping BTree record corruption detected at %pS!" , fa); +else if (xfs_btree_is_rtrmap (cur->bc_ops)) +xfs_warn (mp, +"RT Reverse Mapping BTree record corruption in rtgroup %u detected at %pS!" , + cur->bc_group->xg_gno, fa);else xfs_warn(mp, "Reverse Mapping BTree record corruption in AG %d detected at %pS!",
fs/xfs/libxfs/xfs_rmap.h +3 -0
@@ -7,6 +7,7 @@#define __XFS_RMAP_H__struct xfs_perag ; +struct xfs_rtgroup ;static inline void xfs_rmap_ino_bmbt_owner(
@@ -206,6 +207,8 @@ xfs_failaddr_t xfs_rmap_btrec_to_irec(const union xfs_btree_rec *rec, struct xfs_rmap_irec *irec);xfs_failaddr_t xfs_rmap_check_irec (struct xfs_perag *pag,const struct xfs_rmap_irec *irec); +xfs_failaddr_t xfs_rtrmap_check_irec (struct xfs_rtgroup *rtg, +const struct xfs_rmap_irec *irec);int xfs_rmap_has_records (struct xfs_btree_cur *cur,xfs_agblock_t bno,xfs_extlen_t len,enum xbtree_recpacking *outcome);
fs/xfs/libxfs/xfs_rtgroup.h +26 -0
@@ -132,6 +132,32 @@ xfs_rtgroup_next(return xfs_rtgroup_next_range (mp, rtg,0 , mp->m_sb.sb_rgcount -1 ); } +static inline bool +xfs_verify_rgbno ( +struct xfs_rtgroup *rtg, +xfs_rgblock_t rgbno) +{ +ASSERT (xfs_has_rtgroups (rtg_mount (rtg))); + +return xfs_verify_gbno (rtg_group (rtg), rgbno); +} + +/* +* Check that [@rgbno,@len] is a valid extent range in @rtg. +* +* Must only be used for RTG-enabled file systems. +*/ +static inline bool +xfs_verify_rgbext ( +struct xfs_rtgroup *rtg, +xfs_rgblock_t rgbno, +xfs_extlen_t len) +{ +ASSERT (xfs_has_rtgroups (rtg_mount (rtg))); + +return xfs_verify_gbext (rtg_group (rtg), rgbno, len); +} + static inline xfs_rtblock_t xfs_rgbno_to_rtb( struct xfs_rtgroup *rtg,
PATCH 8/37 xfs: add a realtime flag to the rmap update log redo items
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Extend the rmap update (RUI) log items to handle realtime volumes by adding a new log intent item type.
--- fs/xfs/libxfs/xfs_defer.h | 1 fs/xfs/libxfs/xfs_log_format.h | 6 + fs/xfs/libxfs/xfs_log_recover.h | 2 fs/xfs/libxfs/xfs_refcount.c | 4 - fs/xfs/libxfs/xfs_rmap.c | 17 ++- fs/xfs/libxfs/xfs_rmap.h | 5 + fs/xfs/scrub/alloc_repair.c | 2 fs/xfs/xfs_log_recover.c | 2 fs/xfs/xfs_rmap_item.c | 197 +++++++++++++++++++++++++++++++++++++-- 9 files changed, 213 insertions(+), 23 deletions(-)
fs/xfs/libxfs/xfs_defer.h +1 -0
@@ -69,6 +69,7 @@ struct xfs_defer_op_type {extern const struct xfs_defer_op_type xfs_bmap_update_defer_type;extern const struct xfs_defer_op_type xfs_refcount_update_defer_type;extern const struct xfs_defer_op_type xfs_rmap_update_defer_type; +extern const struct xfs_defer_op_type xfs_rtrmap_update_defer_type;extern const struct xfs_defer_op_type xfs_extent_free_defer_type;extern const struct xfs_defer_op_type xfs_agfl_free_defer_type;extern const struct xfs_defer_op_type xfs_rtextent_free_defer_type;
fs/xfs/libxfs/xfs_log_format.h +5 -1
@@ -250,6 +250,8 @@ typedef struct xfs_trans_header {#define XFS_LI_XMD 0x1249/* mapping exchange done */ #define XFS_LI_EFI_RT 0x124a/* realtime extent free intent */ #define XFS_LI_EFD_RT 0x124b/* realtime extent free done */ +#define XFS_LI_RUI_RT 0x124c/* realtime rmap update intent */ +#define XFS_LI_RUD_RT 0x124d/* realtime rmap update done */ #define XFS_LI_TYPE_DESC \ { XFS_LI_EFI, "XFS_LI_EFI" }, \
@@ -271,7 +273,9 @@ typedef struct xfs_trans_header { { XFS_LI_XMI, "XFS_LI_XMI" }, \ { XFS_LI_XMD, "XFS_LI_XMD" }, \ { XFS_LI_EFI_RT, "XFS_LI_EFI_RT" }, \ - { XFS_LI_EFD_RT, "XFS_LI_EFD_RT" } + { XFS_LI_EFD_RT, "XFS_LI_EFD_RT" }, \ + { XFS_LI_RUI_RT, "XFS_LI_RUI_RT" }, \ + { XFS_LI_RUD_RT, "XFS_LI_RUD_RT" }/* * Inode Log Item Format definitions.
fs/xfs/libxfs/xfs_log_recover.h +2 -0
@@ -79,6 +79,8 @@ extern const struct xlog_recover_item_ops xlog_xmi_item_ops;extern const struct xlog_recover_item_ops xlog_xmd_item_ops;extern const struct xlog_recover_item_ops xlog_rtefi_item_ops;extern const struct xlog_recover_item_ops xlog_rtefd_item_ops; +extern const struct xlog_recover_item_ops xlog_rtrui_item_ops; +extern const struct xlog_recover_item_ops xlog_rtrud_item_ops;/* * Macros, structures, prototypes for internal log manager use.
fs/xfs/libxfs/xfs_refcount.c +2 -2
@@ -1831,7 +1831,7 @@ xfs_refcount_alloc_cow_extent(__xfs_refcount_add (tp,XFS_REFCOUNT_ALLOC_COW , fsb, len);/* Add rmap entry */ -xfs_rmap_alloc_extent (tp, fsb, len,XFS_RMAP_OWN_COW ); +xfs_rmap_alloc_extent (tp, false, fsb, len,XFS_RMAP_OWN_COW ); }/* Forget a CoW staging event in the refcount btree. */
@@ -1847,7 +1847,7 @@ xfs_refcount_free_cow_extent(return ;/* Remove rmap entry */ -xfs_rmap_free_extent (tp, fsb, len,XFS_RMAP_OWN_COW ); +xfs_rmap_free_extent (tp, false, fsb, len,XFS_RMAP_OWN_COW );__xfs_refcount_add (tp,XFS_REFCOUNT_FREE_COW , fsb, len); }
fs/xfs/libxfs/xfs_rmap.c +12 -5
@@ -2710,6 +2710,7 @@ __xfs_rmap_add(struct xfs_trans *tp, enum xfs_rmap_intent_type type, uint64_t owner, + bool isrt, int whichfork, struct xfs_bmbt_irec *bmap) {
@@ -2721,6 +2722,7 @@ __xfs_rmap_add( ri->ri_owner = owner; ri->ri_whichfork = whichfork; ri->ri_bmap = *bmap; + ri->ri_realtime = isrt;xfs_rmap_defer_add (tp, ri); }
@@ -2734,6 +2736,7 @@ xfs_rmap_map_extent( struct xfs_bmbt_irec *PREV) {enum xfs_rmap_intent_type type =XFS_RMAP_MAP ; +bool isrt =xfs_ifork_is_realtime (ip, whichfork);if (!xfs_rmap_update_is_needed (tp->t_mountp, whichfork))return ;
@@ -2741,7 +2744,7 @@ xfs_rmap_map_extent(if (whichfork !=XFS_ATTR_FORK &&xfs_is_reflink_inode (ip)) type =XFS_RMAP_MAP_SHARED ; -__xfs_rmap_add (tp, type, ip->i_ino, whichfork,PREV ); +__xfs_rmap_add (tp, type, ip->i_ino, isrt, whichfork,PREV ); }/* Unmap an extent out of a file. */
@@ -2753,6 +2756,7 @@ xfs_rmap_unmap_extent( struct xfs_bmbt_irec *PREV) {enum xfs_rmap_intent_type type =XFS_RMAP_UNMAP ; +bool isrt =xfs_ifork_is_realtime (ip, whichfork);if (!xfs_rmap_update_is_needed (tp->t_mountp, whichfork))return ;
@@ -2760,7 +2764,7 @@ xfs_rmap_unmap_extent(if (whichfork !=XFS_ATTR_FORK &&xfs_is_reflink_inode (ip)) type =XFS_RMAP_UNMAP_SHARED ; -__xfs_rmap_add (tp, type, ip->i_ino, whichfork,PREV ); +__xfs_rmap_add (tp, type, ip->i_ino, isrt, whichfork,PREV ); }/*
@@ -2778,6 +2782,7 @@ xfs_rmap_convert_extent( struct xfs_bmbt_irec *PREV) {enum xfs_rmap_intent_type type =XFS_RMAP_CONVERT ; +bool isrt =xfs_ifork_is_realtime (ip, whichfork);if (!xfs_rmap_update_is_needed (mp, whichfork))return ;
@@ -2785,13 +2790,14 @@ xfs_rmap_convert_extent(if (whichfork !=XFS_ATTR_FORK &&xfs_is_reflink_inode (ip)) type =XFS_RMAP_CONVERT_SHARED ; -__xfs_rmap_add (tp, type, ip->i_ino, whichfork,PREV ); +__xfs_rmap_add (tp, type, ip->i_ino, isrt, whichfork,PREV ); }/* Schedule the creation of an rmap for non-file data. */ void xfs_rmap_alloc_extent (struct xfs_trans *tp, +bool isrt,xfs_fsblock_t fsbno,xfs_extlen_t len,uint64_t owner)
@@ -2806,13 +2812,14 @@ xfs_rmap_alloc_extent( bmap.br_startoff =0 ; bmap.br_state =XFS_EXT_NORM ; -__xfs_rmap_add (tp,XFS_RMAP_ALLOC , owner,XFS_DATA_FORK , &bmap); +__xfs_rmap_add (tp,XFS_RMAP_ALLOC , owner, isrt,XFS_DATA_FORK , &bmap); }/* Schedule the deletion of an rmap for non-file data. */ void xfs_rmap_free_extent (struct xfs_trans *tp, +bool isrt,xfs_fsblock_t fsbno,xfs_extlen_t len,uint64_t owner)
@@ -2827,7 +2834,7 @@ xfs_rmap_free_extent( bmap.br_startoff =0 ; bmap.br_state =XFS_EXT_NORM ; -__xfs_rmap_add (tp,XFS_RMAP_FREE , owner,XFS_DATA_FORK , &bmap); +__xfs_rmap_add (tp,XFS_RMAP_FREE , owner, isrt,XFS_DATA_FORK , &bmap); }/* Compare rmap records. Returns -1 if a < b, 1 if a > b, and 0 if equal. */
fs/xfs/libxfs/xfs_rmap.h +3 -2
@@ -175,6 +175,7 @@ struct xfs_rmap_intent {uint64_t ri_owner;struct xfs_bmbt_irec ri_bmap;struct xfs_group *ri_group; +bool ri_realtime; };/* functions for updating the rmapbt based on bmbt map/unmap operations */
@@ -185,9 +186,9 @@ void xfs_rmap_unmap_extent(struct xfs_trans *tp, struct xfs_inode *ip,void xfs_rmap_convert_extent (struct xfs_mount *mp,struct xfs_trans *tp,struct xfs_inode *ip,int whichfork,struct xfs_bmbt_irec *imap); -void xfs_rmap_alloc_extent (struct xfs_trans *tp,xfs_fsblock_t fsbno, +void xfs_rmap_alloc_extent (struct xfs_trans *tp,bool isrt,xfs_fsblock_t fsbno,xfs_extlen_t len,uint64_t owner); -void xfs_rmap_free_extent (struct xfs_trans *tp,xfs_fsblock_t fsbno, +void xfs_rmap_free_extent (struct xfs_trans *tp,bool isrt,xfs_fsblock_t fsbno,xfs_extlen_t len,uint64_t owner); int xfs_rmap_finish_one(struct xfs_trans *tp, struct xfs_rmap_intent *ri,
fs/xfs/scrub/alloc_repair.c +1 -1
@@ -542,7 +542,7 @@ xrep_abt_dispose_one(/* Add a deferred rmap for each extent we used. */ if (resv->used >0 ) -xfs_rmap_alloc_extent (sc->tp, +xfs_rmap_alloc_extent (sc->tp, false,xfs_agbno_to_fsb (pag, resv->agbno), resv->used,XFS_RMAP_OWN_AG );
fs/xfs/xfs_log_recover.c +2 -0
@@ -1820,6 +1820,8 @@ static const struct xlog_recover_item_ops *xlog_recover_item_ops[] = { &xlog_xmd_item_ops, &xlog_rtefi_item_ops, &xlog_rtefd_item_ops, + &xlog_rtrui_item_ops, + &xlog_rtrud_item_ops, }; static const struct xlog_recover_item_ops *
fs/xfs/xfs_rmap_item.c +185 -12
305 lines not on this page · raw message
PATCH 9/37 xfs: support recovering rmap intent items targetting realtime extents
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Now that we have rmap on the realtime device and rmap intent items that target the realtime device, log recovery has to support remapping extents on the realtime volume. Make this work. Identify rtrmapbt blocks in the log correctly so that we can validate them during log recovery.
--- fs/xfs/xfs_buf_item_recover.c | 4 ++++ fs/xfs/xfs_rmap_item.c | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-)
fs/xfs/xfs_buf_item_recover.c +4 -0
@@ -262,6 +262,9 @@ xlog_recover_validate_buf_type(case XFS_BMAP_MAGIC : bp->b_ops = &xfs_bmbt_buf_ops;break ; +case XFS_RTRMAP_CRC_MAGIC : + bp->b_ops = &xfs_rtrmapbt_buf_ops; +break ;case XFS_RMAP_CRC_MAGIC : bp->b_ops = &xfs_rmapbt_buf_ops;break ;
@@ -855,6 +858,7 @@ xlog_recover_get_buf_lsn( uuid = &btb->bb_u.s.bb_uuid;break ; } +case XFS_RTRMAP_CRC_MAGIC :case XFS_BMAP_CRC_MAGIC :case XFS_BMAP_MAGIC : {struct xfs_btree_block *btb = blk;
fs/xfs/xfs_rmap_item.c +12 -3
@@ -459,6 +459,7 @@ xfs_rmap_update_abort_intent(static inline bool xfs_rui_validate_map (struct xfs_mount *mp, +bool isrt,struct xfs_map_extent *map) {if (!xfs_has_rmapbt (mp))
@@ -488,6 +489,9 @@ xfs_rui_validate_map(if (!xfs_verify_fileext (mp, map->me_startoff, map->me_len))return false; +if (isrt) +return xfs_verify_rtbext (mp, map->me_startblock, map->me_len); +return xfs_verify_fsbext (mp, map->me_startblock, map->me_len); }
@@ -495,6 +499,7 @@ static inline voidxfs_rui_recover_work ( struct xfs_mount *mp, struct xfs_defer_pending *dfp, + bool isrt, const struct xfs_map_extent *map) { struct xfs_rmap_intent *ri;
@@ -539,7 +544,9 @@ xfs_rui_recover_work( ri->ri_bmap.br_blockcount = map->me_len; ri->ri_bmap.br_state = (map->me_flags &XFS_RMAP_EXTENT_UNWRITTEN ) ?XFS_EXT_UNWRITTEN :XFS_EXT_NORM ; - ri->ri_group =xfs_group_intent_get (mp, map->me_startblock,XG_TYPE_AG ); + ri->ri_group =xfs_group_intent_get (mp, map->me_startblock, + isrt ?XG_TYPE_RTG :XG_TYPE_AG ); + ri->ri_realtime = isrt;xfs_defer_add_item (dfp, &ri->ri_list); }
@@ -558,6 +565,7 @@ xfs_rmap_recover_work(struct xfs_rui_log_item *ruip =RUI_ITEM (lip);struct xfs_trans *tp;struct xfs_mount *mp = lip->li_log->l_mp; +bool isrt =xfs_rui_item_isrt (lip);int i;int error =0 ;
@@ -567,7 +575,7 @@ xfs_rmap_recover_work(* just toss the RUI. */ for (i =0 ; i < ruip->rui_format.rui_nextents; i++) { -if (!xfs_rui_validate_map (mp, +if (!xfs_rui_validate_map (mp, isrt, &ruip->rui_format.rui_extents[i])) { XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, &ruip->rui_format,
@@ -575,7 +583,8 @@ xfs_rmap_recover_work(return -EFSCORRUPTED ; } -xfs_rui_recover_work (mp, dfp, &ruip->rui_format.rui_extents[i]); +xfs_rui_recover_work (mp, dfp, isrt, + &ruip->rui_format.rui_extents[i]); } resv =xlog_recover_resv (&M_RES (mp)->tr_itruncate);
PATCH 10/37 xfs: pretty print metadata file types in error messages
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Create a helper function to turn a metadata file type code into a printable string, and use this to complain about lockdep problems with rtgroup inodes. We'll use this more in the next patch.
--- fs/xfs/libxfs/xfs_metafile.c | 18 ++++++++++++++++++ fs/xfs/libxfs/xfs_metafile.h | 2 ++ fs/xfs/libxfs/xfs_rtgroup.c | 3 ++- 3 files changed, 22 insertions(+), 1 deletion(-)
fs/xfs/libxfs/xfs_metafile.c +18 -0
@@ -22,6 +22,24 @@#include "xfs_error.h" #include "xfs_alloc.h" +static const struct { +enum xfs_metafile_type mtype; +const char *name; +} xfs_metafile_type_strs[] = {XFS_METAFILE_TYPE_STR }; + +const char * +xfs_metafile_type_str (enum xfs_metafile_type metatype) +{ +unsigned int i; + +for (i =0 ; i <ARRAY_SIZE (xfs_metafile_type_strs); i++) { +if (xfs_metafile_type_strs[i].mtype == metatype) +return xfs_metafile_type_strs[i].name; + } + +return NULL ; +} +/* Set up an inode to be recognized as a metadata directory inode. */ void xfs_metafile_set_iflag(
fs/xfs/libxfs/xfs_metafile.h +2 -0
@@ -6,6 +6,8 @@#ifndef __XFS_METAFILE_H__#define __XFS_METAFILE_H__ +const char *xfs_metafile_type_str (enum xfs_metafile_type metatype); +/* All metadata files must have these flags set. */ #define XFS_METAFILE_DIFLAGS (XFS_DIFLAG_IMMUTABLE | \ XFS_DIFLAG_SYNC | \
fs/xfs/libxfs/xfs_rtgroup.c +2 -1
@@ -282,7 +282,8 @@ xfs_rtginode_ilock_print_fn(const struct xfs_inode *ip = container_of(m, struct xfs_inode, i_lock.dep_map); -printk (KERN_CONT " rgno=%u" , ip->i_projid); +printk (KERN_CONT " rgno=%u metatype=%s" , ip->i_projid, +xfs_metafile_type_str (ip->i_metatype)); }/*
PATCH 11/37 xfs: support file data forks containing metadata btrees
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Create a new fork format type for metadata btrees. This fork type requires that the inode is in the metadata directory tree, and only applies to the data fork. The actual type of the metadata btree itself is determined by the di_metatype field.
--- fs/xfs/libxfs/xfs_format.h | 6 ++++-- fs/xfs/libxfs/xfs_inode_buf.c | 23 ++++++++++++++++++++-- fs/xfs/libxfs/xfs_inode_fork.c | 19 +++++++++++++++++++ fs/xfs/scrub/bmap.c | 1 + fs/xfs/scrub/bmap_repair.c | 1 + fs/xfs/scrub/inode.c | 4 ++++ fs/xfs/scrub/inode_repair.c | 36 +++++++++++++++++++++++++++++++++++ fs/xfs/scrub/rmap_repair.c | 31 ++++++++++++++++++++---------- fs/xfs/xfs_inode.c | 19 ++++++++++++++++++- fs/xfs/xfs_inode_item.c | 2 ++ fs/xfs/xfs_inode_item_recover.c | 40 ++++++++++++++++++++++++++++++++++----- fs/xfs/xfs_trace.h | 1 + 12 files changed, 162 insertions(+), 21 deletions(-)
fs/xfs/libxfs/xfs_format.h +4 -2
@@ -997,7 +997,8 @@ enum xfs_dinode_fmt {XFS_DINODE_FMT_LOCAL ,/* bulk data */ XFS_DINODE_FMT_EXTENTS ,/* struct xfs_bmbt_rec */ XFS_DINODE_FMT_BTREE ,/* struct xfs_bmdr_block */ - XFS_DINODE_FMT_UUID /* added long ago, but never used */ +XFS_DINODE_FMT_UUID ,/* added long ago, but never used */ + XFS_DINODE_FMT_META_BTREE, /* metadata btree */ };#define XFS_INODE_FORMAT_STR \
@@ -1005,7 +1006,8 @@ enum xfs_dinode_fmt { { XFS_DINODE_FMT_LOCAL, "local" }, \ { XFS_DINODE_FMT_EXTENTS, "extent" }, \ { XFS_DINODE_FMT_BTREE, "btree" }, \ - { XFS_DINODE_FMT_UUID, "uuid" } + { XFS_DINODE_FMT_UUID, "uuid" }, \ + { XFS_DINODE_FMT_META_BTREE, "meta_btree" }/* * Max values for extnum and aextnum.
fs/xfs/libxfs/xfs_inode_buf.c +20 -3
@@ -441,6 +441,16 @@ xfs_dinode_verify_fork(if (di_nextents > max_extents)return __this_address;break ; +case XFS_DINODE_FMT_META_BTREE : +if (!xfs_has_metadir (mp)) +return __this_address; +if (!(dip->di_flags2 &cpu_to_be64 (XFS_DIFLAG2_METADATA ))) +return __this_address; +switch (be16_to_cpu (dip->di_metatype)) { +default : +return __this_address; + } +break ;default :return __this_address; }
@@ -460,6 +470,10 @@ xfs_dinode_verify_forkoff(if (dip->di_forkoff != (roundup (sizeof (xfs_dev_t),8 ) >>3 ))return __this_address;break ; +case XFS_DINODE_FMT_META_BTREE : +if (!xfs_has_metadir (mp) || !xfs_has_parent (mp)) +return __this_address; + fallthrough;case XFS_DINODE_FMT_LOCAL :/* fall through ... */ case XFS_DINODE_FMT_EXTENTS :/* fall through ... */ case XFS_DINODE_FMT_BTREE :
@@ -637,9 +651,6 @@ xfs_dinode_verify(if (mode && nextents + naextents > nblocks)return __this_address; -if (nextents + naextents ==0 && nblocks !=0 ) -return __this_address; -if (S_ISDIR (mode) && nextents > mp->m_dir_geo->max_extents)return __this_address;
@@ -743,6 +754,12 @@ xfs_dinode_verify(return fa; } +/* metadata inodes containing btrees always have zero extent count */ +if (XFS_DFORK_FORMAT (dip,XFS_DATA_FORK ) !=XFS_DINODE_FMT_META_BTREE ) { +if (nextents + naextents ==0 && nblocks !=0 ) +return __this_address; + } +return NULL ; }
fs/xfs/libxfs/xfs_inode_fork.c +19 -0
@@ -267,6 +267,12 @@ xfs_iformat_data_fork(return xfs_iformat_extents (ip, dip,XFS_DATA_FORK );case XFS_DINODE_FMT_BTREE :return xfs_iformat_btree (ip, dip,XFS_DATA_FORK ); +case XFS_DINODE_FMT_META_BTREE : +switch (ip->i_metatype) { +default : +break ; + } + fallthrough;default :xfs_inode_verifier_error (ip, -EFSCORRUPTED , __func__, dip,sizeof (*dip), __this_address);
@@ -601,6 +607,19 @@ xfs_iflush_fork( }break ; +case XFS_DINODE_FMT_META_BTREE : +ASSERT (whichfork ==XFS_DATA_FORK ); + +if (!(iip->ili_fields & brootflag[whichfork])) +break ; + +switch (ip->i_metatype) { +default : +ASSERT (0 ); +break ; + } +break ; +default :ASSERT (0 );break ;
fs/xfs/scrub/bmap.c +1 -0
@@ -983,6 +983,7 @@ xchk_bmap(case XFS_DINODE_FMT_UUID :case XFS_DINODE_FMT_DEV :case XFS_DINODE_FMT_LOCAL : +case XFS_DINODE_FMT_META_BTREE :/* No mappings to check. */ if (whichfork ==XFS_COW_FORK )xchk_fblock_set_corrupt (sc, whichfork,0 );
fs/xfs/scrub/bmap_repair.c +1 -0
@@ -731,6 +731,7 @@ xrep_bmap_check_inputs(case XFS_DINODE_FMT_DEV :case XFS_DINODE_FMT_LOCAL :case XFS_DINODE_FMT_UUID : +case XFS_DINODE_FMT_META_BTREE :return -ECANCELED ;case XFS_DINODE_FMT_EXTENTS :case XFS_DINODE_FMT_BTREE :
fs/xfs/scrub/inode.c +4 -0
@@ -502,6 +502,10 @@ xchk_dinode(if (!S_ISREG (mode) && !S_ISDIR (mode))xchk_ino_set_corrupt (sc, ino);break ; +case XFS_DINODE_FMT_META_BTREE : +if (!S_ISREG (mode)) +xchk_ino_set_corrupt (sc, ino); +break ;case XFS_DINODE_FMT_UUID :default :xchk_ino_set_corrupt (sc, ino);
fs/xfs/scrub/inode_repair.c +36 -0
@@ -888,6 +888,25 @@ xrep_dinode_bad_bmbt_fork(return false; } +/* Check a metadata-btree fork. */ +STATIC bool +xrep_dinode_bad_metabt_fork ( +struct xfs_scrub *sc, +struct xfs_dinode *dip, +unsigned int dfork_size, +int whichfork) +{ +if (whichfork !=XFS_DATA_FORK ) +return true; + +switch (be16_to_cpu (dip->di_metatype)) { +default : +return true; + } + +return false; +} +/* * Check the data fork for things that will fail the ifork verifiers or the * ifork formatters.
@@ -968,6 +987,11 @@ xrep_dinode_check_dfork( XFS_DATA_FORK))return true;break ; +case XFS_DINODE_FMT_META_BTREE : +if (xrep_dinode_bad_metabt_fork (sc, dip, dfork_size, +XFS_DATA_FORK )) +return true; +break ;default :return true; }
@@ -1088,6 +1112,11 @@ xrep_dinode_check_afork( XFS_ATTR_FORK))return true;break ; +case XFS_DINODE_FMT_META_BTREE : +if (xrep_dinode_bad_metabt_fork (sc, dip, afork_size, +XFS_ATTR_FORK )) +return true; +break ;default :return true; }
@@ -1241,6 +1270,13 @@ xrep_dinode_ensure_forkoff( bmdr =XFS_DFORK_PTR (dip,XFS_DATA_FORK ); dfork_min =xfs_bmap_broot_space (sc->mp, bmdr);break ; +case XFS_DINODE_FMT_META_BTREE : +switch (be16_to_cpu (dip->di_metatype)) { +default : + dfork_min =0 ; +break ; + } +break ;default : dfork_min =0 ;break ;
fs/xfs/scrub/rmap_repair.c +21 -10
@@ -499,6 +499,14 @@ xrep_rmap_scan_iext(return xrep_rmap_stash_accumulated (rf); } +static int +xrep_rmap_scan_meta_btree ( +struct xrep_rmap_ifork *rf, +struct xfs_inode *ip) +{ +return -EFSCORRUPTED ;/* XXX placeholder */ +} +/* Find all the extents from a given AG in an inode fork. */ STATIC int xrep_rmap_scan_ifork(
@@ -512,14 +520,14 @@ xrep_rmap_scan_ifork( .whichfork = whichfork, };struct xfs_ifork *ifp =xfs_ifork_ptr (ip, whichfork); +bool mappings_done;int error =0 ;if (!ifp)return 0 ; -if (ifp->if_format ==XFS_DINODE_FMT_BTREE ) { -bool mappings_done; - +switch (ifp->if_format) { +case XFS_DINODE_FMT_BTREE :/* * Scan the bmap btree for data device mappings. This includes * the btree blocks themselves, even if this is a realtime
@@ -528,15 +536,18 @@ xrep_rmap_scan_ifork( error =xrep_rmap_scan_bmbt (&rf, ip, &mappings_done);if (error || mappings_done)return error; - }else if (ifp->if_format !=XFS_DINODE_FMT_EXTENTS ) { -return 0 ; + fallthrough; +case XFS_DINODE_FMT_EXTENTS : +/* Scan incore extent cache if this isn't a realtime file. */ +if (xfs_ifork_is_realtime (ip, whichfork)) +return 0 ; + +return xrep_rmap_scan_iext (&rf, ifp); +case XFS_DINODE_FMT_META_BTREE : +return xrep_rmap_scan_meta_btree (&rf, ip); } -/* Scan incore extent cache if this isn't a realtime file. */ -if (xfs_ifork_is_realtime (ip, whichfork)) -return 0 ; - -return xrep_rmap_scan_iext (&rf, ifp); +return 0 ; }/*
fs/xfs/xfs_inode.c +18 -1
@@ -2382,7 +2382,16 @@ xfs_iflush( __func__, ip->i_ino, be16_to_cpu(dip->di_magic), dip); goto flush_out; } -if (S_ISREG (VFS_I (ip)->i_mode)) { +if (ip->i_df.if_format ==XFS_DINODE_FMT_META_BTREE ) { +if (!S_ISREG (VFS_I (ip)->i_mode) || + !(ip->i_diflags2 &XFS_DIFLAG2_METADATA )) { +xfs_alert_tag (mp,XFS_PTAG_IFLUSH , +"%s: Bad %s meta btree inode %Lu, ptr " PTR_FMT , + __func__,xfs_metafile_type_str (ip->i_metatype), + ip->i_ino, ip); + goto flush_out; + } + }else if (S_ISREG (VFS_I (ip)->i_mode)) { if (XFS_TEST_ERROR( ip->i_df.if_format != XFS_DINODE_FMT_EXTENTS && ip->i_df.if_format != XFS_DINODE_FMT_BTREE,
@@ -2422,6 +2431,14 @@ xfs_iflush( goto flush_out; } +if (xfs_inode_has_attr_fork (ip) && + ip->i_af.if_format ==XFS_DINODE_FMT_META_BTREE ) { +xfs_alert_tag (mp,XFS_PTAG_IFLUSH , +"%s: meta btree in inode %Lu attr fork, ptr " PTR_FMT , + __func__, ip->i_ino, ip); + goto flush_out; + } +/* * Inode item log recovery for v2 inodes are dependent on the flushiter * count for correct sequencing. We bump the flush iteration count so
fs/xfs/xfs_inode_item.c +2 -0
@@ -242,6 +242,7 @@ xfs_inode_item_data_fork_size( }break ;case XFS_DINODE_FMT_BTREE : +case XFS_DINODE_FMT_META_BTREE :if ((iip->ili_fields &XFS_ILOG_DBROOT ) && ip->i_df.if_broot_bytes >0 ) { *nbytes += ip->i_df.if_broot_bytes;
@@ -362,6 +363,7 @@ xfs_inode_item_format_data_fork( }break ;case XFS_DINODE_FMT_BTREE : +case XFS_DINODE_FMT_META_BTREE : iip->ili_fields &= ~(XFS_ILOG_DDATA |XFS_ILOG_DEXT |XFS_ILOG_DEV );
fs/xfs/xfs_inode_item_recover.c +35 -5
@@ -266,6 +266,35 @@ xlog_dinode_verify_extent_counts(return 0 ; } +static inline int +xlog_recover_inode_dbroot ( +struct xfs_mount *mp, +void *src, +unsigned int len, +struct xfs_dinode *dip) +{ +void *dfork =XFS_DFORK_DPTR (dip); +unsigned int dsize =XFS_DFORK_DSIZE (dip, mp); + +switch (dip->di_format) { +case XFS_DINODE_FMT_BTREE : +xfs_bmbt_to_bmdr (mp, src, len, dfork, dsize); +break ; +case XFS_DINODE_FMT_META_BTREE : +switch (be16_to_cpu (dip->di_metatype)) { +default : +ASSERT (0 ); +return -EFSCORRUPTED ; + } +break ; +default : +ASSERT (0 ); +return -EFSCORRUPTED ; + } + +return 0 ; +} + STATIC int xlog_recover_inode_commit_pass2( struct xlog *log,
@@ -393,8 +422,9 @@ xlog_recover_inode_commit_pass2(if (unlikely (S_ISREG (ldip->di_mode))) { -if ((ldip->di_format !=XFS_DINODE_FMT_EXTENTS ) && - (ldip->di_format !=XFS_DINODE_FMT_BTREE )) { +if (ldip->di_format !=XFS_DINODE_FMT_EXTENTS && + ldip->di_format !=XFS_DINODE_FMT_BTREE && + ldip->di_format !=XFS_DINODE_FMT_META_BTREE ) {XFS_CORRUPTION_ERROR ("Bad log dinode data fork format for regular file" ,XFS_ERRLEVEL_LOW , mp, ldip,sizeof (*ldip));
@@ -475,9 +505,9 @@ xlog_recover_inode_commit_pass2(break ;case XFS_ILOG_DBROOT : -xfs_bmbt_to_bmdr (mp, (struct xfs_btree_block *)src, len, - (struct xfs_bmdr_block *)XFS_DFORK_DPTR (dip), -XFS_DFORK_DSIZE (dip, mp)); + error =xlog_recover_inode_dbroot (mp, src, len, dip); +if (error) + goto out_release;break ;default :
fs/xfs/xfs_trace.h +1 -0
@@ -2299,6 +2299,7 @@ TRACE_DEFINE_ENUM(XFS_DINODE_FMT_LOCAL);TRACE_DEFINE_ENUM (XFS_DINODE_FMT_EXTENTS );TRACE_DEFINE_ENUM (XFS_DINODE_FMT_BTREE );TRACE_DEFINE_ENUM (XFS_DINODE_FMT_UUID ); +TRACE_DEFINE_ENUM (XFS_DINODE_FMT_META_BTREE ); DECLARE_EVENT_CLASS(xfs_swap_extent_class, TP_PROTO(struct xfs_inode *ip, int which),
PATCH 12/37 xfs: add realtime reverse map inode to metadata directory
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Add a metadir path to select the realtime rmap btree inode and load it at mount time. The rtrmapbt inode will have a unique extent format code, which means that we also have to update the inode validation and flush routines to look for it.
--- fs/xfs/libxfs/xfs_format.h | 4 +++- fs/xfs/libxfs/xfs_inode_buf.c | 9 +++++++++ fs/xfs/libxfs/xfs_inode_fork.c | 6 ++++++ fs/xfs/libxfs/xfs_rtgroup.c | 20 ++++++++++++++++++-- fs/xfs/libxfs/xfs_rtgroup.h | 8 ++++++++ fs/xfs/libxfs/xfs_rtrmap_btree.c | 6 +++--- 6 files changed, 47 insertions(+), 6 deletions(-)
fs/xfs/libxfs/xfs_format.h +3 -1
@@ -857,6 +857,7 @@ enum xfs_metafile_type {XFS_METAFILE_PRJQUOTA ,/* project quota */ XFS_METAFILE_RTBITMAP ,/* rt bitmap */ XFS_METAFILE_RTSUMMARY ,/* rt summary */ +XFS_METAFILE_RTRMAP ,/* rt rmap */ XFS_METAFILE_MAX } __packed;
@@ -868,7 +869,8 @@ enum xfs_metafile_type { { XFS_METAFILE_GRPQUOTA, "grpquota" }, \ { XFS_METAFILE_PRJQUOTA, "prjquota" }, \ { XFS_METAFILE_RTBITMAP, "rtbitmap" }, \ - { XFS_METAFILE_RTSUMMARY, "rtsummary" } + { XFS_METAFILE_RTSUMMARY, "rtsummary" }, \ + { XFS_METAFILE_RTRMAP, "rtrmap" }/* * On-disk inode structure.
fs/xfs/libxfs/xfs_inode_buf.c +9 -0
@@ -447,6 +447,15 @@ xfs_dinode_verify_fork(if (!(dip->di_flags2 &cpu_to_be64 (XFS_DIFLAG2_METADATA )))return __this_address;switch (be16_to_cpu (dip->di_metatype)) { +case XFS_METAFILE_RTRMAP : +/* +* growfs must create the rtrmap inodes before adding a +* realtime volume to the filesystem, so we cannot use +* the rtrmapbt predicate here. +*/ +if (!xfs_has_rmapbt (mp)) +return __this_address; +break ;default :return __this_address; }
fs/xfs/libxfs/xfs_inode_fork.c +6 -0
@@ -269,6 +269,9 @@ xfs_iformat_data_fork(return xfs_iformat_btree (ip, dip,XFS_DATA_FORK );case XFS_DINODE_FMT_META_BTREE :switch (ip->i_metatype) { +case XFS_METAFILE_RTRMAP : +ASSERT (0 );/* to be implemented later */ +return -EFSCORRUPTED ;default :break ; }
@@ -614,6 +617,9 @@ xfs_iflush_fork(break ;switch (ip->i_metatype) { +case XFS_METAFILE_RTRMAP : +ASSERT (0 );/* to be implemented later */ +break ;default :ASSERT (0 );break ;
fs/xfs/libxfs/xfs_rtgroup.c +18 -2
@@ -315,6 +315,8 @@ struct xfs_rtginode_ops {unsigned int sick;/* rtgroup sickness flag */ +unsigned int fmt_mask;/* all valid data fork formats */ +/* Does the fs have this feature? */ bool (*enabled)(struct xfs_mount *mp);
@@ -330,14 +332,29 @@ static const struct xfs_rtginode_ops xfs_rtginode_ops[XFS_RTGI_MAX] = { .name = "bitmap", .metafile_type = XFS_METAFILE_RTBITMAP, .sick = XFS_SICK_RG_BITMAP, + .fmt_mask = (1U <<XFS_DINODE_FMT_EXTENTS ) | + (1U << XFS_DINODE_FMT_BTREE), .create = xfs_rtbitmap_create, }, [XFS_RTGI_SUMMARY] = { .name = "summary", .metafile_type = XFS_METAFILE_RTSUMMARY, .sick = XFS_SICK_RG_SUMMARY, + .fmt_mask = (1U <<XFS_DINODE_FMT_EXTENTS ) | + (1U << XFS_DINODE_FMT_BTREE), .create = xfs_rtsummary_create, }, + [XFS_RTGI_RMAP] = { + .name = "rmap", + .metafile_type = XFS_METAFILE_RTRMAP, + .fmt_mask = 1U << XFS_DINODE_FMT_META_BTREE, +/* +* growfs must create the rtrmap inodes before adding a +* realtime volume to the filesystem, so we cannot use the +* rtrmapbt predicate here. +*/ + .enabled = xfs_has_rmapbt, + }, };/* Return the shortname of this rtgroup inode. */
@@ -434,8 +451,7 @@ xfs_rtginode_load(return error; } -if (XFS_IS_CORRUPT (mp, ip->i_df.if_format !=XFS_DINODE_FMT_EXTENTS && - ip->i_df.if_format !=XFS_DINODE_FMT_BTREE )) { +if (XFS_IS_CORRUPT (mp, !((1U << ip->i_df.if_format) & ops->fmt_mask))) {xfs_irele (ip);xfs_rtginode_mark_sick (rtg, type);return -EFSCORRUPTED ;
fs/xfs/libxfs/xfs_rtgroup.h +8 -0
@@ -14,6 +14,7 @@ struct xfs_trans;enum xfs_rtg_inodes {XFS_RTGI_BITMAP ,/* allocation bitmap */ XFS_RTGI_SUMMARY ,/* allocation summary */ +XFS_RTGI_RMAP ,/* rmap btree inode */ XFS_RTGI_MAX , };
@@ -74,6 +75,11 @@ static inline struct xfs_inode *rtg_summary(const struct xfs_rtgroup *rtg)return rtg->rtg_inodes[XFS_RTGI_SUMMARY ]; } +static inline struct xfs_inode *rtg_rmap (const struct xfs_rtgroup *rtg) +{ +return rtg->rtg_inodes[XFS_RTGI_RMAP ]; +} +/* Passive rtgroup references */ static inline struct xfs_rtgroup * xfs_rtgroup_get(
@@ -284,6 +290,8 @@ int xfs_rtginode_create(struct xfs_rtgroup *rtg, enum xfs_rtg_inodes type, bool init);void xfs_rtginode_irele (struct xfs_inode **ipp); +void xfs_rtginode_irele (struct xfs_inode **ipp); +static inline const char *xfs_rtginode_path (xfs_rgnumber_t rgno,enum xfs_rtg_inodes type) {
fs/xfs/libxfs/xfs_rtrmap_btree.c +3 -3
@@ -18,6 +18,7 @@#include "xfs_alloc.h" #include "xfs_btree.h" #include "xfs_btree_staging.h" +#include "xfs_metafile.h" #include "xfs_rmap.h" #include "xfs_rtrmap_btree.h" #include "xfs_trace.h"
@@ -405,12 +406,10 @@ xfs_rtrmapbt_init_cursor(struct xfs_trans *tp, struct xfs_rtgroup *rtg) { - struct xfs_inode *ip = NULL; + struct xfs_inode *ip = rtg_rmap(rtg);struct xfs_mount *mp =rtg_mount (rtg);struct xfs_btree_cur *cur; -return NULL ;/* XXX */ -xfs_assert_ilocked (ip,XFS_ILOCK_SHARED |XFS_ILOCK_EXCL ); cur = xfs_btree_alloc_cursor(mp, tp, &xfs_rtrmapbt_ops,
@@ -439,6 +438,7 @@ xfs_rtrmapbt_commit_staged_btree(int flags =XFS_ILOG_CORE |XFS_ILOG_DBROOT ;ASSERT (cur->bc_flags &XFS_BTREE_STAGING ); +ASSERT (ifake->if_fork->if_format ==XFS_DINODE_FMT_META_BTREE );/* * Free any resources hanging off the real fork, then shallow-copy the
PATCH 13/37 xfs: add metadata reservations for realtime rmap btrees
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Reserve some free blocks so that we will always have enough free blocks in the data volume to handle expansion of the realtime rmap btree.
--- fs/xfs/libxfs/xfs_rtrmap_btree.c | 41 ++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_rtrmap_btree.h | 2 ++ fs/xfs/xfs_rtalloc.c | 23 ++++++++++++++++++++- 3 files changed, 65 insertions(+), 1 deletion(-)
fs/xfs/libxfs/xfs_rtrmap_btree.c +41 -0
@@ -540,3 +540,44 @@ xfs_rtrmapbt_compute_maxlevels(/* Add one level to handle the inode root level. */ mp->m_rtrmap_maxlevels =min (d_maxlevels, r_maxlevels) +1 ; } + +/* Calculate the rtrmap btree size for some records. */ +static unsigned long long +xfs_rtrmapbt_calc_size ( +struct xfs_mount *mp, +unsigned long long len) +{ +return xfs_btree_calc_size (mp->m_rtrmap_mnr, len); +} + +/* +* Calculate the maximum rmap btree size. +*/ +static unsigned long long +xfs_rtrmapbt_max_size ( +struct xfs_mount *mp, +xfs_rtblock_t rtblocks) +{ +/* Bail out if we're uninitialized, which can happen in mkfs. */ +if (mp->m_rtrmap_mxr[0 ] ==0 ) +return 0 ; + +return xfs_rtrmapbt_calc_size (mp, rtblocks); +} + +/* +* Figure out how many blocks to reserve and how many are used by this btree. +*/ +xfs_filblks_t +xfs_rtrmapbt_calc_reserves ( +struct xfs_mount *mp) +{ +uint32_t blocks = mp->m_groups[XG_TYPE_RTG ].blocks; + +if (!xfs_has_rtrmapbt (mp)) +return 0 ; + +/* Reserve 1% of the rtgroup or enough for 1 block per record. */ +return max_t (xfs_filblks_t, blocks /100 , +xfs_rtrmapbt_max_size (mp, blocks)); +}
fs/xfs/libxfs/xfs_rtrmap_btree.h +2 -0
@@ -79,4 +79,6 @@ unsigned int xfs_rtrmapbt_maxlevels_ondisk(void);int __init xfs_rtrmapbt_init_cur_cache (void );void xfs_rtrmapbt_destroy_cur_cache (void ); +xfs_filblks_t xfs_rtrmapbt_calc_reserves (struct xfs_mount *mp); +#endif /* __XFS_RTRMAP_BTREE_H__ */
fs/xfs/xfs_rtalloc.c +22 -1
@@ -22,6 +22,7 @@#include "xfs_rtalloc.h" #include "xfs_sb.h" #include "xfs_rtbitmap.h" +#include "xfs_rtrmap_btree.h" #include "xfs_quota.h" #include "xfs_log_priv.h" #include "xfs_health.h"
@@ -1498,6 +1499,13 @@ voidxfs_rt_resv_free ( struct xfs_mount *mp) { +struct xfs_rtgroup *rtg =NULL ; +unsigned int i; + +while ((rtg =xfs_rtgroup_next (mp, rtg))) { +for (i =0 ; i <XFS_RTGI_MAX ; i++) +xfs_metafile_resv_free (rtg->rtg_inodes[i]); + } }/* Reserve space for rt metadata inodes' space expansion. */
@@ -1505,7 +1513,20 @@ intxfs_rt_resv_init ( struct xfs_mount *mp) { -return 0 ; +struct xfs_rtgroup *rtg =NULL ; +xfs_filblks_t ask; +int error =0 ; + +while ((rtg =xfs_rtgroup_next (mp, rtg))) { +int err2; + + ask =xfs_rtrmapbt_calc_reserves (mp); + err2 =xfs_metafile_resv_init (rtg_rmap (rtg), ask); +if (err2 && !error) + error = err2; + } + +return error; }/*
PATCH 14/37 xfs: wire up a new metafile type for the realtime rmap
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Plumb in the pieces we need to embed the root of the realtime rmap btree in an inode's data fork, complete with new metafile type and on-disk interpretation functions.
--- fs/xfs/libxfs/xfs_format.h | 8 + fs/xfs/libxfs/xfs_inode_fork.c | 6 - fs/xfs/libxfs/xfs_ondisk.h | 1 fs/xfs/libxfs/xfs_rtrmap_btree.c | 251 ++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_rtrmap_btree.h | 112 +++++++++++++++++ fs/xfs/xfs_inode_item_recover.c | 4 + 6 files changed, 379 insertions(+), 3 deletions(-)
fs/xfs/libxfs/xfs_format.h +8 -0
@@ -1736,6 +1736,14 @@ typedef __be32 xfs_rmap_ptr_t;*/ #define XFS_RTRMAP_CRC_MAGIC 0x4d415052/* 'MAPR' */ +/* +* rtrmap root header, on-disk form only. +*/ +struct xfs_rtrmap_root { +__be16 bb_level;/* 0 is a leaf */ +__be16 bb_numrecs;/* current # of data records */ +}; +/* inode-based btree pointer type */ typedef __be64 xfs_rtrmap_ptr_t ;
fs/xfs/libxfs/xfs_inode_fork.c +3 -3
@@ -27,6 +27,7 @@#include "xfs_errortag.h" #include "xfs_health.h" #include "xfs_symlink_remote.h" +#include "xfs_rtrmap_btree.h" struct kmem_cache *xfs_ifork_cache;
@@ -270,8 +271,7 @@ xfs_iformat_data_fork(case XFS_DINODE_FMT_META_BTREE :switch (ip->i_metatype) {case XFS_METAFILE_RTRMAP : -ASSERT (0 );/* to be implemented later */ -return -EFSCORRUPTED ; +return xfs_iformat_rtrmap (ip, dip);default :break ; }
@@ -618,7 +618,7 @@ xfs_iflush_fork(switch (ip->i_metatype) {case XFS_METAFILE_RTRMAP : -ASSERT (0 );/* to be implemented later */ +xfs_iflush_rtrmap (ip, dip);break ;default :ASSERT (0 );
fs/xfs/libxfs/xfs_ondisk.h +1 -0
@@ -84,6 +84,7 @@ xfs_check_ondisk_structs(void) XFS_CHECK_STRUCT_SIZE(union xfs_suminfo_raw, 4); XFS_CHECK_STRUCT_SIZE(struct xfs_rtbuf_blkinfo, 48);XFS_CHECK_STRUCT_SIZE (xfs_rtrmap_ptr_t,8 ); + XFS_CHECK_STRUCT_SIZE(struct xfs_rtrmap_root, 4);/* * m68k has problems with struct xfs_attr_leaf_name_remote, but we pad
fs/xfs/libxfs/xfs_rtrmap_btree.c +251 -0
278 lines not on this page · raw message
fs/xfs/libxfs/xfs_rtrmap_btree.h +112 -0
122 lines not on this page · raw message
fs/xfs/xfs_inode_item_recover.c +4 -0
@@ -22,6 +22,7 @@#include "xfs_log_recover.h" #include "xfs_icache.h" #include "xfs_bmap_btree.h" +#include "xfs_rtrmap_btree.h" STATIC void xlog_recover_inode_ra_pass2(
@@ -282,6 +283,9 @@ xlog_recover_inode_dbroot(break ;case XFS_DINODE_FMT_META_BTREE :switch (be16_to_cpu (dip->di_metatype)) { +case XFS_METAFILE_RTRMAP : +xfs_rtrmapbt_to_disk (mp, src, len, dfork, dsize); +return 0 ;default :ASSERT (0 );return -EFSCORRUPTED ;
PATCH 15/37 xfs: wire up rmap map and unmap to the realtime rmapbt
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Connect the map and unmap reverse-mapping operations to the realtime rmapbt via the deferred operation callbacks. This enables us to perform rmap operations against the correct btree.
--- fs/xfs/libxfs/xfs_rmap.c | 78 +++++++++++++++++++++++++++++-------------- fs/xfs/libxfs/xfs_rtgroup.c | 9 +++++ fs/xfs/libxfs/xfs_rtgroup.h | 5 ++- 3 files changed, 66 insertions(+), 26 deletions(-)
fs/xfs/libxfs/xfs_rmap.c +53 -25
@@ -26,6 +26,7 @@#include "xfs_health.h" #include "xfs_rmap_item.h" #include "xfs_rtgroup.h" +#include "xfs_rtrmap_btree.h" struct kmem_cache *xfs_rmap_intent_cache;
@@ -2619,6 +2620,47 @@ __xfs_rmap_finish_intent( } } +static int +xfs_rmap_finish_init_cursor ( +struct xfs_trans *tp, +struct xfs_rmap_intent *ri, +struct xfs_btree_cur **pcur) +{ +struct xfs_perag *pag =to_perag (ri->ri_group); +struct xfs_buf *agbp =NULL ; +int error; + +/* +* Refresh the freelist before we start changing the rmapbt, because a +* shape change could cause us to allocate blocks. +*/ + error =xfs_free_extent_fix_freelist (tp, pag, &agbp); +if (error) { +xfs_ag_mark_sick (pag,XFS_SICK_AG_AGFL ); +return error; + } +if (XFS_IS_CORRUPT (tp->t_mountp, !agbp)) { +xfs_ag_mark_sick (pag,XFS_SICK_AG_AGFL ); +return -EFSCORRUPTED ; + } + *pcur =xfs_rmapbt_init_cursor (tp->t_mountp, tp, agbp, pag); +return 0 ; +} + +static int +xfs_rtrmap_finish_init_cursor ( +struct xfs_trans *tp, +struct xfs_rmap_intent *ri, +struct xfs_btree_cur **pcur) +{ +struct xfs_rtgroup *rtg =to_rtg (ri->ri_group); + +xfs_rtgroup_lock (rtg,XFS_RTGLOCK_RMAP ); +xfs_rtgroup_trans_join (tp, rtg,XFS_RTGLOCK_RMAP ); + *pcur =xfs_rtrmapbt_init_cursor (tp, rtg); +return 0 ; +} +/* * Process one of the deferred rmap operations. We pass back the * btree cursor to maintain our lock on the rmapbt between calls.
@@ -2634,8 +2676,6 @@ xfs_rmap_finish_one( {struct xfs_owner_info oinfo;struct xfs_mount *mp = tp->t_mountp; -struct xfs_btree_cur *rcur = *pcur; -struct xfs_buf *agbp =NULL ;xfs_agblock_t bno;bool unwritten;int error =0 ;
@@ -2649,38 +2689,26 @@ xfs_rmap_finish_one(* If we haven't gotten a cursor or the cursor AG doesn't match * the startblock, get one now. */ -if (rcur !=NULL && rcur->bc_group != ri->ri_group) { -xfs_btree_del_cursor (rcur,0 ); - rcur =NULL ; +if (*pcur !=NULL && (*pcur)->bc_group != ri->ri_group) { +xfs_btree_del_cursor (*pcur,0 ); *pcur =NULL ; } -if (rcur ==NULL ) { -struct xfs_perag *pag =to_perag (ri->ri_group); - -/* -* Refresh the freelist before we start changing the -* rmapbt, because a shape change could cause us to -* allocate blocks. -*/ - error =xfs_free_extent_fix_freelist (tp, pag, &agbp); -if (error) { -xfs_ag_mark_sick (pag,XFS_SICK_AG_AGFL ); +if (*pcur ==NULL ) { +if (ri->ri_group->xg_type ==XG_TYPE_RTG ) + error =xfs_rtrmap_finish_init_cursor (tp, ri, pcur); +else + error =xfs_rmap_finish_init_cursor (tp, ri, pcur); +if (error)return error; - } -if (XFS_IS_CORRUPT (tp->t_mountp, !agbp)) { -xfs_ag_mark_sick (pag,XFS_SICK_AG_AGFL ); -return -EFSCORRUPTED ; - } - - *pcur = rcur =xfs_rmapbt_init_cursor (mp, tp, agbp, pag); }xfs_rmap_ino_owner (&oinfo, ri->ri_owner, ri->ri_whichfork, ri->ri_bmap.br_startoff); unwritten = ri->ri_bmap.br_state ==XFS_EXT_UNWRITTEN ; - bno =XFS_FSB_TO_AGBNO (rcur->bc_mp, ri->ri_bmap.br_startblock); - error =__xfs_rmap_finish_intent (rcur, ri->ri_type, bno, + bno =xfs_fsb_to_gbno (mp, ri->ri_bmap.br_startblock, + ri->ri_group->xg_type); + error =__xfs_rmap_finish_intent (*pcur, ri->ri_type, bno, ri->ri_bmap.br_blockcount, &oinfo, unwritten);if (error)return error;
fs/xfs/libxfs/xfs_rtgroup.c +9 -0
@@ -202,6 +202,9 @@ xfs_rtgroup_lock( }else if (rtglock_flags &XFS_RTGLOCK_BITMAP_SHARED ) {xfs_ilock (rtg_bitmap (rtg),XFS_ILOCK_SHARED ); } + +if ((rtglock_flags &XFS_RTGLOCK_RMAP ) &&rtg_rmap (rtg)) +xfs_ilock (rtg_rmap (rtg),XFS_ILOCK_EXCL ); }/* Unlock metadata inodes associated with this rt group. */
@@ -214,6 +217,9 @@ xfs_rtgroup_unlock(ASSERT (!(rtglock_flags &XFS_RTGLOCK_BITMAP_SHARED ) || !(rtglock_flags &XFS_RTGLOCK_BITMAP )); +if ((rtglock_flags &XFS_RTGLOCK_RMAP ) &&rtg_rmap (rtg)) +xfs_iunlock (rtg_rmap (rtg),XFS_ILOCK_EXCL ); +if (rtglock_flags &XFS_RTGLOCK_BITMAP ) {xfs_iunlock (rtg_summary (rtg),XFS_ILOCK_EXCL );xfs_iunlock (rtg_bitmap (rtg),XFS_ILOCK_EXCL );
@@ -239,6 +245,9 @@ xfs_rtgroup_trans_join(xfs_trans_ijoin (tp,rtg_bitmap (rtg),XFS_ILOCK_EXCL );xfs_trans_ijoin (tp,rtg_summary (rtg),XFS_ILOCK_EXCL ); } + +if ((rtglock_flags &XFS_RTGLOCK_RMAP ) &&rtg_rmap (rtg)) +xfs_trans_ijoin (tp,rtg_rmap (rtg),XFS_ILOCK_EXCL ); }/* Retrieve rt group geometry. */
fs/xfs/libxfs/xfs_rtgroup.h +4 -1
@@ -265,9 +265,12 @@ int xfs_update_last_rtgroup_size(struct xfs_mount *mp,#define XFS_RTGLOCK_BITMAP (1U << 0)/* Lock the rt bitmap inode in shared mode */ #define XFS_RTGLOCK_BITMAP_SHARED (1U << 1) +/* Lock the rt rmap inode in exclusive mode */ +#define XFS_RTGLOCK_RMAP (1U << 2)#define XFS_RTGLOCK_ALL_FLAGS (XFS_RTGLOCK_BITMAP | \ - XFS_RTGLOCK_BITMAP_SHARED) + XFS_RTGLOCK_BITMAP_SHARED | \ + XFS_RTGLOCK_RMAP)void xfs_rtgroup_lock (struct xfs_rtgroup *rtg,unsigned int rtglock_flags);void xfs_rtgroup_unlock (struct xfs_rtgroup *rtg,unsigned int rtglock_flags);
PATCH 16/37 xfs: create routine to allocate and initialize a realtime rmap btree inode
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Create a library routine to allocate and initialize an empty realtime rmapbt inode. We'll use this for mkfs and repair.
--- fs/xfs/libxfs/xfs_rtgroup.c | 2 + fs/xfs/libxfs/xfs_rtrmap_btree.c | 54 ++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_rtrmap_btree.h | 5 ++++ fs/xfs/xfs_rtalloc.c | 12 +++++++- 4 files changed, 71 insertions(+), 2 deletions(-)
fs/xfs/libxfs/xfs_rtgroup.c +2 -0
@@ -33,6 +33,7 @@#include "xfs_rtbitmap.h" #include "xfs_metafile.h" #include "xfs_metadir.h" +#include "xfs_rtrmap_btree.h" /* Find the first usable fsblock in this rtgroup. */ static inline uint32_t
@@ -363,6 +364,7 @@ static const struct xfs_rtginode_ops xfs_rtginode_ops[XFS_RTGI_MAX] = {* rtrmapbt predicate here. */ .enabled = xfs_has_rmapbt, + .create = xfs_rtrmapbt_create, }, };
fs/xfs/libxfs/xfs_rtrmap_btree.c +54 -0
57 lines not on this page · raw message
fs/xfs/libxfs/xfs_rtrmap_btree.h +5 -0
@@ -193,4 +193,9 @@ void xfs_rtrmapbt_to_disk(struct xfs_mount *mp, struct xfs_btree_block *rblock, unsigned int dblocklen);void xfs_iflush_rtrmap (struct xfs_inode *ip,struct xfs_dinode *dip); +int xfs_rtrmapbt_create (struct xfs_rtgroup *rtg,struct xfs_inode *ip, +struct xfs_trans *tp,bool init); +int xfs_rtrmapbt_init_rtsb (struct xfs_mount *mp,struct xfs_rtgroup *rtg, +struct xfs_trans *tp); +#endif /* __XFS_RTRMAP_BTREE_H__ */
fs/xfs/xfs_rtalloc.c +10 -2
@@ -846,6 +846,13 @@ xfs_growfs_rt_init_rtsb( mp->m_rtsb_bp = rtsb_bp; error =xfs_bwrite (rtsb_bp);xfs_buf_unlock (rtsb_bp); +if (error) +return error; + +/* Initialize the rtrmap to reflect the rtsb. */ +if (rtg_rmap (args->rtg) !=NULL ) + error =xfs_rtrmapbt_init_rtsb (nargs->mp, args->rtg, args->tp); +return error; }
@@ -894,8 +901,9 @@ xfs_growfs_rt_bmblock( goto out_free; nargs.tp = args.tp; -xfs_rtgroup_lock (args.rtg,XFS_RTGLOCK_BITMAP ); -xfs_rtgroup_trans_join (args.tp, args.rtg,XFS_RTGLOCK_BITMAP ); +xfs_rtgroup_lock (args.rtg,XFS_RTGLOCK_BITMAP |XFS_RTGLOCK_RMAP ); +xfs_rtgroup_trans_join (args.tp, args.rtg, +XFS_RTGLOCK_BITMAP |XFS_RTGLOCK_RMAP );/* * Update the bitmap inode's size ondisk and incore. We need to update
PATCH 17/37 xfs: wire up getfsmap to the realtime reverse mapping btree
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Connect the getfsmap ioctl to the realtime rmapbt.
--- fs/xfs/xfs_fsmap.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+), 1 deletion(-)
fs/xfs/xfs_fsmap.c +173 -1
@@ -26,6 +26,7 @@#include "xfs_rtbitmap.h" #include "xfs_ag.h" #include "xfs_rtgroup.h" +#include "xfs_rtrmap_btree.h" /* Convert an xfs_fsmap to an fsmap. */ static void
@@ -832,6 +833,174 @@ xfs_getfsmap_rtdev_rtbitmap( return error; } + +/* Transform a realtime rmapbt record into a fsmap */ +STATIC int +xfs_getfsmap_rtdev_rmapbt_helper ( +struct xfs_btree_cur *cur, +const struct xfs_rmap_irec *rec, +void *priv) +{ +struct xfs_fsmap_irec frec = { + .owner = rec->rm_owner, + .offset = rec->rm_offset, + .rm_flags = rec->rm_flags, + .rec_key = rec->rm_startblock, + }; +struct xfs_getfsmap_info *info = priv; + +return xfs_getfsmap_group_helper (info, cur->bc_tp, cur->bc_group, + rec->rm_startblock, rec->rm_blockcount, &frec); +} + +/* Actually query the rtrmap btree. */ +STATIC int +xfs_getfsmap_rtdev_rmapbt_query ( +struct xfs_trans *tp, +struct xfs_getfsmap_info *info, +struct xfs_btree_cur **curpp) +{ +struct xfs_rtgroup *rtg =to_rtg (info->group); + +/* Query the rtrmapbt */ +xfs_rtgroup_lock (rtg,XFS_RTGLOCK_RMAP ); + *curpp =xfs_rtrmapbt_init_cursor (tp, rtg); +return xfs_rmap_query_range (*curpp, &info->low, &info->high, + xfs_getfsmap_rtdev_rmapbt_helper, info); +} + +/* Execute a getfsmap query against the realtime device rmapbt. */ +STATIC int +xfs_getfsmap_rtdev_rmapbt ( +struct xfs_trans *tp, +const struct xfs_fsmap *keys, +struct xfs_getfsmap_info *info) +{ +struct xfs_mount *mp = tp->t_mountp; +struct xfs_rtgroup *rtg =NULL ; +struct xfs_btree_cur *bt_cur =NULL ; +xfs_rtblock_t start_rtb; +xfs_rtblock_t end_rtb; +xfs_rgnumber_t start_rg, end_rg; +uint64_t eofs; +int error =0 ; + + eofs =XFS_FSB_TO_BB (mp, mp->m_sb.sb_rblocks); +if (keys[0 ].fmr_physical >= eofs) +return 0 ; + start_rtb =xfs_daddr_to_rtb (mp, keys[0 ].fmr_physical); + end_rtb =xfs_daddr_to_rtb (mp,min (eofs -1 , keys[1 ].fmr_physical)); + + info->missing_owner =XFS_FMR_OWN_FREE ; + +/* +* Convert the fsmap low/high keys to rtgroup based keys. Initialize +* low to the fsmap low key and max out the high key to the end +* of the rtgroup. +*/ + info->low.rm_offset =XFS_BB_TO_FSBT (mp, keys[0 ].fmr_offset); + error =xfs_fsmap_owner_to_rmap (&info->low, &keys[0 ]); +if (error) +return error; + info->low.rm_blockcount =XFS_BB_TO_FSBT (mp, keys[0 ].fmr_length); +xfs_getfsmap_set_irec_flags (&info->low, &keys[0 ]); + +/* Adjust the low key if we are continuing from where we left off. */ +if (info->low.rm_blockcount ==0 ) { +/* No previous record from which to continue */ + }else if (rmap_not_shareable (mp, &info->low)) { +/* Last record seen was an unshareable extent */ + info->low.rm_owner =0 ; + info->low.rm_offset =0 ; + + start_rtb += info->low.rm_blockcount; +if (xfs_rtb_to_daddr (mp, start_rtb) >= eofs) +return 0 ; + }else { +/* Last record seen was a shareable file data extent */ + info->low.rm_offset += info->low.rm_blockcount; + } + info->low.rm_startblock =xfs_rtb_to_rgbno (mp, start_rtb); + + info->high.rm_startblock =-1U ; + info->high.rm_owner =ULLONG_MAX ; + info->high.rm_offset =ULLONG_MAX ; + info->high.rm_blockcount =0 ; + info->high.rm_flags =XFS_RMAP_KEY_FLAGS |XFS_RMAP_REC_FLAGS ; + + start_rg =xfs_rtb_to_rgno (mp, start_rtb); + end_rg =xfs_rtb_to_rgno (mp, end_rtb); + +while ((rtg =xfs_rtgroup_next_range (mp, rtg, start_rg, end_rg))) { +/* +* Set the rtgroup high key from the fsmap high key if this +* is the last rtgroup that we're querying. +*/ + info->group =rtg_group (rtg); +if (rtg_rgno (rtg) == end_rg) { + info->high.rm_startblock = +xfs_rtb_to_rgbno (mp, end_rtb); + info->high.rm_offset = +XFS_BB_TO_FSBT (mp, keys[1 ].fmr_offset); + error =xfs_fsmap_owner_to_rmap (&info->high, &keys[1 ]); +if (error) +break ; +xfs_getfsmap_set_irec_flags (&info->high, &keys[1 ]); + } + +if (bt_cur) { +xfs_rtgroup_unlock (to_rtg (bt_cur->bc_group), +XFS_RTGLOCK_RMAP ); +xfs_btree_del_cursor (bt_cur,XFS_BTREE_NOERROR ); + bt_cur =NULL ; + } + +trace_xfs_fsmap_low_group_key (mp, info->dev,rtg_rgno (rtg), + &info->low); +trace_xfs_fsmap_high_group_key (mp, info->dev,rtg_rgno (rtg), + &info->high); + + error =xfs_getfsmap_rtdev_rmapbt_query (tp, info, &bt_cur); +if (error) +break ; + +/* +* Set the rtgroup low key to the start of the rtgroup prior to +* moving on to the next rtgroup. +*/ +if (rtg_rgno (rtg) == start_rg) +memset (&info->low,0 ,sizeof (info->low)); + +/* +* If this is the last rtgroup, report any gap at the end of it +* before we drop the reference to the perag when the loop +* terminates. +*/ +if (rtg_rgno (rtg) == end_rg) { + info->last = true; + error =xfs_getfsmap_rtdev_rmapbt_helper (bt_cur, + &info->high, info); +if (error) +break ; + } + info->group =NULL ; + } + +if (bt_cur) { +xfs_rtgroup_unlock (to_rtg (bt_cur->bc_group), +XFS_RTGLOCK_RMAP ); +xfs_btree_del_cursor (bt_cur, error <0 ?XFS_BTREE_ERROR : +XFS_BTREE_NOERROR ); + } + +/* loop termination case */ +if (rtg) { + info->group =NULL ; +xfs_rtgroup_rele (rtg); + } + +return error; +}#endif /* CONFIG_XFS_RT */ /* Do we recognize the device? */
@@ -971,7 +1140,10 @@ xfs_getfsmap(if (mp->m_rtdev_targp) { handlers[2 ].nr_sectors =XFS_FSB_TO_BB (mp, mp->m_sb.sb_rblocks); handlers[2 ].dev =new_encode_dev (mp->m_rtdev_targp->bt_dev); - handlers[2 ].fn = xfs_getfsmap_rtdev_rtbitmap; +if (use_rmap) + handlers[2 ].fn = xfs_getfsmap_rtdev_rmapbt; +else + handlers[2 ].fn = xfs_getfsmap_rtdev_rtbitmap; }#endif /* CONFIG_XFS_RT */
PATCH 18/37 xfs: check that the rtrmapbt maxlevels doesn't increase when growing fs
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
The size of filesystem transaction reservations depends on the maximum height (maxlevels) of the realtime btrees. Since we don't want a grow operation to increase the reservation size enough that we'll fail the minimum log size checks on the next mount, constrain growfs operations if they would cause an increase in those maxlevels.
--- fs/xfs/xfs_fsops.c | 11 +++++++++++ fs/xfs/xfs_rtalloc.c | 25 ++++++++++++++++++------- fs/xfs/xfs_rtalloc.h | 10 ++++++++++ fs/xfs/xfs_trace.h | 21 +++++++++++++++++++++ 4 files changed, 60 insertions(+), 7 deletions(-)
fs/xfs/xfs_fsops.c +11 -0
@@ -22,6 +22,7 @@#include "xfs_ag_resv.h" #include "xfs_trace.h" #include "xfs_rtalloc.h" +#include "xfs_rtrmap_btree.h" /* * Write new AG headers to disk. Non-transactional, but need to be
@@ -114,6 +115,12 @@ xfs_growfs_data_private(xfs_buf_relse (bp); } +/* Make sure the new fs size won't cause problems with the log. */ + error =xfs_growfs_check_rtgeom (mp, nb, mp->m_sb.sb_rblocks, + mp->m_sb.sb_rextsize); +if (error) +return error; + nb_div = nb; nb_mod =do_div (nb_div, mp->m_sb.sb_agblocks);if (nb_mod && nb_mod >=XFS_MIN_AG_BLOCKS )
@@ -221,7 +228,11 @@ xfs_growfs_data_private( error =xfs_fs_reserve_ag_blocks (mp);if (error == -ENOSPC ) error =0 ; + +/* Compute new maxlevels for rt btrees. */ +xfs_rtrmapbt_compute_maxlevels (mp); } +return error; out_trans_cancel:
fs/xfs/xfs_rtalloc.c +18 -7
@@ -989,9 +989,11 @@ xfs_growfs_rt_bmblock( goto out_free;/* -* Ensure the mount RT feature flag is now set. +* Ensure the mount RT feature flag is now set, and compute new +* maxlevels for rt btrees. */ mp->m_features |=XFS_FEAT_REALTIME ; +xfs_rtrmapbt_compute_maxlevels (mp);kfree (nmp);return 0 ;
@@ -1159,29 +1161,37 @@ xfs_growfs_rtg(return error; } -static int +int xfs_growfs_check_rtgeom (const struct xfs_mount *mp, +xfs_rfsblock_t dblocks,xfs_rfsblock_t rblocks,xfs_extlen_t rextsize) { +xfs_extlen_t min_logfsbs;struct xfs_mount *nmp; -int error =0 ; nmp =xfs_growfs_rt_alloc_fake_mount (mp, rblocks, rextsize);if (!nmp)return -ENOMEM ; + nmp->m_sb.sb_dblocks = dblocks; + +xfs_rtrmapbt_compute_maxlevels (nmp); +xfs_trans_resv_calc (nmp,M_RES (nmp));/* * New summary size can't be more than half the size of the log. This * prevents us from getting a log overflow, since we'll log basically * the whole summary file at once. */ -if (nmp->m_rsumblocks > (mp->m_sb.sb_logblocks >>1 )) - error = -EINVAL ; + min_logfsbs =min_t (xfs_extlen_t,xfs_log_calc_minimum_size (nmp), + nmp->m_rsumblocks *2 );kfree (nmp); -return error; + +if (min_logfsbs > mp->m_sb.sb_logblocks) +return -EINVAL ; +return 0 ; }/*
@@ -1300,7 +1310,8 @@ xfs_growfs_rt( goto out_unlock;/* Make sure the new fs size won't cause problems with the log. */ - error =xfs_growfs_check_rtgeom (mp, in->newblocks, in->extsize); + error =xfs_growfs_check_rtgeom (mp, mp->m_sb.sb_dblocks, in->newblocks, + in->extsize);if (error) goto out_unlock;
fs/xfs/xfs_rtalloc.h +10 -0
@@ -46,6 +46,8 @@ xfs_growfs_rt( xfs_growfs_rt_t *in); /* user supplied growfs struct */int xfs_rtalloc_reinit_frextents (struct xfs_mount *mp); +int xfs_growfs_check_rtgeom (const struct xfs_mount *mp,xfs_rfsblock_t dblocks, +xfs_rfsblock_t rblocks,xfs_agblock_t rextsize);#else # define xfs_growfs_rt (mp,in) (-ENOSYS)# define xfs_rtalloc_reinit_frextents (m) (0)
@@ -65,6 +67,14 @@ xfs_rtmount_init(# define xfs_rtunmount_inodes (m)# define xfs_rt_resv_free (mp) ((void)0)# define xfs_rt_resv_init (mp) (0) + +static inline int +xfs_growfs_check_rtgeom (const struct xfs_mount *mp, +xfs_rfsblock_t dblocks,xfs_rfsblock_t rblocks, +xfs_extlen_t rextsize) +{ +return 0 ; +}#endif /* CONFIG_XFS_RT */ #endif /* __XFS_RTALLOC_H__ */
fs/xfs/xfs_trace.h +21 -0
@@ -5622,6 +5622,27 @@ DEFINE_METAFILE_RESV_EVENT(xfs_metafile_resv_free_space);DEFINE_METAFILE_RESV_EVENT (xfs_metafile_resv_critical);DEFINE_INODE_ERROR_EVENT (xfs_metafile_resv_init_error); +#ifdef CONFIG_XFS_RT +TRACE_EVENT (xfs_growfs_check_rtgeom, + TP_PROTO(const struct xfs_mount *mp, unsigned int min_logfsbs), +TP_ARGS (mp, min_logfsbs), +TP_STRUCT__entry ( + __field(dev_t, dev) + __field(unsigned int, logblocks) + __field(unsigned int, min_logfsbs) + ), +TP_fast_assign ( + __entry->dev = mp->m_super->s_dev; + __entry->logblocks = mp->m_sb.sb_logblocks; + __entry->min_logfsbs = min_logfsbs; + ), +TP_printk ("dev %d:%d logblocks %u min_logfsbs %u" , +MAJOR (__entry->dev),MINOR (__entry->dev), + __entry->logblocks, + __entry->min_logfsbs) +); +#endif /* CONFIG_XFS_RT */ +#endif /* _TRACE_XFS_H */ #undef TRACE_INCLUDE_PATH
PATCH 19/37 xfs: report realtime rmap btree corruption errors to the health system
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Whenever we encounter corrupt realtime rmap btree blocks, we should report that to the health monitoring system for later reporting.
--- fs/xfs/libxfs/xfs_btree.h | 2 +- fs/xfs/libxfs/xfs_fs.h | 1 + fs/xfs/libxfs/xfs_health.h | 4 +++- fs/xfs/libxfs/xfs_rtgroup.c | 1 + fs/xfs/libxfs/xfs_rtrmap_btree.c | 10 ++++++++-- fs/xfs/xfs_health.c | 1 + 6 files changed, 15 insertions(+), 4 deletions(-)
fs/xfs/libxfs/xfs_btree.h +1 -1
@@ -135,7 +135,7 @@ struct xfs_btree_ops {/* offset of btree stats array */ unsigned int statoff; -/* sick mask for health reporting (only for XFS_BTREE_TYPE_AG) */ +/* sick mask for health reporting (not for bmap btrees) */ unsigned int sick_mask;/* cursor operations */
fs/xfs/libxfs/xfs_fs.h +1 -0
@@ -993,6 +993,7 @@ struct xfs_rtgroup_geometry {#define XFS_RTGROUP_GEOM_SICK_SUPER (1U << 0)/* superblock */ #define XFS_RTGROUP_GEOM_SICK_BITMAP (1U << 1)/* rtbitmap */ #define XFS_RTGROUP_GEOM_SICK_SUMMARY (1U << 2)/* rtsummary */ +#define XFS_RTGROUP_GEOM_SICK_RMAPBT (1U << 3)/* reverse mappings */ /* * ioctl commands that are used by Linux filesystems
fs/xfs/libxfs/xfs_health.h +3 -1
@@ -70,6 +70,7 @@ struct xfs_rtgroup;#define XFS_SICK_RG_SUPER (1 << 0)/* rt group superblock */ #define XFS_SICK_RG_BITMAP (1 << 1)/* rt group bitmap */ #define XFS_SICK_RG_SUMMARY (1 << 2)/* rt groups summary */ +#define XFS_SICK_RG_RMAPBT (1 << 3)/* reverse mappings */ /* Observable health issues for AG metadata. */ #define XFS_SICK_AG_SB (1 << 0)/* superblock */
@@ -115,7 +116,8 @@ struct xfs_rtgroup;#define XFS_SICK_RG_PRIMARY (XFS_SICK_RG_SUPER | \ XFS_SICK_RG_BITMAP | \ - XFS_SICK_RG_SUMMARY) + XFS_SICK_RG_SUMMARY | \ + XFS_SICK_RG_RMAPBT)#define XFS_SICK_AG_PRIMARY (XFS_SICK_AG_SB | \ XFS_SICK_AG_AGF | \
fs/xfs/libxfs/xfs_rtgroup.c +1 -0
@@ -357,6 +357,7 @@ static const struct xfs_rtginode_ops xfs_rtginode_ops[XFS_RTGI_MAX] = { [XFS_RTGI_RMAP] = { .name = "rmap", .metafile_type = XFS_METAFILE_RTRMAP, + .sick = XFS_SICK_RG_RMAPBT, .fmt_mask = 1U << XFS_DINODE_FMT_META_BTREE,/* * growfs must create the rtrmap inodes before adding a
fs/xfs/libxfs/xfs_rtrmap_btree.c +8 -2
@@ -27,6 +27,7 @@#include "xfs_extent_busy.h" #include "xfs_rtgroup.h" #include "xfs_bmap.h" +#include "xfs_health.h" static struct kmem_cache *xfs_rtrmapbt_cur_cache;
@@ -496,6 +497,7 @@ const struct xfs_btree_ops xfs_rtrmapbt_ops = { .lru_refs = XFS_RMAP_BTREE_REF, .statoff = XFS_STATS_CALC_INDEX(xs_rtrmap_2), + .sick_mask = XFS_SICK_RG_RMAPBT, .dup_cursor = xfs_rtrmapbt_dup_cursor, .alloc_block = xfs_btree_alloc_metafile_block,
@@ -755,16 +757,20 @@ xfs_iformat_rtrmap(* growfs must create the rtrmap inodes before adding a realtime volume * to the filesystem, so we cannot use the rtrmapbt predicate here. */ -if (!xfs_has_rmapbt (ip->i_mount)) +if (!xfs_has_rmapbt (ip->i_mount)) { +xfs_inode_mark_sick (ip,XFS_SICK_INO_CORE );return -EFSCORRUPTED ; + } dsize =XFS_DFORK_SIZE (dip, mp,XFS_DATA_FORK ); numrecs =be16_to_cpu (dfp->bb_numrecs); level =be16_to_cpu (dfp->bb_level);if (level > mp->m_rtrmap_maxlevels || -xfs_rtrmap_droot_space_calc (level, numrecs) > dsize) +xfs_rtrmap_droot_space_calc (level, numrecs) > dsize) { +xfs_inode_mark_sick (ip,XFS_SICK_INO_CORE );return -EFSCORRUPTED ; + } broot =xfs_broot_alloc (xfs_ifork_ptr (ip,XFS_DATA_FORK ),xfs_rtrmap_broot_space_calc (mp, level, numrecs));
fs/xfs/xfs_health.c +1 -0
@@ -447,6 +447,7 @@ static const struct ioctl_sick_map rtgroup_map[] = { { XFS_SICK_RG_SUPER, XFS_RTGROUP_GEOM_SICK_SUPER }, { XFS_SICK_RG_BITMAP, XFS_RTGROUP_GEOM_SICK_BITMAP }, { XFS_SICK_RG_SUMMARY, XFS_RTGROUP_GEOM_SICK_SUMMARY }, + { XFS_SICK_RG_RMAPBT, XFS_RTGROUP_GEOM_SICK_RMAPBT }, };/* Fill out rtgroup geometry health info. */
PATCH 20/37 xfs: allow queued realtime intents to drain before scrubbing
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
When a writer thread executes a chain of log intent items for the realtime volume, the ILOCKs taken during each step are for each rt metadata file, not the entire rt volume itself. Although scrub takes all rt metadata ILOCKs, this isn't sufficient to guard against scrub checking the rt volume while that writer thread is in the middle of finishing a chain because there's no higher level locking primitive guarding the realtime volume.
When there's a collision, cross-referencing between data structures (e.g. rtrmapbt and rtrefcountbt) yields false corruption events; if repair is running, this results in incorrect repairs, which is catastrophic.
Fix this by adding to the mount structure the same drain that we use to protect scrub against concurrent AG updates, but this time for the realtime volume.
--- fs/xfs/scrub/bmap.c | 7 ++++ fs/xfs/scrub/common.c | 72 ++++++++++++++++++++++++++++++++++++++++++++-- fs/xfs/scrub/common.h | 5 ++- fs/xfs/scrub/rgsuper.c | 4 ++- fs/xfs/scrub/rtbitmap.c | 8 ++++- fs/xfs/scrub/rtsummary.c | 5 +++ fs/xfs/scrub/scrub.c | 2 + fs/xfs/xfs_drain.c | 20 ++++++------- fs/xfs/xfs_drain.h | 7 +++- 9 files changed, 108 insertions(+), 22 deletions(-)
fs/xfs/scrub/bmap.c +6 -1
@@ -324,10 +324,15 @@ xchk_bmap_rt_iextent_xref( irec->br_startoff, &error))return ; -xchk_rtgroup_lock (&info->sc->sr,XCHK_RTGLOCK_ALL ); + error =xchk_rtgroup_lock (info->sc, &info->sc->sr,XCHK_RTGLOCK_ALL ); +if (!xchk_fblock_process_error (info->sc, info->whichfork, + irec->br_startoff, &error)) + goto out_free; +xchk_xref_is_used_rt_space (info->sc, irec->br_startblock, irec->br_blockcount); +out_free:xchk_rtgroup_free (info->sc, &info->sc->sr); }
fs/xfs/scrub/common.c +69 -3
89 lines not on this page · raw message
fs/xfs/scrub/common.h +3 -2
@@ -141,12 +141,13 @@ xchk_rtgroup_init_existing( return error == -ENOENT ? -EFSCORRUPTED : error; } -void xchk_rtgroup_lock (struct xchk_rt *sr,unsigned int rtglock_flags); +int xchk_rtgroup_lock (struct xfs_scrub *sc,struct xchk_rt *sr, +unsigned int rtglock_flags);void xchk_rtgroup_free (struct xfs_scrub *sc,struct xchk_rt *sr);#else # define xchk_rtgroup_init (sc, rgno, sr) (-EFSCORRUPTED)# define xchk_rtgroup_init_existing (sc, rgno, sr) (-EFSCORRUPTED) -# define xchk_rtgroup_lock (sc, lockflags) do { } while (0) +# define xchk_rtgroup_lock (sc, sr, lockflags) (-EFSCORRUPTED)# define xchk_rtgroup_free (sc, sr) do { } while (0)#endif /* CONFIG_XFS_RT */
fs/xfs/scrub/rgsuper.c +3 -1
@@ -61,7 +61,9 @@ xchk_rgsuperblock(if (!xchk_xref_process_error (sc,0 ,0 , &error))return error; -xchk_rtgroup_lock (&sc->sr,XFS_RTGLOCK_BITMAP_SHARED ); + error =xchk_rtgroup_lock (sc, &sc->sr,XFS_RTGLOCK_BITMAP_SHARED ); +if (error) +return error;/* * Since we already validated the rt superblock at mount time, we don't
fs/xfs/scrub/rtbitmap.c +7 -1
@@ -30,6 +30,9 @@ xchk_setup_rtbitmap(struct xchk_rtbitmap *rtb;int error; +if (xchk_need_intent_drain (sc)) +xchk_fsgates_enable (sc,XCHK_FSGATES_DRAIN ); + rtb =kzalloc (sizeof (struct xchk_rtbitmap ),XCHK_GFP_FLAGS );if (!rtb)return -ENOMEM ;
@@ -57,12 +60,15 @@ xchk_setup_rtbitmap(if (error)return error; + error =xchk_rtgroup_lock (sc, &sc->sr,XCHK_RTGLOCK_ALL ); +if (error) +return error; +/* * Now that we've locked the rtbitmap, we can't race with growfsrt * trying to expand the bitmap or change the size of the rt volume. * Hence it is safe to compute and check the geometry values. */ -xchk_rtgroup_lock (&sc->sr,XFS_RTGLOCK_BITMAP );if (mp->m_sb.sb_rblocks) { rtb->rextents =xfs_blen_to_rtbxlen (mp, mp->m_sb.sb_rblocks); rtb->rextslog =xfs_compute_rextslog (rtb->rextents);
fs/xfs/scrub/rtsummary.c +4 -1
@@ -89,6 +89,10 @@ xchk_setup_rtsummary(if (error)return error; + error =xchk_rtgroup_lock (sc, &sc->sr,XFS_RTGLOCK_BITMAP ); +if (error) +return error; +/* * Now that we've locked the rtbitmap and rtsummary, we can't race with * growfsrt trying to expand the summary or change the size of the rt
@@ -99,7 +103,6 @@ xchk_setup_rtsummary(* exclusively here. If we ever start caring about running concurrent * fsmap with scrub this could be changed. */ -xchk_rtgroup_lock (&sc->sr,XFS_RTGLOCK_BITMAP );if (mp->m_sb.sb_rblocks) { rts->rextents =xfs_blen_to_rtbxlen (mp, mp->m_sb.sb_rblocks); rts->rbmblocks =xfs_rtbitmap_blockcount (mp);
fs/xfs/scrub/scrub.c +1 -1
@@ -164,7 +164,7 @@ xchk_fsgates_disable(trace_xchk_fsgates_disable (sc, sc->flags &XCHK_FSGATES_ALL );if (sc->flags &XCHK_FSGATES_DRAIN ) -xfs_drain_wait_disable (); +xfs_defer_drain_wait_disable ();if (sc->flags &XCHK_FSGATES_QUOTA )xfs_dqtrx_hook_disable ();
fs/xfs/xfs_drain.c +10 -10
@@ -13,28 +13,28 @@#include "xfs_trace.h" /* -* Use a static key here to reduce the overhead of xfs_drain_rele. If the -* compiler supports jump labels, the static branch will be replaced by a nop -* sled when there are no xfs_drain_wait callers. Online fsck is currently -* the only caller, so this is a reasonable tradeoff. +* Use a static key here to reduce the overhead of xfs_defer_drain_rele. If +* the compiler supports jump labels, the static branch will be replaced by a +* nop sled when there are no xfs_defer_drain_wait callers. Online fsck is +* currently the only caller, so this is a reasonable tradeoff. * * Note: Patching the kernel code requires taking the cpu hotplug lock. Other * parts of the kernel allocate memory with that lock held, which means that * XFS callers cannot hold any locks that might be used by memory reclaim or * writeback when calling the static_branch_{inc,dec} functions. */ -static DEFINE_STATIC_KEY_FALSE (xfs_drain_waiter_gate); +static DEFINE_STATIC_KEY_FALSE (xfs_defer_drain_waiter_gate);void -xfs_drain_wait_disable (void ) +xfs_defer_drain_wait_disable (void ) { -static_branch_dec (&xfs_drain_waiter_gate); +static_branch_dec (&xfs_defer_drain_waiter_gate); }void -xfs_drain_wait_enable (void ) +xfs_defer_drain_wait_enable (void ) { -static_branch_inc (&xfs_drain_waiter_gate); +static_branch_inc (&xfs_defer_drain_waiter_gate); }void
@@ -71,7 +71,7 @@ static inline bool has_waiters(struct wait_queue_head *wq_head)static inline void xfs_defer_drain_rele (struct xfs_defer_drain *dr) {if (atomic_dec_and_test (&dr->dr_count) && -static_branch_unlikely (&xfs_drain_waiter_gate) && +static_branch_unlikely (&xfs_defer_drain_waiter_gate) &&has_waiters (&dr->dr_waiters))wake_up (&dr->dr_waiters); }
fs/xfs/xfs_drain.h +5 -2
@@ -26,8 +26,8 @@ struct xfs_defer_drain {void xfs_defer_drain_init (struct xfs_defer_drain *dr);void xfs_defer_drain_free (struct xfs_defer_drain *dr); -void xfs_drain_wait_disable (void ); -void xfs_drain_wait_enable (void ); +void xfs_defer_drain_wait_disable (void ); +void xfs_defer_drain_wait_enable (void );/* * Deferred Work Intent Drains
@@ -61,6 +61,9 @@ void xfs_drain_wait_enable(void);* All functions that create work items must increment the intent counter as * soon as the item is added to the transaction and cannot drop the counter * until the item is finished or cancelled. +* +* The same principles apply to realtime groups because the rt metadata inode +* ILOCKs are not held across transaction rolls. */ struct xfs_group *xfs_group_intent_get (struct xfs_mount *mp,xfs_fsblock_t fsbno,enum xfs_group_type type);
PATCH 21/37 xfs: scrub the realtime rmapbt
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Check the realtime reverse mapping btree against the rtbitmap, and modify the rtbitmap scrub to check against the rtrmapbt.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_fs.h | 3 - fs/xfs/scrub/common.c | 86 ++++++++++++++++++++ fs/xfs/scrub/common.h | 10 ++ fs/xfs/scrub/health.c | 1 fs/xfs/scrub/inode.c | 6 - fs/xfs/scrub/inode_repair.c | 7 +- fs/xfs/scrub/repair.c | 1 fs/xfs/scrub/rtrmap.c | 184 +++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 9 ++ fs/xfs/scrub/scrub.h | 5 + fs/xfs/scrub/stats.c | 1 fs/xfs/scrub/trace.h | 4 + 13 files changed, 307 insertions(+), 11 deletions(-) create mode 100644 fs/xfs/scrub/rtrmap.c
fs/xfs/Makefile +1 -0
@@ -194,6 +194,7 @@ xfs-$(CONFIG_XFS_ONLINE_SCRUB_STATS) += scrub/stats.o xfs-$(CONFIG_XFS_RT) += $(addprefix scrub/, \ rgsuper.o \ rtbitmap.o \ + rtrmap.o \ rtsummary.o \ )
fs/xfs/libxfs/xfs_fs.h +2 -1
@@ -737,9 +737,10 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_DIRTREE 28/* directory tree structure */ #define XFS_SCRUB_TYPE_METAPATH 29/* metadata directory tree paths */ #define XFS_SCRUB_TYPE_RGSUPER 30/* realtime superblock */ +#define XFS_SCRUB_TYPE_RTRMAPBT 31/* rtgroup reverse mapping btree */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 31 +#define XFS_SCRUB_TYPE_NR 32/* * This special type code only applies to the vectored scrub implementation.
fs/xfs/scrub/common.c +86 -0
110 lines not on this page · raw message
fs/xfs/scrub/common.h +9 -1
@@ -63,6 +63,7 @@ static inline int xchk_setup_nothing(struct xfs_scrub *sc)/* Setup functions */ int xchk_setup_agheader (struct xfs_scrub *sc);int xchk_setup_fs (struct xfs_scrub *sc); +int xchk_setup_rt (struct xfs_scrub *sc);int xchk_setup_ag_allocbt (struct xfs_scrub *sc);int xchk_setup_ag_iallocbt (struct xfs_scrub *sc);int xchk_setup_ag_rmapbt (struct xfs_scrub *sc);
@@ -80,10 +81,12 @@ int xchk_setup_metapath(struct xfs_scrub *sc);int xchk_setup_rtbitmap (struct xfs_scrub *sc);int xchk_setup_rtsummary (struct xfs_scrub *sc);int xchk_setup_rgsuperblock (struct xfs_scrub *sc); +int xchk_setup_rtrmapbt (struct xfs_scrub *sc);#else # define xchk_setup_rtbitmap xchk_setup_nothing# define xchk_setup_rtsummary xchk_setup_nothing# define xchk_setup_rgsuperblock xchk_setup_nothing +# define xchk_setup_rtrmapbt xchk_setup_nothing#endif #ifdef CONFIG_XFS_QUOTA int xchk_ino_dqattach (struct xfs_scrub *sc);
@@ -125,7 +128,8 @@ xchk_ag_init_existing(#ifdef CONFIG_XFS_RT /* All the locks we need to check an rtgroup. */ -#define XCHK_RTGLOCK_ALL (XFS_RTGLOCK_BITMAP) +#define XCHK_RTGLOCK_ALL (XFS_RTGLOCK_BITMAP | \ + XFS_RTGLOCK_RMAP)int xchk_rtgroup_init (struct xfs_scrub *sc,xfs_rgnumber_t rgno,struct xchk_rt *sr);
@@ -143,11 +147,13 @@ xchk_rtgroup_init_existing(int xchk_rtgroup_lock (struct xfs_scrub *sc,struct xchk_rt *sr,unsigned int rtglock_flags); +void xchk_rtgroup_btcur_free (struct xchk_rt *sr);void xchk_rtgroup_free (struct xfs_scrub *sc,struct xchk_rt *sr);#else # define xchk_rtgroup_init (sc, rgno, sr) (-EFSCORRUPTED)# define xchk_rtgroup_init_existing (sc, rgno, sr) (-EFSCORRUPTED)# define xchk_rtgroup_lock (sc, sr, lockflags) (-EFSCORRUPTED) +# define xchk_rtgroup_btcur_free (sr) do { } while (0)# define xchk_rtgroup_free (sc, sr) do { } while (0)#endif /* CONFIG_XFS_RT */
@@ -275,6 +281,8 @@ void xchk_fsgates_enable(struct xfs_scrub *sc, unsigned int scrub_fshooks);int xchk_inode_is_allocated (struct xfs_scrub *sc,xfs_agino_t agino,bool *inuse); +int xchk_inode_count_blocks (struct xfs_scrub *sc,int whichfork, +xfs_extnum_t *nextents,xfs_filblks_t *count);bool xchk_inode_is_dirtree_root (const struct xfs_inode *ip);bool xchk_inode_is_sb_rooted (const struct xfs_inode *ip);
fs/xfs/scrub/health.c +1 -0
@@ -114,6 +114,7 @@ static const struct xchk_health_map type_to_health_flag[XFS_SCRUB_TYPE_NR] = { [XFS_SCRUB_TYPE_DIRTREE] = { XHG_INO, XFS_SICK_INO_DIRTREE }, [XFS_SCRUB_TYPE_METAPATH] = { XHG_FS, XFS_SICK_FS_METAPATH }, [XFS_SCRUB_TYPE_RGSUPER] = { XHG_RTGROUP, XFS_SICK_RG_SUPER }, + [XFS_SCRUB_TYPE_RTRMAPBT] = { XHG_RTGROUP, XFS_SICK_RG_RMAPBT }, };/* Return the health status mask for this scrub type. */
fs/xfs/scrub/inode.c +2 -4
@@ -690,15 +690,13 @@ xchk_inode_xref_bmap(return ;/* Walk all the extents to check nextents/naextents/nblocks. */ - error =xfs_bmap_count_blocks (sc->tp, sc->ip,XFS_DATA_FORK , - &nextents, &count); + error =xchk_inode_count_blocks (sc,XFS_DATA_FORK , &nextents, &count);if (!xchk_should_check_xref (sc, &error,NULL ))return ;if (nextents <xfs_dfork_data_extents (dip))xchk_ino_xref_set_corrupt (sc, sc->ip->i_ino); - error =xfs_bmap_count_blocks (sc->tp, sc->ip,XFS_ATTR_FORK , - &nextents, &acount); + error =xchk_inode_count_blocks (sc,XFS_ATTR_FORK , &nextents, &acount);if (!xchk_should_check_xref (sc, &error,NULL ))return ;if (nextents !=xfs_dfork_attr_extents (dip))
fs/xfs/scrub/inode_repair.c +3 -4
@@ -1536,8 +1536,7 @@ xrep_inode_blockcounts(trace_xrep_inode_blockcounts (sc);/* Set data fork counters from the data fork mappings. */ - error =xfs_bmap_count_blocks (sc->tp, sc->ip,XFS_DATA_FORK , - &nextents, &count); + error =xchk_inode_count_blocks (sc,XFS_DATA_FORK , &nextents, &count);if (error)return error;if (xfs_is_reflink_inode (sc->ip)) {
@@ -1561,8 +1560,8 @@ xrep_inode_blockcounts(/* Set attr fork counters from the attr fork mappings. */ ifp =xfs_ifork_ptr (sc->ip,XFS_ATTR_FORK );if (ifp) { - error =xfs_bmap_count_blocks (sc->tp, sc->ip,XFS_ATTR_FORK , - &nextents, &acount); + error =xchk_inode_count_blocks (sc,XFS_ATTR_FORK , &nextents, + &acount);if (error)return error;if (count >= sc->mp->m_sb.sb_dblocks)
fs/xfs/scrub/repair.c +1 -0
@@ -62,6 +62,7 @@ xrep_attempt(trace_xrep_attempt (XFS_I (file_inode (sc->file)), sc->sm, error);xchk_ag_btcur_free (&sc->sa); +xchk_rtgroup_btcur_free (&sc->sr);/* Repair whatever's broken. */ ASSERT (sc->ops->repair);
fs/xfs/scrub/rtrmap.c new file +184 -0
184 lines not on this page · raw message
fs/xfs/scrub/scrub.c +9 -0
@@ -218,6 +218,8 @@ xchk_teardown( int error) {xchk_ag_free (sc, &sc->sa); +xchk_rtgroup_btcur_free (&sc->sr); +if (sc->tp) {if (error ==0 && (sc->sm->sm_flags &XFS_SCRUB_IFLAG_REPAIR )) error =xfs_trans_commit (sc->tp);
@@ -458,6 +460,13 @@ static const struct xchk_meta_ops meta_scrub_ops[] = { .has = xfs_has_rtsb, .repair = xrep_rgsuperblock, }, + [XFS_SCRUB_TYPE_RTRMAPBT] = { /* realtime group rmapbt */ + .type = ST_RTGROUP, + .setup = xchk_setup_rtrmapbt, + .scrub = xchk_rtrmapbt, + .has = xfs_has_rtrmapbt, + .repair = xrep_notsupported, + }, }; static int
fs/xfs/scrub/scrub.h +5 -0
@@ -126,6 +126,9 @@ struct xchk_rt {/* XFS_RTGLOCK_* lock state if locked */ unsigned int rtlock_flags; + +/* rtgroup btrees */ +struct xfs_btree_cur *rmap_cur; };struct xfs_scrub {
@@ -280,10 +283,12 @@ int xchk_metapath(struct xfs_scrub *sc);int xchk_rtbitmap (struct xfs_scrub *sc);int xchk_rtsummary (struct xfs_scrub *sc);int xchk_rgsuperblock (struct xfs_scrub *sc); +int xchk_rtrmapbt (struct xfs_scrub *sc);#else # define xchk_rtbitmap xchk_nothing# define xchk_rtsummary xchk_nothing# define xchk_rgsuperblock xchk_nothing +# define xchk_rtrmapbt xchk_nothing#endif #ifdef CONFIG_XFS_QUOTA int xchk_quota (struct xfs_scrub *sc);
fs/xfs/scrub/stats.c +1 -0
@@ -82,6 +82,7 @@ static const char *name_map[XFS_SCRUB_TYPE_NR] = { [XFS_SCRUB_TYPE_DIRTREE] = "dirtree", [XFS_SCRUB_TYPE_METAPATH] = "metapath", [XFS_SCRUB_TYPE_RGSUPER] = "rgsuper", + [XFS_SCRUB_TYPE_RTRMAPBT] = "rtrmapbt", };/* Format the scrub stats into a text buffer, similar to pcp style. */
fs/xfs/scrub/trace.h +3 -1
@@ -72,6 +72,7 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_DIRTREE);TRACE_DEFINE_ENUM (XFS_SCRUB_TYPE_BARRIER );TRACE_DEFINE_ENUM (XFS_SCRUB_TYPE_METAPATH );TRACE_DEFINE_ENUM (XFS_SCRUB_TYPE_RGSUPER ); +TRACE_DEFINE_ENUM (XFS_SCRUB_TYPE_RTRMAPBT );#define XFS_SCRUB_TYPE_STRINGS \ { XFS_SCRUB_TYPE_PROBE, "probe" }, \
@@ -105,7 +106,8 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_RGSUPER); { XFS_SCRUB_TYPE_DIRTREE, "dirtree" }, \ { XFS_SCRUB_TYPE_BARRIER, "barrier" }, \ { XFS_SCRUB_TYPE_METAPATH, "metapath" }, \ - { XFS_SCRUB_TYPE_RGSUPER, "rgsuper" } + { XFS_SCRUB_TYPE_RGSUPER, "rgsuper" }, \ + { XFS_SCRUB_TYPE_RTRMAPBT, "rtrmapbt" } #define XFS_SCRUB_FLAG_STRINGS \ { XFS_SCRUB_IFLAG_REPAIR, "repair" }, \
PATCH 22/37 xfs: cross-reference realtime bitmap to realtime rmapbt scrubber
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
When we're checking the realtime rmap btree entries, cross-reference those entries with the realtime bitmap too.
--- fs/xfs/scrub/rtrmap.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
fs/xfs/scrub/rtrmap.c +15 -0
@@ -142,6 +142,20 @@ xchk_rtrmapbt_check_mergeable(memcpy (&cr->prev_rec, irec,sizeof (struct xfs_rmap_irec )); } +/* Cross-reference with other metadata. */ +STATIC void +xchk_rtrmapbt_xref ( +struct xfs_scrub *sc, +struct xfs_rmap_irec *irec) +{ +if (sc->sm->sm_flags &XFS_SCRUB_OFLAG_CORRUPT ) +return ; + +xchk_xref_is_used_rt_space (sc, +xfs_rgbno_to_rtb (sc->sr.rtg, irec->rm_startblock), + irec->rm_blockcount); +} +/* Scrub a realtime rmapbt record. */ STATIC int xchk_rtrmapbt_rec(
@@ -162,6 +176,7 @@ xchk_rtrmapbt_rec(xchk_rtrmapbt_check_mergeable (bs, cr, &irec);xchk_rtrmapbt_check_overlapping (bs, cr, &irec); +xchk_rtrmapbt_xref (bs->sc, &irec);return 0 ; }
PATCH 23/37 xfs: cross-reference the realtime rmapbt
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Teach the data fork and realtime bitmap scrubbers to cross-reference information with the realtime rmap btree.
--- fs/xfs/scrub/bmap.c | 52 +++++++++++++++++++++++++++----------- fs/xfs/scrub/rgsuper.c | 2 + fs/xfs/scrub/rtbitmap.c | 55 +++++++++++++++++++++++++++++++++++++--- fs/xfs/scrub/rtbitmap.h | 5 ++++ fs/xfs/scrub/rtrmap.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.h | 9 +++++++ 6 files changed, 169 insertions(+), 19 deletions(-)
fs/xfs/scrub/bmap.c +37 -15
@@ -143,15 +143,22 @@ static inline boolxchk_bmap_get_rmap ( struct xchk_bmap_info *info, struct xfs_bmbt_irec *irec, - xfs_agblock_t agbno, + xfs_agblock_t bno, uint64_t owner, struct xfs_rmap_irec *rmap) { + struct xfs_btree_cur **curp = &info->sc->sa.rmap_cur;xfs_fileoff_t offset;unsigned int rflags =0 ;int has_rmap;int error; +if (xfs_ifork_is_realtime (info->sc->ip, info->whichfork)) + curp = &info->sc->sr.rmap_cur; + +if (*curp ==NULL ) +return false; +if (info->whichfork ==XFS_ATTR_FORK ) rflags |=XFS_RMAP_ATTR_FORK ;if (irec->br_state ==XFS_EXT_UNWRITTEN )
@@ -172,13 +179,13 @@ xchk_bmap_get_rmap(* range rmap lookup to make sure we get the correct owner/offset. */ if (info->is_shared) { - error =xfs_rmap_lookup_le_range (info->sc->sa.rmap_cur, agbno, - owner, offset, rflags, rmap, &has_rmap); + error =xfs_rmap_lookup_le_range (*curp, bno, owner, offset, + rflags, rmap, &has_rmap); }else { - error =xfs_rmap_lookup_le (info->sc->sa.rmap_cur, agbno, - owner, offset, rflags, rmap, &has_rmap); + error =xfs_rmap_lookup_le (*curp, bno, owner, offset, + rflags, rmap, &has_rmap); } -if (!xchk_should_check_xref (info->sc, &error, &info->sc->sa.rmap_cur)) +if (!xchk_should_check_xref (info->sc, &error, curp))return false;if (!has_rmap)
@@ -192,29 +199,29 @@ STATIC voidxchk_bmap_xref_rmap ( struct xchk_bmap_info *info, struct xfs_bmbt_irec *irec, - xfs_agblock_t agbno) + xfs_agblock_t bno) { struct xfs_rmap_irec rmap;unsigned long long rmap_end;uint64_t owner = info->sc->ip->i_ino; -if (!info->sc->sa.rmap_cur ||xchk_skip_xref (info->sc->sm)) +if (xchk_skip_xref (info->sc->sm))return ;/* Find the rmap record for this irec. */ -if (!xchk_bmap_get_rmap (info, irec, agbno, owner, &rmap)) +if (!xchk_bmap_get_rmap (info, irec, bno, owner, &rmap))return ;/* * The rmap must be an exact match for this incore file mapping record, * which may have arisen from multiple ondisk records. */ -if (rmap.rm_startblock != agbno) +if (rmap.rm_startblock != bno)xchk_fblock_xref_set_corrupt (info->sc, info->whichfork, irec->br_startoff); rmap_end = (unsigned long long )rmap.rm_startblock + rmap.rm_blockcount; -if (rmap_end != agbno + irec->br_blockcount) +if (rmap_end != bno + irec->br_blockcount)xchk_fblock_xref_set_corrupt (info->sc, info->whichfork, irec->br_startoff);
@@ -259,7 +266,7 @@ STATIC voidxchk_bmap_xref_rmap_cow ( struct xchk_bmap_info *info, struct xfs_bmbt_irec *irec, - xfs_agblock_t agbno) + xfs_agblock_t bno) { struct xfs_rmap_irec rmap;unsigned long long rmap_end;
@@ -269,7 +276,7 @@ xchk_bmap_xref_rmap_cow(return ;/* Find the rmap record for this irec. */ -if (!xchk_bmap_get_rmap (info, irec, agbno, owner, &rmap)) +if (!xchk_bmap_get_rmap (info, irec, bno, owner, &rmap))return ;/*
@@ -277,12 +284,12 @@ xchk_bmap_xref_rmap_cow(* can start before and end after the physical space allocated to this * mapping. There are no offsets to check. */ -if (rmap.rm_startblock > agbno) +if (rmap.rm_startblock > bno)xchk_fblock_xref_set_corrupt (info->sc, info->whichfork, irec->br_startoff); rmap_end = (unsigned long long )rmap.rm_startblock + rmap.rm_blockcount; -if (rmap_end < agbno + irec->br_blockcount) +if (rmap_end < bno + irec->br_blockcount)xchk_fblock_xref_set_corrupt (info->sc, info->whichfork, irec->br_startoff);
@@ -315,6 +322,8 @@ xchk_bmap_rt_iextent_xref(struct xchk_bmap_info *info, struct xfs_bmbt_irec *irec) { + struct xfs_owner_info oinfo; +xfs_rgblock_t rgbno;int error; error = xchk_rtgroup_init_existing(info->sc,
@@ -332,6 +341,19 @@ xchk_bmap_rt_iextent_xref(xchk_xref_is_used_rt_space (info->sc, irec->br_startblock, irec->br_blockcount); +if (!xfs_has_rtrmapbt (info->sc->mp)) + goto out_cur; + + rgbno =xfs_rtb_to_rgbno (info->sc->mp, irec->br_startblock); +xchk_bmap_xref_rmap (info, irec, rgbno); + +xfs_rmap_ino_owner (&oinfo, info->sc->ip->i_ino, info->whichfork, + irec->br_startoff); +xchk_xref_is_only_rt_owned_by (info->sc, rgbno, + irec->br_blockcount, &oinfo); + +out_cur: +xchk_rtgroup_btcur_free (&info->sc->sr); out_free:xchk_rtgroup_free (info->sc, &info->sc->sr); }
fs/xfs/scrub/rgsuper.c +2 -0
@@ -13,6 +13,7 @@#include "xfs_log_format.h" #include "xfs_trans.h" #include "xfs_sb.h" +#include "xfs_rmap.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/repair.h"
@@ -34,6 +35,7 @@ xchk_rgsuperblock_xref(return ;xchk_xref_is_used_rt_space (sc,xfs_rgbno_to_rtb (sc->sr.rtg,0 ),1 ); +xchk_xref_is_only_rt_owned_by (sc,0 ,1 , &XFS_RMAP_OINFO_FS ); }int
fs/xfs/scrub/rtbitmap.c +51 -4
117 lines not on this page · raw message
fs/xfs/scrub/rtbitmap.h +5 -0
@@ -7,10 +7,15 @@#define __XFS_SCRUB_RTBITMAP_H__struct xchk_rtbitmap { +struct xfs_scrub *sc; +uint64_t rextents;uint64_t rbmblocks;unsigned int rextslog;unsigned int resblks; + +/* The next free rt group block number that we expect to see. */ +xfs_rgblock_t next_free_rgbno; };#ifdef CONFIG_XFS_ONLINE_REPAIR
fs/xfs/scrub/rtrmap.c +65 -0
68 lines not on this page · raw message
fs/xfs/scrub/scrub.h +9 -0
@@ -322,8 +322,17 @@ void xchk_xref_is_not_cow_staging(struct xfs_scrub *sc, xfs_agblock_t bno,#ifdef CONFIG_XFS_RT void xchk_xref_is_used_rt_space (struct xfs_scrub *sc,xfs_rtblock_t rtbno,xfs_extlen_t len); +void xchk_xref_has_no_rt_owner (struct xfs_scrub *sc,xfs_rgblock_t rgbno, +xfs_extlen_t len); +void xchk_xref_has_rt_owner (struct xfs_scrub *sc,xfs_rgblock_t rgbno, +xfs_extlen_t len); +void xchk_xref_is_only_rt_owned_by (struct xfs_scrub *sc,xfs_rgblock_t rgbno, +xfs_extlen_t len,const struct xfs_owner_info *oinfo);#else # define xchk_xref_is_used_rt_space (sc, rtbno, len) do { } while (0) +# define xchk_xref_has_no_rt_owner (sc, rtbno, len) do { } while (0) +# define xchk_xref_has_rt_owner (sc, rtbno, len) do { } while (0) +# define xchk_xref_is_only_rt_owned_by (sc, bno, len, oinfo) do { } while (0)#endif #endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH 24/37 xfs: scan rt rmap when we're doing an intense rmap check of bmbt mappings
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Teach the bmbt scrubber how to perform a comprehensive check that the rmapbt does not contain /any/ mappings that are not described by bmbt records when it's dealing with a realtime file.
--- fs/xfs/scrub/bmap.c | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-)
fs/xfs/scrub/bmap.c +42 -6
@@ -21,6 +21,8 @@#include "xfs_rmap_btree.h" #include "xfs_rtgroup.h" #include "xfs_health.h" +#include "xfs_rtalloc.h" +#include "xfs_rtrmap_btree.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/btree.h"
@@ -641,8 +643,7 @@ xchk_bmap_check_rmap(xchk_fblock_set_corrupt (sc, sbcri->whichfork, check_rec.rm_offset);if (irec.br_startblock != -xfs_agbno_to_fsb (to_perag (cur->bc_group), - check_rec.rm_startblock)) +xfs_gbno_to_fsb (cur->bc_group, check_rec.rm_startblock))xchk_fblock_set_corrupt (sc, sbcri->whichfork, check_rec.rm_offset);if (irec.br_blockcount > check_rec.rm_blockcount)
@@ -696,6 +697,30 @@ xchk_bmap_check_ag_rmaps(return error; } +/* Make sure each rt rmap has a corresponding bmbt entry. */ +STATIC int +xchk_bmap_check_rt_rmaps ( +struct xfs_scrub *sc, +struct xfs_rtgroup *rtg) +{ +struct xchk_bmap_check_rmap_info sbcri; +struct xfs_btree_cur *cur; +int error; + +xfs_rtgroup_lock (rtg,XFS_RTGLOCK_RMAP ); + cur =xfs_rtrmapbt_init_cursor (sc->tp, rtg); + + sbcri.sc = sc; + sbcri.whichfork =XFS_DATA_FORK ; + error =xfs_rmap_query_all (cur, xchk_bmap_check_rmap, &sbcri); +if (error == -ECANCELED ) + error =0 ; + +xfs_btree_del_cursor (cur, error); +xfs_rtgroup_unlock (rtg,XFS_RTGLOCK_RMAP ); +return error; +} +/* * Decide if we want to scan the reverse mappings to determine if the attr * fork /really/ has zero space mappings.
@@ -750,10 +775,6 @@ xchk_bmap_check_empty_datafork( {struct xfs_ifork *ifp = &ip->i_df; -/* Don't support realtime rmap checks yet. */ -if (XFS_IS_REALTIME_INODE (ip)) -return false; -/* * If the dinode repair found a bad data fork, it will reset the fork * to extents format with zero records and wait for the this scrubber
@@ -804,6 +825,21 @@ xchk_bmap_check_rmaps(struct xfs_perag *pag =NULL ;int error; +if (xfs_ifork_is_realtime (sc->ip, whichfork)) { +struct xfs_rtgroup *rtg =NULL ; + +while ((rtg =xfs_rtgroup_next (sc->mp, rtg))) { + error =xchk_bmap_check_rt_rmaps (sc, rtg); +if (error || + (sc->sm->sm_flags &XFS_SCRUB_OFLAG_CORRUPT )) { +xfs_rtgroup_rele (rtg); +return error; + } + } + +return 0 ; + } +while ((pag =xfs_perag_next (sc->mp, pag))) { error =xchk_bmap_check_ag_rmaps (sc, whichfork, pag); if (error ||
PATCH 25/37 xfs: scrub the metadir path of rt rmap btree files
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Add a new XFS_SCRUB_METAPATH subtype so that we can scrub the metadata directory tree path to the rmap btree file for each rt group.
--- fs/xfs/libxfs/xfs_fs.h | 3 ++- fs/xfs/scrub/metapath.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-)
fs/xfs/libxfs/xfs_fs.h +2 -1
@@ -830,9 +830,10 @@ struct xfs_scrub_vec_head {#define XFS_SCRUB_METAPATH_USRQUOTA (5)/* user quota */ #define XFS_SCRUB_METAPATH_GRPQUOTA (6)/* group quota */ #define XFS_SCRUB_METAPATH_PRJQUOTA (7)/* project quota */ +#define XFS_SCRUB_METAPATH_RTRMAPBT (8)/* realtime reverse mapping */ /* Number of metapath sm_ino values */ -#define XFS_SCRUB_METAPATH_NR (8) +#define XFS_SCRUB_METAPATH_NR (9)/* * ioctl limits
fs/xfs/scrub/metapath.c +3 -0
@@ -21,6 +21,7 @@#include "xfs_trans_space.h" #include "xfs_attr.h" #include "xfs_rtgroup.h" +#include "xfs_rtrmap_btree.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/trace.h"
@@ -246,6 +247,8 @@ xchk_setup_metapath(return xchk_setup_metapath_dqinode (sc,XFS_DQTYPE_GROUP );case XFS_SCRUB_METAPATH_PRJQUOTA :return xchk_setup_metapath_dqinode (sc,XFS_DQTYPE_PROJ ); +case XFS_SCRUB_METAPATH_RTRMAPBT : +return xchk_setup_metapath_rtginode (sc,XFS_RTGI_RMAP );default :return -ENOENT ; }
PATCH 26/37 xfs: walk the rt reverse mapping tree when rebuilding rmap
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
When we're rebuilding the data device rmap, if we encounter an "rmap" format fork, we have to walk the (realtime) rmap btree inode to build the appropriate mappings.
--- fs/xfs/scrub/rmap_repair.c | 53 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-)
fs/xfs/scrub/rmap_repair.c +52 -1
@@ -31,6 +31,8 @@#include "xfs_refcount.h" #include "xfs_refcount_btree.h" #include "xfs_ag.h" +#include "xfs_rtrmap_btree.h" +#include "xfs_rtgroup.h" #include "scrub/xfs_scrub.h" #include "scrub/scrub.h" #include "scrub/common.h"
@@ -504,7 +506,56 @@ xrep_rmap_scan_meta_btree(struct xrep_rmap_ifork *rf, struct xfs_inode *ip) { - return -EFSCORRUPTED; /* XXX placeholder */ + struct xfs_scrub *sc = rf->rr->sc; +struct xfs_rtgroup *rtg =NULL ; +struct xfs_btree_cur *cur =NULL ; +enum xfs_rtg_inodes type; +int error; + +if (rf->whichfork !=XFS_DATA_FORK ) +return -EFSCORRUPTED ; + +switch (ip->i_metatype) { +case XFS_METAFILE_RTRMAP : + type =XFS_RTGI_RMAP ; +break ; +default : +ASSERT (0 ); +return -EFSCORRUPTED ; + } + +while ((rtg =xfs_rtgroup_next (sc->mp, rtg))) { +if (ip == rtg->rtg_inodes[type]) + goto found; + } + +/* +* We should never find an rt metadata btree inode that isn't +* associated with an rtgroup yet has ondisk blocks allocated to it. +*/ +if (ip->i_nblocks) { +ASSERT (0 ); +return -EFSCORRUPTED ; + } + +return 0 ; + +found: +switch (ip->i_metatype) { +case XFS_METAFILE_RTRMAP : + cur =xfs_rtrmapbt_init_cursor (sc->tp, rtg); +break ; +default : +ASSERT (0 ); + error = -EFSCORRUPTED ; + goto out_rtg; + } + + error =xrep_rmap_scan_iroot_btree (rf, cur); +xfs_btree_del_cursor (cur, error); +out_rtg: +xfs_rtgroup_rele (rtg); +return error; }/* Find all the extents from a given AG in an inode fork. */
PATCH 27/37 xfs: online repair of realtime file bmaps
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Now that we have a reverse-mapping index of the realtime device, we can rebuild the data fork forward-mappings of any realtime file. Enhance the existing bmbt repair code to walk the rtrmap btrees to gather this information.
--- fs/xfs/scrub/bmap_repair.c | 128 +++++++++++++++++++++++++++++++++++++++++++- fs/xfs/scrub/repair.c | 46 ++++++++++++++++ fs/xfs/scrub/repair.h | 2 + 3 files changed, 172 insertions(+), 4 deletions(-)
fs/xfs/scrub/bmap_repair.c +124 -4
@@ -25,11 +25,13 @@#include "xfs_bmap_btree.h" #include "xfs_rmap.h" #include "xfs_rmap_btree.h" +#include "xfs_rtrmap_btree.h" #include "xfs_refcount.h" #include "xfs_quota.h" #include "xfs_ialloc.h" #include "xfs_ag.h" #include "xfs_reflink.h" +#include "xfs_rtgroup.h" #include "scrub/xfs_scrub.h" #include "scrub/scrub.h" #include "scrub/common.h"
@@ -359,6 +361,112 @@ xrep_bmap_scan_ag(return error; } +#ifdef CONFIG_XFS_RT +/* Check for any obvious errors or conflicts in the file mapping. */ +STATIC int +xrep_bmap_check_rtfork_rmap ( +struct xfs_scrub *sc, +struct xfs_btree_cur *cur, +const struct xfs_rmap_irec *rec) +{ +/* xattr extents are never stored on realtime devices */ +if (rec->rm_flags &XFS_RMAP_ATTR_FORK ) +return -EFSCORRUPTED ; + +/* bmbt blocks are never stored on realtime devices */ +if (rec->rm_flags &XFS_RMAP_BMBT_BLOCK ) +return -EFSCORRUPTED ; + +/* Data extents for non-rt files are never stored on the rt device. */ +if (!XFS_IS_REALTIME_INODE (sc->ip)) +return -EFSCORRUPTED ; + +/* Check the file offsets and physical extents. */ +if (!xfs_verify_fileext (sc->mp, rec->rm_offset, rec->rm_blockcount)) +return -EFSCORRUPTED ; + +/* Check that this is within the rtgroup. */ +if (!xfs_verify_rgbext (to_rtg (cur->bc_group), rec->rm_startblock, + rec->rm_blockcount)) +return -EFSCORRUPTED ; + +/* Make sure this isn't free space. */ +return xrep_require_rtext_inuse (sc, rec->rm_startblock, + rec->rm_blockcount); +} + +/* Record realtime extents that belong to this inode's fork. */ +STATIC int +xrep_bmap_walk_rtrmap ( +struct xfs_btree_cur *cur, +const struct xfs_rmap_irec *rec, +void *priv) +{ +struct xrep_bmap *rb = priv; +int error =0 ; + +if (xchk_should_terminate (rb->sc, &error)) +return error; + +/* Skip extents which are not owned by this inode and fork. */ +if (rec->rm_owner != rb->sc->ip->i_ino) +return 0 ; + + error =xrep_bmap_check_rtfork_rmap (rb->sc, cur, rec); +if (error) +return error; + +/* +* Record all blocks allocated to this file even if the extent isn't +* for the fork we're rebuilding so that we can reset di_nblocks later. +*/ + rb->nblocks += rec->rm_blockcount; + +/* If this rmap isn't for the fork we want, we're done. */ +if (rb->whichfork ==XFS_DATA_FORK && + (rec->rm_flags &XFS_RMAP_ATTR_FORK )) +return 0 ; +if (rb->whichfork ==XFS_ATTR_FORK && + !(rec->rm_flags &XFS_RMAP_ATTR_FORK )) +return 0 ; + +return xrep_bmap_from_rmap (rb, rec->rm_offset, +xfs_rgbno_to_rtb (to_rtg (cur->bc_group), + rec->rm_startblock), + rec->rm_blockcount, + rec->rm_flags &XFS_RMAP_UNWRITTEN ); +} + +/* Scan the realtime reverse mappings to build the new extent map. */ +STATIC int +xrep_bmap_scan_rtgroup ( +struct xrep_bmap *rb, +struct xfs_rtgroup *rtg) +{ +struct xfs_scrub *sc = rb->sc; +int error; + +if (!xfs_has_rtrmapbt (sc->mp)) +return 0 ; + + error =xrep_rtgroup_init (sc, rtg, &sc->sr, +XFS_RTGLOCK_RMAP |XFS_RTGLOCK_BITMAP_SHARED ); +if (error) +return error; + + error =xfs_rmap_query_all (sc->sr.rmap_cur, xrep_bmap_walk_rtrmap, rb); +xchk_rtgroup_btcur_free (&sc->sr); +xchk_rtgroup_free (sc, &sc->sr); +return error; +} +#else +static inline int +xrep_bmap_scan_rtgroup (struct xrep_bmap *rb,struct xfs_rtgroup *rtg) +{ +return -EFSCORRUPTED ; +} +#endif +/* Find the delalloc extents from the old incore extent tree. */ STATIC int xrep_bmap_find_delalloc(
@@ -410,6 +518,22 @@ xrep_bmap_find_mappings(struct xfs_perag *pag =NULL ;int error =0 ; +/* +* Iterate the rtrmaps for extents. Metadata files never have content +* on the realtime device, so there's no need to scan them. +*/ +if (!xfs_is_metadir_inode (sc->ip)) { +struct xfs_rtgroup *rtg =NULL ; + +while ((rtg =xfs_rtgroup_next (sc->mp, rtg))) { + error =xrep_bmap_scan_rtgroup (rb, rtg); +if (error) { +xfs_rtgroup_rele (rtg); +return error; + } + } + } +/* Iterate the rmaps for extents. */ while ((pag =xfs_perag_next (sc->mp, pag))) { error =xrep_bmap_scan_ag (rb, pag);
@@ -754,10 +878,6 @@ xrep_bmap_check_inputs(return -EINVAL ; } -/* Don't know how to rebuild realtime data forks. */ -if (XFS_IS_REALTIME_INODE (sc->ip)) -return -EOPNOTSUPP ; -return 0 ; }
fs/xfs/scrub/repair.c +46 -0
64 lines not on this page · raw message
fs/xfs/scrub/repair.h +2 -0
@@ -110,6 +110,8 @@ int xrep_ag_init(struct xfs_scrub *sc, struct xfs_perag *pag,#ifdef CONFIG_XFS_RT int xrep_rtgroup_init (struct xfs_scrub *sc,struct xfs_rtgroup *rtg,struct xchk_rt *sr,unsigned int rtglock_flags); +int xrep_require_rtext_inuse (struct xfs_scrub *sc,xfs_rgblock_t rgbno, +xfs_filblks_t len);#else # define xrep_rtgroup_init (sc, rtg, sr, lockflags) (-ENOSYS)#endif /* CONFIG_XFS_RT */
PATCH 28/37 xfs: repair inodes that have realtime extents
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Plumb into the inode core repair code the ability to search for extents on realtime devices.
--- fs/xfs/scrub/inode_repair.c | 58 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-)
fs/xfs/scrub/inode_repair.c +57 -1
@@ -38,6 +38,8 @@#include "xfs_log_priv.h" #include "xfs_health.h" #include "xfs_symlink_remote.h" +#include "xfs_rtgroup.h" +#include "xfs_rtrmap_btree.h" #include "scrub/xfs_scrub.h" #include "scrub/scrub.h" #include "scrub/common.h"
@@ -773,17 +775,71 @@ xrep_dinode_count_ag_rmaps(return error; } +/* Count extents and blocks for an inode given an rt rmap. */ +STATIC int +xrep_dinode_walk_rtrmap ( +struct xfs_btree_cur *cur, +const struct xfs_rmap_irec *rec, +void *priv) +{ +struct xrep_inode *ri = priv; +int error =0 ; + +if (xchk_should_terminate (ri->sc, &error)) +return error; + +/* We only care about this inode. */ +if (rec->rm_owner != ri->sc->sm->sm_ino) +return 0 ; + +if (rec->rm_flags & (XFS_RMAP_ATTR_FORK |XFS_RMAP_BMBT_BLOCK )) +return -EFSCORRUPTED ; + + ri->rt_blocks += rec->rm_blockcount; + ri->rt_extents++; +return 0 ; +} + +/* Count extents and blocks for an inode from all realtime rmap data. */ +STATIC int +xrep_dinode_count_rtgroup_rmaps ( +struct xrep_inode *ri, +struct xfs_rtgroup *rtg) +{ +struct xfs_scrub *sc = ri->sc; +int error; + + error =xrep_rtgroup_init (sc, rtg, &sc->sr,XFS_RTGLOCK_RMAP ); +if (error) +return error; + + error =xfs_rmap_query_all (sc->sr.rmap_cur, xrep_dinode_walk_rtrmap, + ri); +xchk_rtgroup_btcur_free (&sc->sr); +xchk_rtgroup_free (sc, &sc->sr); +return error; +} +/* Count extents and blocks for a given inode from all rmap data. */ STATIC intxrep_dinode_count_rmaps (struct xrep_inode *ri) {struct xfs_perag *pag =NULL ; +struct xfs_rtgroup *rtg =NULL ;int error; -if (!xfs_has_rmapbt (ri->sc->mp) ||xfs_has_realtime (ri->sc->mp)) +if (!xfs_has_rmapbt (ri->sc->mp))return -EOPNOTSUPP ; +while ((rtg =xfs_rtgroup_next (ri->sc->mp, rtg))) { + error =xrep_dinode_count_rtgroup_rmaps (ri, rtg); +if (error) { +xfs_rtgroup_rele (rtg); +return error; + } + } +while ((pag =xfs_perag_next (ri->sc->mp, pag))) { error =xrep_dinode_count_ag_rmaps (ri, pag);if (error) {
PATCH 29/37 xfs: repair rmap btree inodes
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Teach the inode repair code how to deal with realtime rmap btree inodes that won't load properly. This is most likely moot since the filesystem generally won't mount without the rtrmapbt inodes being usable, but we'll add this for completeness.
--- fs/xfs/scrub/inode_repair.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
fs/xfs/scrub/inode_repair.c +35 -0
@@ -944,6 +944,34 @@ xrep_dinode_bad_bmbt_fork(return false; } +/* Return true if this rmap-format ifork looks like garbage. */ +STATIC bool +xrep_dinode_bad_rtrmapbt_fork ( +struct xfs_scrub *sc, +struct xfs_dinode *dip, +unsigned int dfork_size) +{ +struct xfs_rtrmap_root *dfp; +unsigned int nrecs; +unsigned int level; + +if (dfork_size <sizeof (struct xfs_rtrmap_root )) +return true; + + dfp =XFS_DFORK_PTR (dip,XFS_DATA_FORK ); + nrecs =be16_to_cpu (dfp->bb_numrecs); + level =be16_to_cpu (dfp->bb_level); + +if (level > sc->mp->m_rtrmap_maxlevels) +return true; +if (xfs_rtrmap_droot_space_calc (level, nrecs) > dfork_size) +return true; +if (level >0 && nrecs ==0 ) +return true; + +return false; +} +/* Check a metadata-btree fork. */ STATIC bool xrep_dinode_bad_metabt_fork(
@@ -956,6 +984,8 @@ xrep_dinode_bad_metabt_fork(return true;switch (be16_to_cpu (dip->di_metatype)) { +case XFS_METAFILE_RTRMAP : +return xrep_dinode_bad_rtrmapbt_fork (sc, dip, dfork_size);default :return true; }
@@ -1220,6 +1250,7 @@ xrep_dinode_ensure_forkoff( uint16_t mode) {struct xfs_bmdr_block *bmdr; +struct xfs_rtrmap_root *rmdr;struct xfs_scrub *sc = ri->sc;xfs_extnum_t attr_extents, data_extents;size_t bmdr_minsz =xfs_bmdr_space_calc (1 );
@@ -1328,6 +1359,10 @@ xrep_dinode_ensure_forkoff(break ;case XFS_DINODE_FMT_META_BTREE :switch (be16_to_cpu (dip->di_metatype)) { +case XFS_METAFILE_RTRMAP : + rmdr =XFS_DFORK_PTR (dip,XFS_DATA_FORK ); + dfork_min =xfs_rtrmap_broot_space (sc->mp, rmdr); +break ;default : dfork_min =0 ;break ;
PATCH 30/37 xfs: online repair of realtime bitmaps for a realtime group
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
For a given rt group, regenerate the bitmap contents from the group's realtime rmap btree.
--- fs/xfs/libxfs/xfs_rtbitmap.h | 9 + fs/xfs/scrub/common.h | 6 + fs/xfs/scrub/repair.c | 2 fs/xfs/scrub/repair.h | 1 fs/xfs/scrub/rtbitmap.c | 5 fs/xfs/scrub/rtbitmap.h | 50 +++++ fs/xfs/scrub/rtbitmap_repair.c | 429 ++++++++++++++++++++++++++++++++++++++- fs/xfs/scrub/rtsummary_repair.c | 3 fs/xfs/scrub/tempexch.h | 2 fs/xfs/scrub/tempfile.c | 20 +- fs/xfs/scrub/trace.c | 1 fs/xfs/scrub/trace.h | 150 ++++++++++++++ 12 files changed, 659 insertions(+), 19 deletions(-)
fs/xfs/libxfs/xfs_rtbitmap.h +9 -0
@@ -135,6 +135,15 @@ xfs_rtb_to_rtx(return div_u64 (rtbno, mp->m_sb.sb_rextsize); } +/* Return the offset of a rtgroup block number within an rt extent. */ +static inline xfs_extlen_t +xfs_rgbno_to_rtxoff ( +struct xfs_mount *mp, +xfs_rgblock_t rgbno) +{ +return rgbno % mp->m_sb.sb_rextsize; +} +/* Return the offset of an rt block number within an rt extent. */ static inline xfs_extlen_t xfs_rtb_to_rtxoff(
fs/xfs/scrub/common.h +6 -0
@@ -264,6 +264,12 @@ int xchk_metadata_inode_forks(struct xfs_scrub *sc); (sc)->mp->m_super->s_id, \ (sc)->ip ? (sc)->ip->i_ino : (sc)->sm->sm_ino, \ ##__VA_ARGS__) +#define xchk_xfile_rtgroup_descr (sc, fmt, ...) \ + kasprintf(XCHK_GFP_FLAGS, "XFS (%s): rtgroup 0x%x " fmt, \ + (sc)->mp->m_super->s_id, \ + (sc)->sa.pag ? \ + rtg_rgno((sc)->sr.rtg) : (sc)->sm->sm_agno, \ + ##__VA_ARGS__)/* * Setting up a hook to wait for intents to drain is costly -- we have to take
fs/xfs/scrub/repair.c +1 -1
@@ -959,7 +959,7 @@ xrep_ag_init(#ifdef CONFIG_XFS_RT /* Initialize all the btree cursors for a RT repair. */ -static void +void xrep_rtgroup_btcur_init (struct xfs_scrub *sc,struct xchk_rt *sr)
fs/xfs/scrub/repair.h +1 -0
@@ -110,6 +110,7 @@ int xrep_ag_init(struct xfs_scrub *sc, struct xfs_perag *pag,#ifdef CONFIG_XFS_RT int xrep_rtgroup_init (struct xfs_scrub *sc,struct xfs_rtgroup *rtg,struct xchk_rt *sr,unsigned int rtglock_flags); +void xrep_rtgroup_btcur_init (struct xfs_scrub *sc,struct xchk_rt *sr);int xrep_require_rtext_inuse (struct xfs_scrub *sc,xfs_rgblock_t rgbno,xfs_filblks_t len);#else
fs/xfs/scrub/rtbitmap.c +4 -1
@@ -20,9 +20,11 @@#include "xfs_sb.h" #include "xfs_rmap.h" #include "xfs_rtrmap_btree.h" +#include "xfs_exchmaps.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/repair.h" +#include "scrub/tempexch.h" #include "scrub/rtbitmap.h" #include "scrub/btree.h"
@@ -38,7 +40,8 @@ xchk_setup_rtbitmap(if (xchk_need_intent_drain (sc))xchk_fsgates_enable (sc,XCHK_FSGATES_DRAIN ); - rtb =kzalloc (sizeof (struct xchk_rtbitmap ),XCHK_GFP_FLAGS ); + rtb =kzalloc (struct_size (rtb, words,xchk_rtbitmap_wordcnt (sc)), +XCHK_GFP_FLAGS );if (!rtb)return -ENOMEM ; sc->buf = rtb;
fs/xfs/scrub/rtbitmap.h +50 -0
68 lines not on this page · raw message
fs/xfs/scrub/rtbitmap_repair.c +421 -8
474 lines not on this page · raw message
fs/xfs/scrub/rtsummary_repair.c +2 -1
@@ -165,7 +165,8 @@ xrep_rtsummary(* Now exchange the contents. Nothing in repair uses the temporary * buffer, so we can reuse it for the tempfile exchrange information. */ - error =xrep_tempexch_trans_reserve (sc,XFS_DATA_FORK , &rts->tempexch); + error =xrep_tempexch_trans_reserve (sc,XFS_DATA_FORK ,0 , + rts->rsumblocks, &rts->tempexch);if (error)return error;
fs/xfs/scrub/tempexch.h +1 -1
@@ -12,7 +12,7 @@ struct xrep_tempexch { };int xrep_tempexch_trans_reserve (struct xfs_scrub *sc,int whichfork, -struct xrep_tempexch *ti); +xfs_fileoff_t off,xfs_filblks_t len,struct xrep_tempexch *ti);int xrep_tempexch_trans_alloc (struct xfs_scrub *sc,int whichfork,struct xrep_tempexch *ti);
fs/xfs/scrub/tempfile.c +13 -7
@@ -606,6 +606,8 @@ STATIC intxrep_tempexch_prep_request ( struct xfs_scrub *sc, int whichfork, + xfs_fileoff_t off, + xfs_filblks_t len, struct xrep_tempexch *tx) { struct xfs_exchmaps_req *req = &tx->req;
@@ -629,18 +631,19 @@ xrep_tempexch_prep_request(/* Exchange all mappings in both forks. */ req->ip1 = sc->tempip; req->ip2 = sc->ip; - req->startoff1 =0 ; - req->startoff2 =0 ; + req->startoff1 = off; + req->startoff2 = off;switch (whichfork) {case XFS_ATTR_FORK : req->flags |=XFS_EXCHMAPS_ATTR_FORK ;break ;case XFS_DATA_FORK : -/* Always exchange sizes when exchanging data fork mappings. */ - req->flags |=XFS_EXCHMAPS_SET_SIZES ; +/* Exchange sizes when exchanging all data fork mappings. */ +if (off ==0 && len ==XFS_MAX_FILEOFF ) + req->flags |=XFS_EXCHMAPS_SET_SIZES ;break ; } - req->blockcount =XFS_MAX_FILEOFF ; + req->blockcount = len;return 0 ; }
@@ -796,6 +799,8 @@ intxrep_tempexch_trans_reserve ( struct xfs_scrub *sc, int whichfork, + xfs_fileoff_t off, + xfs_filblks_t len, struct xrep_tempexch *tx) { int error;
@@ -804,7 +809,7 @@ xrep_tempexch_trans_reserve(xfs_assert_ilocked (sc->ip,XFS_ILOCK_EXCL );xfs_assert_ilocked (sc->tempip,XFS_ILOCK_EXCL ); - error =xrep_tempexch_prep_request (sc, whichfork, tx); + error =xrep_tempexch_prep_request (sc, whichfork, off, len, tx);if (error)return error;
@@ -842,7 +847,8 @@ xrep_tempexch_trans_alloc(ASSERT (sc->tp ==NULL );ASSERT (xfs_has_exchange_range (sc->mp)); - error =xrep_tempexch_prep_request (sc, whichfork, tx); + error =xrep_tempexch_prep_request (sc, whichfork,0 ,XFS_MAX_FILEOFF , + tx);if (error)return error;
fs/xfs/scrub/trace.c +1 -0
@@ -21,6 +21,7 @@#include "xfs_rmap.h" #include "xfs_parent.h" #include "xfs_metafile.h" +#include "xfs_rtgroup.h" #include "scrub/scrub.h" #include "scrub/xfile.h" #include "scrub/xfarray.h"
fs/xfs/scrub/trace.h +150 -0
162 lines not on this page · raw message
PATCH 31/37 xfs: support repairing metadata btrees rooted in metadir inodes
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Adapt the repair code so that we can stage a new btree in the data fork area of a metadir inode and reap the old blocks. We already have nearly all of the infrastructure; the only parts that were missing were the metadata inode reservation handling.
--- fs/xfs/scrub/newbt.c | 42 ++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/newbt.h | 1 + fs/xfs/scrub/reap.c | 41 +++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/reap.h | 2 ++ 4 files changed, 86 insertions(+)
fs/xfs/scrub/newbt.c +42 -0
@@ -19,6 +19,8 @@#include "xfs_rmap.h" #include "xfs_ag.h" #include "xfs_defer.h" +#include "xfs_metafile.h" +#include "xfs_quota.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/trace.h"
@@ -120,6 +122,43 @@ xrep_newbt_init_inode(return 0 ; } +/* +* Initialize accounting resources for staging a new metadata inode btree. +* If the metadata file has a space reservation, the caller must adjust that +* reservation when committing the new ondisk btree. +*/ +int +xrep_newbt_init_metadir_inode ( +struct xrep_newbt *xnr, +struct xfs_scrub *sc) +{ +struct xfs_owner_info oinfo; +struct xfs_ifork *ifp; + +ASSERT (xfs_is_metadir_inode (sc->ip)); + +xfs_rmap_ino_bmbt_owner (&oinfo, sc->ip->i_ino,XFS_DATA_FORK ); + + ifp =kmem_cache_zalloc (xfs_ifork_cache,XCHK_GFP_FLAGS ); +if (!ifp) +return -ENOMEM ; + +/* +* Allocate new metadir btree blocks with XFS_AG_RESV_NONE because the +* inode metadata space reservations can only account allocated space +* to the i_nblocks. We do not want to change the inode core fields +* until we're ready to commit the new tree, so we allocate the blocks +* as if they were regular file blocks. This exposes us to a higher +* risk of the repair being cancelled due to ENOSPC. +*/ +xrep_newbt_init_ag (xnr, sc, &oinfo, +XFS_INO_TO_FSB (sc->mp, sc->ip->i_ino), +XFS_AG_RESV_NONE ); + xnr->ifake.if_fork = ifp; + xnr->ifake.if_fork_size =xfs_inode_fork_size (sc->ip,XFS_DATA_FORK ); +return 0 ; +} +/* * Initialize accounting resources for staging a new btree. Callers are * expected to add their own reservations (and clean them up) manually.
@@ -224,6 +263,7 @@ xrep_newbt_alloc_ag_blocks(int error =0 ;ASSERT (sc->sa.pag !=NULL ); +ASSERT (xnr->resv !=XFS_AG_RESV_METAFILE );while (nr_blocks >0 ) {struct xfs_alloc_arg args = {
@@ -297,6 +337,8 @@ xrep_newbt_alloc_file_blocks(struct xfs_mount *mp = sc->mp;int error =0 ; +ASSERT (xnr->resv !=XFS_AG_RESV_METAFILE ); +while (nr_blocks >0 ) {struct xfs_alloc_arg args = { .tp = sc->tp,
fs/xfs/scrub/newbt.h +1 -0
@@ -63,6 +63,7 @@ void xrep_newbt_init_ag(struct xrep_newbt *xnr, struct xfs_scrub *sc, enum xfs_ag_resv_type resv);int xrep_newbt_init_inode (struct xrep_newbt *xnr,struct xfs_scrub *sc,int whichfork,const struct xfs_owner_info *oinfo); +int xrep_newbt_init_metadir_inode (struct xrep_newbt *xnr,struct xfs_scrub *sc);int xrep_newbt_alloc_blocks (struct xrep_newbt *xnr,uint64_t nr_blocks);int xrep_newbt_add_extent (struct xrep_newbt *xnr,struct xfs_perag *pag,xfs_agblock_t agbno,xfs_extlen_t len);
fs/xfs/scrub/reap.c +41 -0
59 lines not on this page · raw message
fs/xfs/scrub/reap.h +2 -0
@@ -14,6 +14,8 @@ int xrep_reap_agblocks(struct xfs_scrub *sc, struct xagb_bitmap *bitmap,int xrep_reap_fsblocks (struct xfs_scrub *sc,struct xfsb_bitmap *bitmap,const struct xfs_owner_info *oinfo);int xrep_reap_ifork (struct xfs_scrub *sc,struct xfs_inode *ip,int whichfork); +int xrep_reap_metadir_fsblocks (struct xfs_scrub *sc, +struct xfsb_bitmap *bitmap);/* Buffer cache scan context. */ struct xrep_bufscan {
PATCH 32/37 xfs: online repair of the realtime rmap btree
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Repair the realtime rmap btree while mounted. Similar to the regular rmap btree repair code, we walk the data fork mappings of every realtime file in the filesystem to collect reverse-mapping records in an xfarray. Then we sort the xfarray, and use the btree bulk loader to create a new rtrmap btree ondisk. Finally, we swap the btree roots, and reap the old blocks in the usual way.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_btree_staging.c | 1 fs/xfs/libxfs/xfs_rtrmap_btree.c | 2 fs/xfs/libxfs/xfs_rtrmap_btree.h | 3 fs/xfs/scrub/common.c | 4 fs/xfs/scrub/common.h | 2 fs/xfs/scrub/repair.c | 144 +++++++ fs/xfs/scrub/repair.h | 14 + fs/xfs/scrub/rtrmap.c | 7 fs/xfs/scrub/rtrmap_repair.c | 733 +++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 2 fs/xfs/scrub/trace.h | 57 +++ 12 files changed, 966 insertions(+), 4 deletions(-) create mode 100644 fs/xfs/scrub/rtrmap_repair.c
fs/xfs/Makefile +1 -0
@@ -234,6 +234,7 @@ xfs-y += $(addprefix scrub/, \ xfs-$(CONFIG_XFS_RT) += $(addprefix scrub/, \ rtbitmap_repair.o \ + rtrmap_repair.o \ rtsummary_repair.o \ )
fs/xfs/libxfs/xfs_btree_staging.c +1 -0
@@ -134,6 +134,7 @@ xfs_btree_stage_ifakeroot( cur->bc_ino.ifake = ifake; cur->bc_nlevels = ifake->if_levels; cur->bc_ino.forksize = ifake->if_fork_size; + cur->bc_ino.whichfork =XFS_STAGING_FORK ; cur->bc_flags |=XFS_BTREE_STAGING ; }
fs/xfs/libxfs/xfs_rtrmap_btree.c +1 -1
@@ -660,7 +660,7 @@ xfs_rtrmapbt_compute_maxlevels( }/* Calculate the rtrmap btree size for some records. */ -static unsigned long long +unsigned long long xfs_rtrmapbt_calc_size (struct xfs_mount *mp,unsigned long long len)
fs/xfs/libxfs/xfs_rtrmap_btree.h +3 -0
@@ -198,4 +198,7 @@ int xfs_rtrmapbt_create(struct xfs_rtgroup *rtg, struct xfs_inode *ip,int xfs_rtrmapbt_init_rtsb (struct xfs_mount *mp,struct xfs_rtgroup *rtg,struct xfs_trans *tp); +unsigned long long xfs_rtrmapbt_calc_size (struct xfs_mount *mp, +unsigned long long len); +#endif /* __XFS_RTRMAP_BTREE_H__ */
fs/xfs/scrub/common.c +2 -2
@@ -819,7 +819,7 @@ xchk_rtgroup_btcur_free(* Unlock the realtime group. This must be done /after/ committing (or * cancelling) the scrub transaction. */ -static void +void xchk_rtgroup_unlock (struct xchk_rt *sr) {
@@ -904,7 +904,7 @@ intxchk_setup_rt ( struct xfs_scrub *sc) { -return xchk_trans_alloc (sc,0 ); +return xchk_trans_alloc (sc,xrep_calc_rtgroup_resblks (sc)); }/* Set us up with AG headers and btree cursors. */
fs/xfs/scrub/common.h +2 -0
@@ -147,12 +147,14 @@ xchk_rtgroup_init_existing(int xchk_rtgroup_lock (struct xfs_scrub *sc,struct xchk_rt *sr,unsigned int rtglock_flags); +void xchk_rtgroup_unlock (struct xchk_rt *sr);void xchk_rtgroup_btcur_free (struct xchk_rt *sr);void xchk_rtgroup_free (struct xfs_scrub *sc,struct xchk_rt *sr);#else # define xchk_rtgroup_init (sc, rgno, sr) (-EFSCORRUPTED)# define xchk_rtgroup_init_existing (sc, rgno, sr) (-EFSCORRUPTED)# define xchk_rtgroup_lock (sc, sr, lockflags) (-EFSCORRUPTED) +# define xchk_rtgroup_unlock (sr) do { } while (0)# define xchk_rtgroup_btcur_free (sr) do { } while (0)# define xchk_rtgroup_free (sc, sr) do { } while (0)#endif /* CONFIG_XFS_RT */
fs/xfs/scrub/repair.c +144 -0
159 lines not on this page · raw message
fs/xfs/scrub/repair.h +14 -0
@@ -97,6 +97,7 @@ int xrep_setup_parent(struct xfs_scrub *sc);int xrep_setup_nlinks (struct xfs_scrub *sc);int xrep_setup_symlink (struct xfs_scrub *sc,unsigned int *resblks);int xrep_setup_dirtree (struct xfs_scrub *sc); +int xrep_setup_rtrmapbt (struct xfs_scrub *sc);/* Repair setup functions */ int xrep_setup_ag_allocbt (struct xfs_scrub *sc);
@@ -113,10 +114,15 @@ int xrep_rtgroup_init(struct xfs_scrub *sc, struct xfs_rtgroup *rtg,void xrep_rtgroup_btcur_init (struct xfs_scrub *sc,struct xchk_rt *sr);int xrep_require_rtext_inuse (struct xfs_scrub *sc,xfs_rgblock_t rgbno,xfs_filblks_t len); +xfs_extlen_t xrep_calc_rtgroup_resblks (struct xfs_scrub *sc);#else # define xrep_rtgroup_init (sc, rtg, sr, lockflags) (-ENOSYS) +# define xrep_calc_rtgroup_resblks (sc) (0)#endif /* CONFIG_XFS_RT */ +int xrep_check_ino_btree_mapping (struct xfs_scrub *sc, +const struct xfs_rmap_irec *rec); +/* Metadata revalidators */ int xrep_revalidate_allocbt (struct xfs_scrub *sc);
@@ -150,10 +156,12 @@ int xrep_metapath(struct xfs_scrub *sc);int xrep_rtbitmap (struct xfs_scrub *sc);int xrep_rtsummary (struct xfs_scrub *sc);int xrep_rgsuperblock (struct xfs_scrub *sc); +int xrep_rtrmapbt (struct xfs_scrub *sc);#else # define xrep_rtbitmap xrep_notsupported# define xrep_rtsummary xrep_notsupported# define xrep_rgsuperblock xrep_notsupported +# define xrep_rtrmapbt xrep_notsupported#endif /* CONFIG_XFS_RT */ #ifdef CONFIG_XFS_QUOTA
@@ -172,6 +180,8 @@ int xrep_trans_alloc_hook_dummy(struct xfs_mount *mp, void **cookiep,void xrep_trans_cancel_hook_dummy (void **cookiep,struct xfs_trans *tp);bool xrep_buf_verify_struct (struct xfs_buf *bp,const struct xfs_buf_ops *ops); +void xrep_inode_set_nblocks (struct xfs_scrub *sc,int64_t new_blocks); +int xrep_reset_metafile_resv (struct xfs_scrub *sc);#else
@@ -195,6 +205,8 @@ xrep_calc_ag_resblks(return 0 ; } +#define xrep_calc_rtgroup_resblks xrep_calc_ag_resblks +static inline int xrep_reset_perag_resv (struct xfs_scrub *sc)
@@ -222,6 +234,7 @@ xrep_setup_nothing(#define xrep_setup_nlinks xrep_setup_nothing#define xrep_setup_dirtree xrep_setup_nothing#define xrep_setup_metapath xrep_setup_nothing +#define xrep_setup_rtrmapbt xrep_setup_nothing#define xrep_setup_inode (sc, imap) ((void)0)
@@ -259,6 +272,7 @@ static inline int xrep_setup_symlink(struct xfs_scrub *sc, unsigned int *x)#define xrep_dirtree xrep_notsupported#define xrep_metapath xrep_notsupported#define xrep_rgsuperblock xrep_notsupported +#define xrep_rtrmapbt xrep_notsupported#endif /* CONFIG_XFS_ONLINE_REPAIR */
fs/xfs/scrub/rtrmap.c +7 -0
@@ -27,6 +27,7 @@#include "scrub/common.h" #include "scrub/btree.h" #include "scrub/trace.h" +#include "scrub/repair.h" /* Set us up with the realtime metadata locked. */ int
@@ -38,6 +39,12 @@ xchk_setup_rtrmapbt(if (xchk_need_intent_drain (sc))xchk_fsgates_enable (sc,XCHK_FSGATES_DRAIN ); +if (xchk_could_repair (sc)) { + error =xrep_setup_rtrmapbt (sc); +if (error) +return error; + } + error =xchk_rtgroup_init (sc, sc->sm->sm_agno, &sc->sr);if (error)return error;
fs/xfs/scrub/rtrmap_repair.c new file +733 -0
733 lines not on this page · raw message
fs/xfs/scrub/scrub.c +1 -1
@@ -465,7 +465,7 @@ static const struct xchk_meta_ops meta_scrub_ops[] = { .setup = xchk_setup_rtrmapbt, .scrub = xchk_rtrmapbt, .has = xfs_has_rtrmapbt, - .repair = xrep_notsupported, + .repair = xrep_rtrmapbt, }, };
fs/xfs/scrub/trace.h +57 -0
69 lines not on this page · raw message
PATCH 33/37 xfs: create a shadow rmap btree during realtime rmap repair
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Create an in-memory btree of rmap records instead of an array. This enables us to do live record collection instead of freezing the fs.
--- fs/xfs/libxfs/xfs_btree_mem.c | 1 fs/xfs/libxfs/xfs_rmap.c | 3 + fs/xfs/libxfs/xfs_rtrmap_btree.c | 117 ++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_rtrmap_btree.h | 6 ++ fs/xfs/libxfs/xfs_shared.h | 7 ++ fs/xfs/scrub/rtrmap_repair.c | 137 ++++++++++++++++++++++++++------------ fs/xfs/xfs_stats.c | 3 + fs/xfs/xfs_stats.h | 1 8 files changed, 228 insertions(+), 47 deletions(-)
fs/xfs/libxfs/xfs_btree_mem.c +1 -0
@@ -18,6 +18,7 @@#include "xfs_ag.h" #include "xfs_buf_item.h" #include "xfs_trace.h" +#include "xfs_rtgroup.h" /* Set the root of an in-memory btree. */ void
fs/xfs/libxfs/xfs_rmap.c +2 -1
@@ -327,7 +327,8 @@ xfs_rmap_check_btrec(struct xfs_btree_cur *cur, const struct xfs_rmap_irec *irec) { - if (xfs_btree_is_rtrmap(cur->bc_ops)) + if (xfs_btree_is_rtrmap(cur->bc_ops) || + xfs_btree_is_mem_rtrmap(cur->bc_ops)) return xfs_rtrmap_check_irec(to_rtg(cur->bc_group), irec); return xfs_rmap_check_irec(to_perag(cur->bc_group), irec); }
fs/xfs/libxfs/xfs_rtrmap_btree.c +117 -0
129 lines not on this page · raw message
fs/xfs/libxfs/xfs_rtrmap_btree.h +6 -0
@@ -11,6 +11,7 @@ struct xfs_btree_cur;struct xfs_mount ;struct xbtree_ifakeroot ;struct xfs_rtgroup ; +struct xfbtree ;/* rmaps only exist on crc enabled filesystems */ #define XFS_RTRMAP_BLOCK_LEN XFS_BTREE_LBLOCK_CRC_LEN
@@ -201,4 +202,9 @@ int xfs_rtrmapbt_init_rtsb(struct xfs_mount *mp, struct xfs_rtgroup *rtg,unsigned long long xfs_rtrmapbt_calc_size (struct xfs_mount *mp,unsigned long long len); +struct xfs_btree_cur *xfs_rtrmapbt_mem_cursor (struct xfs_rtgroup *rtg, +struct xfs_trans *tp,struct xfbtree *xfbtree); +int xfs_rtrmapbt_mem_init (struct xfs_mount *mp,struct xfbtree *xfbtree, +struct xfs_buftarg *btp,xfs_rgnumber_t rgno); +#endif /* __XFS_RTRMAP_BTREE_H__ */
fs/xfs/libxfs/xfs_shared.h +7 -0
@@ -57,6 +57,7 @@ extern const struct xfs_btree_ops xfs_refcountbt_ops;extern const struct xfs_btree_ops xfs_rmapbt_ops;extern const struct xfs_btree_ops xfs_rmapbt_mem_ops;extern const struct xfs_btree_ops xfs_rtrmapbt_ops; +extern const struct xfs_btree_ops xfs_rtrmapbt_mem_ops;static inline bool xfs_btree_is_bno (const struct xfs_btree_ops *ops) {
@@ -98,8 +99,14 @@ static inline bool xfs_btree_is_mem_rmap(const struct xfs_btree_ops *ops) {return ops == &xfs_rmapbt_mem_ops; } + +static inline bool xfs_btree_is_mem_rtrmap (const struct xfs_btree_ops *ops) +{ +return ops == &xfs_rtrmapbt_mem_ops; +}#else # define xfs_btree_is_mem_rmap (...) (false) +# define xfs_btree_is_mem_rtrmap (...) (false)#endif static inline bool xfs_btree_is_rtrmap (const struct xfs_btree_ops *ops)
fs/xfs/scrub/rtrmap_repair.c +92 -45
274 lines not on this page · raw message
fs/xfs/xfs_stats.c +2 -1
@@ -53,7 +53,8 @@ int xfs_stats_format(struct xfsstats __percpu *stats, char *buf) { "refcntbt", xfsstats_offset(xs_rmap_mem_2) }, { "rmapbt_mem", xfsstats_offset(xs_rcbag_2) }, { "rcbagbt", xfsstats_offset(xs_rtrmap_2) }, - { "rtrmapbt", xfsstats_offset(xs_qm_dqreclaims)}, + { "rtrmapbt", xfsstats_offset(xs_rtrmap_mem_2)}, + { "rtrmapbt_mem", xfsstats_offset(xs_qm_dqreclaims)},/* we print both series of quota information together */ { "qm", xfsstats_offset(xs_xstrat_bytes)}, };
fs/xfs/xfs_stats.h +1 -0
@@ -128,6 +128,7 @@ struct __xfsstats {uint32_t xs_rmap_mem_2[__XBTS_MAX];uint32_t xs_rcbag_2[__XBTS_MAX];uint32_t xs_rtrmap_2[__XBTS_MAX]; +uint32_t xs_rtrmap_mem_2[__XBTS_MAX];uint32_t xs_qm_dqreclaims;uint32_t xs_qm_dqreclaim_misses;uint32_t xs_qm_dquot_dups;
PATCH 34/37 xfs: hook live realtime rmap operations during a repair operation
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Hook the regular realtime rmap code when an rtrmapbt repair operation is running so that we can unlock the AGF buffer to scan the filesystem and keep the in-memory btree up to date during the scan.
--- fs/xfs/scrub/rmap_repair.c | 2 - fs/xfs/scrub/rtrmap_repair.c | 131 +++++++++++++++++++++++++++++++++++++++++- fs/xfs/scrub/trace.h | 17 ++++- 3 files changed, 140 insertions(+), 10 deletions(-)
fs/xfs/scrub/rmap_repair.c +1 -1
@@ -1614,7 +1614,7 @@ xrep_rmapbt_live_update(if (!xrep_rmapbt_want_live_update (&rr->iscan, &p->oinfo)) goto out_unlock; -trace_xrep_rmap_live_update (rr->sc->sa.pag, action, p); +trace_xrep_rmap_live_update (pag_group (rr->sc->sa.pag), action, p); error =xrep_trans_alloc_hook_dummy (mp, &txcookie, &tp);if (error)
fs/xfs/scrub/rtrmap_repair.c +127 -4
210 lines not on this page · raw message
fs/xfs/scrub/trace.h +12 -5
@@ -41,6 +41,9 @@ struct xchk_dirtree_outcomes;TRACE_DEFINE_ENUM (XFS_REFC_DOMAIN_SHARED );TRACE_DEFINE_ENUM (XFS_REFC_DOMAIN_COW ); +TRACE_DEFINE_ENUM (XG_TYPE_AG ); +TRACE_DEFINE_ENUM (XG_TYPE_RTG ); +TRACE_DEFINE_ENUM (XFS_SCRUB_TYPE_PROBE );TRACE_DEFINE_ENUM (XFS_SCRUB_TYPE_SB );TRACE_DEFINE_ENUM (XFS_SCRUB_TYPE_AGF );
@@ -2709,11 +2712,12 @@ DEFINE_SCRUB_NLINKS_DIFF_EVENT(xrep_nlinks_update_inode);DEFINE_SCRUB_NLINKS_DIFF_EVENT (xrep_nlinks_unfixable_inode); TRACE_EVENT(xrep_rmap_live_update, - TP_PROTO(const struct xfs_perag *pag, unsigned int op, + TP_PROTO(const struct xfs_group *xg, unsigned int op, const struct xfs_rmap_update_params *p), - TP_ARGS(pag, op, p), + TP_ARGS(xg, op, p), TP_STRUCT__entry( __field(dev_t, dev) + __field(enum xfs_group_type, type) __field(xfs_agnumber_t, agno) __field(unsigned int, op) __field(xfs_agblock_t, agbno)
@@ -2723,8 +2727,9 @@ TRACE_EVENT(xrep_rmap_live_update, __field(unsigned int, flags) ),TP_fast_assign ( - __entry->dev = pag_mount(pag)->m_super->s_dev; - __entry->agno =pag_agno (pag); + __entry->dev = xg->xg_mount->m_super->s_dev; + __entry->type = xg->xg_type; + __entry->agno = xg->xg_gno; __entry->op = op; __entry->agbno = p->startblock; __entry->len = p->blockcount;
@@ -2733,10 +2738,12 @@ TRACE_EVENT(xrep_rmap_live_update,if (p->unwritten) __entry->flags |=XFS_RMAP_UNWRITTEN ; ), - TP_printk("dev %d:%d agno 0x%x op %d agbno 0x%x fsbcount 0x%x owner 0x%llx fileoff 0x%llx flags 0x%x", + TP_printk("dev %d:%d %sno 0x%x op %d %sbno 0x%x fsbcount 0x%x owner 0x%llx fileoff 0x%llx flags 0x%x", MAJOR(__entry->dev), MINOR(__entry->dev), + __print_symbolic(__entry->type, XG_TYPE_STRINGS), __entry->agno, __entry->op, + __print_symbolic(__entry->type, XG_TYPE_STRINGS), __entry->agbno, __entry->len, __entry->owner,
PATCH 35/37 xfs: don't shut down the filesystem for media failures beyond end of log
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
If the filesystem has an external log device on pmem and the pmem reports a media error beyond the end of the log area, don't shut down the filesystem because we don't use that space.
--- fs/xfs/xfs_notify_failure.c | 121 +++++++++++++++++++++++++++++-------------- 1 file changed, 82 insertions(+), 39 deletions(-)
fs/xfs/xfs_notify_failure.c +82 -39
@@ -153,6 +153,79 @@ xfs_dax_notify_failure_thaw(thaw_super (sb,FREEZE_HOLDER_USERSPACE ); } +static int +xfs_dax_translate_range ( +struct xfs_buftarg *btp, +u64 offset, +u64 len, +xfs_daddr_t *daddr, +uint64_t *bblen) +{ +u64 dev_start = btp->bt_dax_part_off; +u64 dev_len =bdev_nr_bytes (btp->bt_bdev); +u64 dev_end = dev_start + dev_len -1 ; + +/* Notify failure on the whole device. */ +if (offset ==0 && len ==U64_MAX ) { + offset = dev_start; + len = dev_len; + } + +/* Ignore the range out of filesystem area */ +if (offset + len -1 < dev_start) +return -ENXIO ; +if (offset > dev_end) +return -ENXIO ; + +/* Calculate the real range when it touches the boundary */ +if (offset > dev_start) + offset -= dev_start; +else { + len -= dev_start - offset; + offset =0 ; + } +if (offset + len -1 > dev_end) + len = dev_end - offset +1 ; + + *daddr =BTOBB (offset); + *bblen =BTOBB (len); +return 0 ; +} + +static int +xfs_dax_notify_logdev_failure ( +struct xfs_mount *mp, +u64 offset, +u64 len, +int mf_flags) +{ +xfs_daddr_t daddr; +uint64_t bblen; +int error; + +/* +* Return ENXIO instead of shutting down the filesystem if the failed +* region is beyond the end of the log. +*/ + error =xfs_dax_translate_range (mp->m_logdev_targp, + offset, len, &daddr, &bblen); +if (error) +return error; + +/* +* In the pre-remove case the failure notification is attempting to +* trigger a force unmount. The expectation is that the device is +* still present, but its removal is in progress and can not be +* cancelled, proceed with accessing the log device. +*/ +if (mf_flags &MF_MEM_PRE_REMOVE ) +return 0 ; + +xfs_err (mp,"ondisk log corrupt, shutting down fs!" ); +xfs_force_shutdown (mp,SHUTDOWN_CORRUPT_ONDISK ); +return -EFSCORRUPTED ; +} + static int xfs_dax_notify_ddev_failure( struct xfs_mount *mp,
@@ -263,8 +336,9 @@ xfs_dax_notify_failure( int mf_flags) {struct xfs_mount *mp =dax_holder (dax_dev); -u64 ddev_start; -u64 ddev_end; +xfs_daddr_t daddr; +uint64_t bblen; +int error;if (!(mp->m_super->s_flags &SB_BORN )) {xfs_warn (mp,"filesystem is not ready for notify_failure()!" );
@@ -279,17 +353,7 @@ xfs_dax_notify_failure(if (mp->m_logdev_targp && mp->m_logdev_targp->bt_daxdev == dax_dev && mp->m_logdev_targp != mp->m_ddev_targp) { -/* -* In the pre-remove case the failure notification is attempting -* to trigger a force unmount. The expectation is that the -* device is still present, but its removal is in progress and -* can not be cancelled, proceed with accessing the log device. -*/ -if (mf_flags &MF_MEM_PRE_REMOVE ) -return 0 ; -xfs_err (mp,"ondisk log corrupt, shutting down fs!" ); -xfs_force_shutdown (mp,SHUTDOWN_CORRUPT_ONDISK ); -return -EFSCORRUPTED ; +return xfs_dax_notify_logdev_failure (mp, offset, len, mf_flags); }if (!xfs_has_rmapbt (mp)) {
@@ -297,33 +361,12 @@ xfs_dax_notify_failure(return -EOPNOTSUPP ; } - ddev_start = mp->m_ddev_targp->bt_dax_part_off; - ddev_end = ddev_start +bdev_nr_bytes (mp->m_ddev_targp->bt_bdev) -1 ; + error =xfs_dax_translate_range (mp->m_ddev_targp, offset, len, &daddr, + &bblen); +if (error) +return error; -/* Notify failure on the whole device. */ -if (offset ==0 && len ==U64_MAX ) { - offset = ddev_start; - len =bdev_nr_bytes (mp->m_ddev_targp->bt_bdev); - } - -/* Ignore the range out of filesystem area */ -if (offset + len -1 < ddev_start) -return -ENXIO ; -if (offset > ddev_end) -return -ENXIO ; - -/* Calculate the real range when it touches the boundary */ -if (offset > ddev_start) - offset -= ddev_start; -else { - len -= ddev_start - offset; - offset =0 ; - } -if (offset + len -1 > ddev_end) - len = ddev_end - offset +1 ; - -return xfs_dax_notify_ddev_failure (mp,BTOBB (offset),BTOBB (len), - mf_flags); +return xfs_dax_notify_ddev_failure (mp, daddr, bblen, mf_flags); }const struct dax_holder_operations xfs_dax_holder_operations = {
PATCH 36/37 xfs: react to fsdax failure notifications on the rt device
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Now that we have reverse mapping for the realtime device, use the information to kill processes that have mappings to bad pmem. This requires refactoring the existing routines to handle rtgroups or AGs; and splitting out the translation function to improve cohesion. Also make a proper header file for the dax holder ops.
--- fs/xfs/xfs_buf.c | 1 fs/xfs/xfs_notify_failure.c | 127 ++++++++++++++++++++++++------------------- fs/xfs/xfs_notify_failure.h | 11 ++++ fs/xfs/xfs_super.h | 1 4 files changed, 84 insertions(+), 56 deletions(-) create mode 100644 fs/xfs/xfs_notify_failure.h
fs/xfs/xfs_buf.c +1 -0
@@ -22,6 +22,7 @@#include "xfs_error.h" #include "xfs_ag.h" #include "xfs_buf_mem.h" +#include "xfs_notify_failure.h" struct kmem_cache *xfs_buf_cache;
fs/xfs/xfs_notify_failure.c +72 -55
184 lines not on this page · raw message
fs/xfs/xfs_notify_failure.h new file +11 -0
@@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* +* Copyright (C) 2024 Oracle. All Rights Reserved. +* Author: Darrick J. Wong <[email protected]> +*/ +#ifndef __XFS_NOTIFY_FAILURE_H__ +#define __XFS_NOTIFY_FAILURE_H__ + +extern const struct dax_holder_operations xfs_dax_holder_operations; + +#endif /* __XFS_NOTIFY_FAILURE_H__ */
fs/xfs/xfs_super.h +0 -1
@@ -92,7 +92,6 @@ extern xfs_agnumber_t xfs_set_inode_alloc(struct xfs_mount *,extern const struct export_operations xfs_export_operations;extern const struct quotactl_ops xfs_quotactl_operations; -extern const struct dax_holder_operations xfs_dax_holder_operations;extern void xfs_reinit_percpu_counters (struct xfs_mount *mp);
PATCH 37/37 xfs: enable realtime rmap btree
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Permit mounting filesystems with realtime rmap btrees.
--- fs/xfs/xfs_rtalloc.c | 12 ++++++++---- fs/xfs/xfs_super.c | 6 ------ 2 files changed, 8 insertions(+), 10 deletions(-)
fs/xfs/xfs_rtalloc.c +8 -4
@@ -1282,11 +1282,15 @@ xfs_growfs_rt( XFS_FSB_TO_B(mp, in->extsize) < XFS_MIN_RTEXTSIZE) goto out_unlock; -/* Unsupported realtime features. */ +/* Check for features supported only on rtgroups filesystems. */ error = -EOPNOTSUPP ; -if (xfs_has_quota (mp) && !xfs_has_rtgroups (mp)) - goto out_unlock; -if (xfs_has_rmapbt (mp) ||xfs_has_reflink (mp)) +if (!xfs_has_rtgroups (mp)) { +if (xfs_has_rmapbt (mp)) + goto out_unlock; +if (xfs_has_quota (mp)) + goto out_unlock; + } +if (xfs_has_reflink (mp)) goto out_unlock; error =xfs_sb_validate_fsb_count (&mp->m_sb, in->newblocks);
fs/xfs/xfs_super.c +0 -6
@@ -1767,12 +1767,6 @@ xfs_fs_fill_super( } } -if (xfs_has_rmapbt (mp) && mp->m_sb.sb_rblocks) { -xfs_alert (mp, -"reverse mapping btree not compatible with realtime device!" ); - error = -EINVAL ; - goto out_filestream_unmount; - }if (xfs_has_exchange_range (mp))xfs_warn_experimental (mp,XFS_EXPERIMENTAL_EXCHRANGE );
PATCH 5/5 xfs: reflink on the realtime device
In reply to Darrick J. WongHi all,
This patchset enables use of the file data block sharing feature (i.e. reflink) on the realtime device. It follows the same basic sequence as the realtime rmap series -- first a few cleanups; then introduction of the new btree format and inode fork format. Next comes enabling CoW and remapping for the rt device; new scrub, repair, and health reporting code; and at the end we implement some code to lengthen write requests so that rt extents are always CoWed fully.
If you're going to start using this code, I strongly recommend pulling from my git trees, which are linked below.
This has been running on the djcloud for months with no problems. Enjoy! Comments and questions are, as always, welcome.
--D
kernel git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-linux.git/log/?h=realtime-reflink
xfsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=realtime-reflink
fstests git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfstests-dev.git/log/?h=realtime-reflink
xfsdocs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-documentation.git/log/?h=realtime-reflink
---
Commits in this patchset:
* xfs: prepare refcount btree cursor tracepoints for realtime
* xfs: namespace the maximum length/refcount symbols
* xfs: introduce realtime refcount btree ondisk definitions
* xfs: realtime refcount btree transaction reservations
* xfs: add realtime refcount btree operations
* xfs: prepare refcount functions to deal with rtrefcountbt
* xfs: add a realtime flag to the refcount update log redo items
* xfs: support recovering refcount intent items targetting realtime extents
* xfs: add realtime refcount btree block detection to log recovery
* xfs: add realtime refcount btree inode to metadata directory
* xfs: add metadata reservations for realtime refcount btree
* xfs: wire up a new metafile type for the realtime refcount
* xfs: refactor xfs_reflink_find_shared
* xfs: wire up realtime refcount btree cursors
* xfs: create routine to allocate and initialize a realtime refcount btree inode
* xfs: update rmap to allow cow staging extents in the rt rmap
* xfs: compute rtrmap btree max levels when reflink enabled
* xfs: refactor reflink quota updates
* xfs: enable CoW for realtime data
* xfs: enable sharing of realtime file blocks
* xfs: allow inodes to have the realtime and reflink flags
* xfs: recover CoW leftovers in the realtime volume
* xfs: fix xfs_get_extsz_hint behavior with realtime alwayscow files
* xfs: apply rt extent alignment constraints to CoW extsize hint
* xfs: enable extent size hints for CoW operations
* xfs: check that the rtrefcount maxlevels doesn't increase when growing fs
* xfs: report realtime refcount btree corruption errors to the health system
* xfs: scrub the realtime refcount btree
* xfs: cross-reference checks with the rt refcount btree
* xfs: allow overlapping rtrmapbt records for shared data extents
* xfs: check reference counts of gaps between rt refcount records
* xfs: allow dquot rt block count to exceed rt blocks on reflink fs
* xfs: detect and repair misaligned rtinherit directory cowextsize hints
* xfs: scrub the metadir path of rt refcount btree files
* xfs: don't flag quota rt block usage on rtreflink filesystems
* xfs: check new rtbitmap records against rt refcount btree
* xfs: walk the rt reference count tree when rebuilding rmap
* xfs: capture realtime CoW staging extents when rebuilding rt rmapbt
* xfs: online repair of the realtime refcount btree
* xfs: repair inodes that have a refcount btree in the data fork
* xfs: check for shared rt extents when rebuilding rt file's data fork
* xfs: fix CoW forks for realtime files
* xfs: enable realtime reflink
--- fs/xfs/Makefile | 3 fs/xfs/libxfs/xfs_bmap.c | 23 + fs/xfs/libxfs/xfs_btree.c | 5 fs/xfs/libxfs/xfs_btree.h | 2 fs/xfs/libxfs/xfs_defer.h | 1 fs/xfs/libxfs/xfs_format.h | 25 + fs/xfs/libxfs/xfs_fs.h | 7 fs/xfs/libxfs/xfs_health.h | 4 fs/xfs/libxfs/xfs_inode_buf.c | 33 + fs/xfs/libxfs/xfs_inode_fork.c | 6 fs/xfs/libxfs/xfs_log_format.h | 6 fs/xfs/libxfs/xfs_log_recover.h | 2 fs/xfs/libxfs/xfs_ondisk.h | 2 fs/xfs/libxfs/xfs_refcount.c | 276 ++++++++++-- fs/xfs/libxfs/xfs_refcount.h | 23 + fs/xfs/libxfs/xfs_rmap.c | 7 fs/xfs/libxfs/xfs_rtgroup.c | 19 + fs/xfs/libxfs/xfs_rtgroup.h | 11 fs/xfs/libxfs/xfs_rtrefcount_btree.c | 757 +++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_rtrefcount_btree.h | 189 ++++++++ fs/xfs/libxfs/xfs_rtrmap_btree.c | 28 + fs/xfs/libxfs/xfs_sb.c | 8 fs/xfs/libxfs/xfs_shared.h | 7 fs/xfs/libxfs/xfs_trans_resv.c | 25 + fs/xfs/scrub/agheader_repair.c | 2 fs/xfs/scrub/bmap.c | 30 + fs/xfs/scrub/bmap_repair.c | 21 + fs/xfs/scrub/common.c | 10 fs/xfs/scrub/common.h | 5 fs/xfs/scrub/cow_repair.c | 180 +++++++- fs/xfs/scrub/health.c | 1 fs/xfs/scrub/inode.c | 31 + fs/xfs/scrub/inode_repair.c | 57 ++ fs/xfs/scrub/metapath.c | 3 fs/xfs/scrub/quota.c | 8 fs/xfs/scrub/quota_repair.c | 2 fs/xfs/scrub/reap.c | 247 ++++++++++- fs/xfs/scrub/reap.h | 7 fs/xfs/scrub/refcount.c | 2 fs/xfs/scrub/refcount_repair.c | 6 fs/xfs/scrub/repair.c | 6 fs/xfs/scrub/repair.h | 7 fs/xfs/scrub/rgb_bitmap.h | 37 ++ fs/xfs/scrub/rmap_repair.c | 7 fs/xfs/scrub/rtb_bitmap.h | 37 ++ fs/xfs/scrub/rtbitmap.c | 2 fs/xfs/scrub/rtbitmap_repair.c | 24 + fs/xfs/scrub/rtrefcount.c | 661 +++++++++++++++++++++++++++++ fs/xfs/scrub/rtrefcount_repair.c | 783 ++++++++++++++++++++++++++++++++++ fs/xfs/scrub/rtrmap.c | 54 ++ fs/xfs/scrub/rtrmap_repair.c | 103 ++++ fs/xfs/scrub/scrub.c | 7 fs/xfs/scrub/scrub.h | 12 + fs/xfs/scrub/stats.c | 1 fs/xfs/scrub/trace.h | 54 +- fs/xfs/xfs_buf_item_recover.c | 4 fs/xfs/xfs_fsmap.c | 25 + fs/xfs/xfs_fsops.c | 2 fs/xfs/xfs_health.c | 1 fs/xfs/xfs_inode_item.c | 14 + fs/xfs/xfs_inode_item_recover.c | 4 fs/xfs/xfs_ioctl.c | 21 + fs/xfs/xfs_log_recover.c | 2 fs/xfs/xfs_mount.c | 5 fs/xfs/xfs_mount.h | 9 fs/xfs/xfs_refcount_item.c | 240 ++++++++++ fs/xfs/xfs_reflink.c | 325 ++++++++++---- fs/xfs/xfs_reflink.h | 4 fs/xfs/xfs_rtalloc.c | 24 + fs/xfs/xfs_rtalloc.h | 5 fs/xfs/xfs_stats.c | 3 fs/xfs/xfs_stats.h | 1 fs/xfs/xfs_super.c | 6 fs/xfs/xfs_trace.h | 111 +++-- 74 files changed, 4330 insertions(+), 352 deletions(-) create mode 100644 fs/xfs/libxfs/xfs_rtrefcount_btree.c create mode 100644 fs/xfs/libxfs/xfs_rtrefcount_btree.h create mode 100644 fs/xfs/scrub/rgb_bitmap.h create mode 100644 fs/xfs/scrub/rtb_bitmap.h create mode 100644 fs/xfs/scrub/rtrefcount.c create mode 100644 fs/xfs/scrub/rtrefcount_repair.c
PATCH 1/43 xfs: prepare refcount btree cursor tracepoints for realtime
From: Darrick J. Wong <[email protected]>
Rework the refcount btree cursor tracepoints in preparation to handle the realtime refcount btree cursor. Mostly this involves renaming the field to "refcbno" and extracting the group number from the cursor when possible.
--- fs/xfs/xfs_refcount_item.c | 4 +- fs/xfs/xfs_trace.h | 111 +++++++++++++++++++++++++++----------------- 2 files changed, 70 insertions(+), 45 deletions(-)
fs/xfs/xfs_refcount_item.c +2 -2
@@ -328,9 +328,9 @@ xfs_refcount_defer_add( {struct xfs_mount *mp = tp->t_mountp; -trace_xfs_refcount_defer (mp, ri); - ri->ri_group =xfs_group_intent_get (mp, ri->ri_startblock,XG_TYPE_AG ); + +trace_xfs_refcount_defer (mp, ri);xfs_defer_add (tp, &ri->ri_list, &xfs_refcount_update_defer_type); }
fs/xfs/xfs_trace.h +68 -43
298 lines not on this page · raw message
PATCH 2/43 xfs: namespace the maximum length/refcount symbols
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Actually namespace these variables properly, so that readers can tell that this is an XFS symbol, and that it's for the refcount functionality.
--- fs/xfs/libxfs/xfs_format.h | 4 ++-- fs/xfs/libxfs/xfs_refcount.c | 18 +++++++++--------- fs/xfs/scrub/refcount.c | 2 +- fs/xfs/scrub/refcount_repair.c | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-)
fs/xfs/libxfs/xfs_format.h +2 -2
@@ -1790,8 +1790,8 @@ struct xfs_refcount_key {__be32 rc_startblock;/* starting block number */ }; -#define MAXREFCOUNT ((xfs_nlink_t)~0U) -#define MAXREFCEXTLEN ((xfs_extlen_t)~0U) +#define XFS_REFC_REFCOUNT_MAX ((xfs_nlink_t)~0U) +#define XFS_REFC_LEN_MAX ((xfs_extlen_t)~0U)/* btree pointer type */ typedef __be32 xfs_refcount_ptr_t ;
fs/xfs/libxfs/xfs_refcount.c +9 -9
@@ -128,7 +128,7 @@ xfs_refcount_check_irec( struct xfs_perag *pag, const struct xfs_refcount_irec *irec) { -if (irec->rc_blockcount ==0 || irec->rc_blockcount >MAXREFCEXTLEN ) +if (irec->rc_blockcount ==0 || irec->rc_blockcount >XFS_REFC_LEN_MAX )return __this_address;if (!xfs_refcount_check_domain (irec))
@@ -138,7 +138,7 @@ xfs_refcount_check_irec(if (!xfs_verify_agbext (pag, irec->rc_startblock, irec->rc_blockcount))return __this_address; -if (irec->rc_refcount ==0 || irec->rc_refcount >MAXREFCOUNT ) +if (irec->rc_refcount ==0 || irec->rc_refcount >XFS_REFC_REFCOUNT_MAX )return __this_address;return NULL ;
@@ -853,9 +853,9 @@ xfs_refc_merge_refcount( const struct xfs_refcount_irec *irec, enum xfs_refc_adjust_op adjust) { - /* Once a record hits MAXREFCOUNT, it is pinned there forever */ - if (irec->rc_refcount == MAXREFCOUNT) - return MAXREFCOUNT; + /* Once a record hits XFS_REFC_REFCOUNT_MAX, it is pinned forever */ + if (irec->rc_refcount == XFS_REFC_REFCOUNT_MAX) + return XFS_REFC_REFCOUNT_MAX;return irec->rc_refcount + adjust; }
@@ -898,7 +898,7 @@ xfs_refc_want_merge_center(* hence we need to catch u32 addition overflows here. */ ulen += cleft->rc_blockcount + right->rc_blockcount; -if (ulen >=MAXREFCEXTLEN ) +if (ulen >=XFS_REFC_LEN_MAX )return false; *ulenp = ulen;
@@ -933,7 +933,7 @@ xfs_refc_want_merge_left(* hence we need to catch u32 addition overflows here. */ ulen += cleft->rc_blockcount; -if (ulen >=MAXREFCEXTLEN ) +if (ulen >=XFS_REFC_LEN_MAX )return false;return true;
@@ -967,7 +967,7 @@ xfs_refc_want_merge_right(* hence we need to catch u32 addition overflows here. */ ulen += cright->rc_blockcount; -if (ulen >=MAXREFCEXTLEN ) +if (ulen >=XFS_REFC_LEN_MAX )return false;return true;
@@ -1196,7 +1196,7 @@ xfs_refcount_adjust_extents(* Adjust the reference count and either update the tree * (incr) or free the blocks (decr). */ -if (ext.rc_refcount ==MAXREFCOUNT ) +if (ext.rc_refcount ==XFS_REFC_REFCOUNT_MAX ) goto skip; ext.rc_refcount += adj;trace_xfs_refcount_modify_extent (cur, &ext);
fs/xfs/scrub/refcount.c +1 -1
@@ -421,7 +421,7 @@ xchk_refcount_mergeable(if (r1->rc_refcount != r2->rc_refcount)return false;if ((unsigned long long )r1->rc_blockcount + r2->rc_blockcount > -MAXREFCEXTLEN ) +XFS_REFC_LEN_MAX )return false;return true;
fs/xfs/scrub/refcount_repair.c +2 -2
@@ -183,7 +183,7 @@ xrep_refc_stash(if (xchk_should_terminate (sc, &error))return error; - irec.rc_refcount =min_t (uint64_t,MAXREFCOUNT , refcount); + irec.rc_refcount =min_t (uint64_t,XFS_REFC_REFCOUNT_MAX , refcount); error =xrep_refc_check_ext (rr->sc, &irec);if (error)
@@ -422,7 +422,7 @@ xrep_refc_find_refcounts(/* * Set up a bag to store all the rmap records that we're tracking to * generate a reference count record. If the size of the bag exceeds -* MAXREFCOUNT, we clamp rc_refcount. +* XFS_REFC_REFCOUNT_MAX, we clamp rc_refcount. */ error =rcbag_init (sc->mp, sc->xmbtp, &rcstack);if (error)
PATCH 3/43 xfs: introduce realtime refcount btree ondisk definitions
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Add the ondisk structure definitions for realtime refcount btrees. The realtime refcount btree will be rooted from a hidden inode so it needs to have a separate btree block magic and pointer format.
Next, add everything needed to read, write and manipulate refcount btree blocks. This prepares the way for connecting the btree operations implementation, though the changes to actually root the rtrefcount btree in an inode come later.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_btree.c | 5 + fs/xfs/libxfs/xfs_format.h | 9 + fs/xfs/libxfs/xfs_ondisk.h | 1 fs/xfs/libxfs/xfs_rtrefcount_btree.c | 273 ++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_rtrefcount_btree.h | 70 +++++++++ fs/xfs/libxfs/xfs_sb.c | 8 + fs/xfs/libxfs/xfs_shared.h | 7 + fs/xfs/xfs_mount.c | 5 - fs/xfs/xfs_mount.h | 9 + fs/xfs/xfs_stats.c | 3 fs/xfs/xfs_stats.h | 1 12 files changed, 390 insertions(+), 2 deletions(-) create mode 100644 fs/xfs/libxfs/xfs_rtrefcount_btree.c create mode 100644 fs/xfs/libxfs/xfs_rtrefcount_btree.h
fs/xfs/Makefile +1 -0
@@ -51,6 +51,7 @@ xfs-y += $(addprefix libxfs/, \ xfs_rmap_btree.o \ xfs_refcount.o \ xfs_refcount_btree.o \ + xfs_rtrefcount_btree.o \ xfs_rtrmap_btree.o \ xfs_sb.o \ xfs_symlink_remote.o \
fs/xfs/libxfs/xfs_btree.c +5 -0
@@ -35,6 +35,7 @@#include "xfs_rmap.h" #include "xfs_quota.h" #include "xfs_metafile.h" +#include "xfs_rtrefcount_btree.h" /* * Btree magic numbers.
@@ -5533,6 +5534,9 @@ xfs_btree_init_cur_caches(void)if (error) goto err; error =xfs_rtrmapbt_init_cur_cache (); +if (error) + goto err; + error =xfs_rtrefcountbt_init_cur_cache ();if (error) goto err;
@@ -5552,6 +5556,7 @@ xfs_btree_destroy_cur_caches(void)xfs_rmapbt_destroy_cur_cache ();xfs_refcountbt_destroy_cur_cache ();xfs_rtrmapbt_destroy_cur_cache (); +xfs_rtrefcountbt_destroy_cur_cache (); }/* Move the btree cursor before the first record. */
fs/xfs/libxfs/xfs_format.h +9 -0
@@ -1796,6 +1796,15 @@ struct xfs_refcount_key {/* btree pointer type */ typedef __be32 xfs_refcount_ptr_t ; +/* +* Realtime Reference Count btree format definitions +* +* This is a btree for reference count records for realtime volumes +*/ +#define XFS_RTREFC_CRC_MAGIC 0x52434e54/* 'RCNT' */ + +/* inode-rooted btree pointer type */ +typedef __be64 xfs_rtrefcount_ptr_t ;/* * BMAP Btree format definitions
fs/xfs/libxfs/xfs_ondisk.h +1 -0
@@ -85,6 +85,7 @@ xfs_check_ondisk_structs(void) XFS_CHECK_STRUCT_SIZE(struct xfs_rtbuf_blkinfo, 48);XFS_CHECK_STRUCT_SIZE (xfs_rtrmap_ptr_t,8 ); XFS_CHECK_STRUCT_SIZE(struct xfs_rtrmap_root, 4); +XFS_CHECK_STRUCT_SIZE (xfs_rtrefcount_ptr_t,8 );/* * m68k has problems with struct xfs_attr_leaf_name_remote, but we pad
fs/xfs/libxfs/xfs_rtrefcount_btree.c new file +273 -0
273 lines not on this page · raw message
fs/xfs/libxfs/xfs_rtrefcount_btree.h new file +70 -0
70 lines not on this page · raw message
fs/xfs/libxfs/xfs_sb.c +8 -0
@@ -29,6 +29,7 @@#include "xfs_exchrange.h" #include "xfs_rtgroup.h" #include "xfs_rtrmap_btree.h" +#include "xfs_rtrefcount_btree.h" /* * Physical superblock buffer manipulations. Shared with libxfs in userspace.
@@ -1226,6 +1227,13 @@ xfs_sb_mount_common( mp->m_refc_mnr[0 ] = mp->m_refc_mxr[0 ] /2 ; mp->m_refc_mnr[1 ] = mp->m_refc_mxr[1 ] /2 ; + mp->m_rtrefc_mxr[0 ] =xfs_rtrefcountbt_maxrecs (mp, sbp->sb_blocksize, + true); + mp->m_rtrefc_mxr[1 ] =xfs_rtrefcountbt_maxrecs (mp, sbp->sb_blocksize, + false); + mp->m_rtrefc_mnr[0 ] = mp->m_rtrefc_mxr[0 ] /2 ; + mp->m_rtrefc_mnr[1 ] = mp->m_rtrefc_mxr[1 ] /2 ; + mp->m_bsize =XFS_FSB_TO_BB (mp,1 ); mp->m_alloc_set_aside =xfs_alloc_set_aside (mp); mp->m_ag_max_usable =xfs_alloc_ag_max_usable (mp);
fs/xfs/libxfs/xfs_shared.h +7 -0
@@ -42,6 +42,7 @@ extern const struct xfs_buf_ops xfs_rtbitmap_buf_ops;extern const struct xfs_buf_ops xfs_rtsummary_buf_ops;extern const struct xfs_buf_ops xfs_rtbuf_ops;extern const struct xfs_buf_ops xfs_rtsb_buf_ops; +extern const struct xfs_buf_ops xfs_rtrefcountbt_buf_ops;extern const struct xfs_buf_ops xfs_rtrmapbt_buf_ops;extern const struct xfs_buf_ops xfs_sb_buf_ops;extern const struct xfs_buf_ops xfs_sb_quiet_buf_ops;
@@ -58,6 +59,7 @@ extern const struct xfs_btree_ops xfs_rmapbt_ops;extern const struct xfs_btree_ops xfs_rmapbt_mem_ops;extern const struct xfs_btree_ops xfs_rtrmapbt_ops;extern const struct xfs_btree_ops xfs_rtrmapbt_mem_ops; +extern const struct xfs_btree_ops xfs_rtrefcountbt_ops;static inline bool xfs_btree_is_bno (const struct xfs_btree_ops *ops) {
@@ -114,6 +116,11 @@ static inline bool xfs_btree_is_rtrmap(const struct xfs_btree_ops *ops)return ops == &xfs_rtrmapbt_ops; } +static inline bool xfs_btree_is_rtrefcount (const struct xfs_btree_ops *ops) +{ +return ops == &xfs_rtrefcountbt_ops; +} +/* log size calculation functions */ int xfs_log_calc_unit_res (struct xfs_mount *mp,int unit_bytes);int xfs_log_calc_minimum_size (struct xfs_mount *);
fs/xfs/xfs_mount.c +4 -1
@@ -38,6 +38,7 @@#include "xfs_metafile.h" #include "xfs_rtgroup.h" #include "xfs_rtrmap_btree.h" +#include "xfs_rtrefcount_btree.h" #include "scrub/stats.h" static DEFINE_MUTEX (xfs_uuid_table_mutex);
@@ -656,7 +657,8 @@ static inline voidxfs_rtbtree_compute_maxlevels ( struct xfs_mount *mp) { - mp->m_rtbtree_maxlevels = mp->m_rtrmap_maxlevels; + mp->m_rtbtree_maxlevels =max (mp->m_rtrmap_maxlevels, + mp->m_rtrefc_maxlevels); }/*
@@ -729,6 +731,7 @@ xfs_mountfs(xfs_rmapbt_compute_maxlevels (mp);xfs_rtrmapbt_compute_maxlevels (mp);xfs_refcountbt_compute_maxlevels (mp); +xfs_rtrefcountbt_compute_maxlevels (mp);xfs_agbtree_compute_maxlevels (mp);xfs_rtbtree_compute_maxlevels (mp);
fs/xfs/xfs_mount.h +9 -0
@@ -162,11 +162,14 @@ typedef struct xfs_mount {uint m_rtrmap_mnr[2 ];/* min rtrmap btree records */ uint m_refc_mxr[2 ];/* max refc btree records */ uint m_refc_mnr[2 ];/* min refc btree records */ +uint m_rtrefc_mxr[2 ];/* max rtrefc btree records */ +uint m_rtrefc_mnr[2 ];/* min rtrefc btree records */ uint m_alloc_maxlevels;/* max alloc btree levels */ uint m_bm_maxlevels[2 ];/* max bmap btree levels */ uint m_rmap_maxlevels;/* max rmap btree levels */ uint m_rtrmap_maxlevels;/* max rtrmap btree level */ uint m_refc_maxlevels;/* max refcount btree level */ +uint m_rtrefc_maxlevels;/* max rtrefc btree level */ unsigned int m_agbtree_maxlevels;/* max level of all AG btrees */ unsigned int m_rtbtree_maxlevels;/* max level of all rt btrees */ xfs_extlen_t m_ag_prealloc_blocks;/* reserved ag blocks */
@@ -408,6 +411,12 @@ static inline bool xfs_has_rtrmapbt(struct xfs_mount *mp)xfs_has_rmapbt (mp); } +static inline bool xfs_has_rtreflink (struct xfs_mount *mp) +{ +return xfs_has_metadir (mp) &&xfs_has_realtime (mp) && +xfs_has_reflink (mp); +} +/* * Some features are always on for v5 file systems, allow the compiler to * eliminiate dead code when building without v4 support.
fs/xfs/xfs_stats.c +2 -1
@@ -54,7 +54,8 @@ int xfs_stats_format(struct xfsstats __percpu *stats, char *buf) { "rmapbt_mem", xfsstats_offset(xs_rcbag_2) }, { "rcbagbt", xfsstats_offset(xs_rtrmap_2) }, { "rtrmapbt", xfsstats_offset(xs_rtrmap_mem_2)}, - { "rtrmapbt_mem", xfsstats_offset(xs_qm_dqreclaims)}, + { "rtrmapbt_mem", xfsstats_offset(xs_rtrefcbt_2) }, + { "rtrefcntbt", xfsstats_offset(xs_qm_dqreclaims)},/* we print both series of quota information together */ { "qm", xfsstats_offset(xs_xstrat_bytes)}, };
fs/xfs/xfs_stats.h +1 -0
@@ -129,6 +129,7 @@ struct __xfsstats {uint32_t xs_rcbag_2[__XBTS_MAX];uint32_t xs_rtrmap_2[__XBTS_MAX];uint32_t xs_rtrmap_mem_2[__XBTS_MAX]; +uint32_t xs_rtrefcbt_2[__XBTS_MAX];uint32_t xs_qm_dqreclaims;uint32_t xs_qm_dqreclaim_misses;uint32_t xs_qm_dquot_dups;
PATCH 4/43 xfs: realtime refcount btree transaction reservations
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Make sure that there's enough log reservation to handle mapping and unmapping realtime extents. We have to reserve enough space to handle a split in the rtrefcountbt to add the record and a second split in the regular refcountbt to record the rtrefcountbt split.
--- fs/xfs/libxfs/xfs_trans_resv.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-)
fs/xfs/libxfs/xfs_trans_resv.c +22 -3
@@ -92,6 +92,14 @@ xfs_refcountbt_block_count(return num_ops * (2 * mp->m_refc_maxlevels -1 ); } +static unsigned int +xfs_rtrefcountbt_block_count ( +struct xfs_mount *mp, +unsigned int num_ops) +{ +return num_ops * (2 * mp->m_rtrefc_maxlevels -1 ); +} +/* * Logging inodes is really tricksy. They are logged in memory format, * which means that what we write into the log doesn't directly translate into
@@ -259,10 +267,13 @@ xfs_rtalloc_block_count(* Compute the log reservation required to handle the refcount update * transaction. Refcount updates are always done via deferred log items. * -* This is calculated as: +* This is calculated as the max of: * Data device refcount updates (t1): * the agfs of the ags containing the blocks: nr_ops * sector size * the refcount btrees: nr_ops * 1 trees * (2 * max depth - 1) * block size +* Realtime refcount updates (t2); +* the rt refcount inode +* the rtrefcount btrees: nr_ops * 1 trees * (2 * max depth - 1) * block size */ static unsigned int xfs_calc_refcountbt_reservation(
@@ -270,12 +281,20 @@ xfs_calc_refcountbt_reservation( unsigned int nr_ops) {unsigned int blksz =XFS_FSB_TO_B (mp,1 ); +unsigned int t1, t2 =0 ;if (!xfs_has_reflink (mp))return 0 ; -return xfs_calc_buf_res (nr_ops, mp->m_sb.sb_sectsize) + -xfs_calc_buf_res (xfs_refcountbt_block_count (mp, nr_ops), blksz); + t1 =xfs_calc_buf_res (nr_ops, mp->m_sb.sb_sectsize) + +xfs_calc_buf_res (xfs_refcountbt_block_count (mp, nr_ops), blksz); + +if (xfs_has_realtime (mp)) + t2 =xfs_calc_inode_res (mp,1 ) + +xfs_calc_buf_res (xfs_rtrefcountbt_block_count (mp, nr_ops), + blksz); + +return max (t1, t2); }/*
PATCH 5/43 xfs: add realtime refcount btree operations
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Implement the generic btree operations needed to manipulate rtrefcount btree blocks. This is different from the regular refcountbt in that we allocate space from the filesystem at large, and are neither constrained to the free space nor any particular AG.
--- fs/xfs/libxfs/xfs_rtrefcount_btree.c | 148 ++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+)
fs/xfs/libxfs/xfs_rtrefcount_btree.c +148 -0
@@ -19,6 +19,7 @@#include "xfs_btree.h" #include "xfs_btree_staging.h" #include "xfs_rtrefcount_btree.h" +#include "xfs_refcount.h" #include "xfs_trace.h" #include "xfs_cksum.h" #include "xfs_error.h"
@@ -45,6 +46,106 @@ xfs_rtrefcountbt_dup_cursor(return xfs_rtrefcountbt_init_cursor (cur->bc_tp,to_rtg (cur->bc_group)); } +STATIC int +xfs_rtrefcountbt_get_minrecs ( +struct xfs_btree_cur *cur, +int level) +{ +if (level == cur->bc_nlevels -1 ) { +struct xfs_ifork *ifp =xfs_btree_ifork_ptr (cur); + +return xfs_rtrefcountbt_maxrecs (cur->bc_mp, ifp->if_broot_bytes, + level ==0 ) /2 ; + } + +return cur->bc_mp->m_rtrefc_mnr[level !=0 ]; +} + +STATIC int +xfs_rtrefcountbt_get_maxrecs ( +struct xfs_btree_cur *cur, +int level) +{ +if (level == cur->bc_nlevels -1 ) { +struct xfs_ifork *ifp =xfs_btree_ifork_ptr (cur); + +return xfs_rtrefcountbt_maxrecs (cur->bc_mp, ifp->if_broot_bytes, + level ==0 ); + } + +return cur->bc_mp->m_rtrefc_mxr[level !=0 ]; +} + +STATIC void +xfs_rtrefcountbt_init_key_from_rec ( +union xfs_btree_key *key, +const union xfs_btree_rec *rec) +{ + key->refc.rc_startblock = rec->refc.rc_startblock; +} + +STATIC void +xfs_rtrefcountbt_init_high_key_from_rec ( +union xfs_btree_key *key, +const union xfs_btree_rec *rec) +{ +__u32 x; + + x =be32_to_cpu (rec->refc.rc_startblock); + x +=be32_to_cpu (rec->refc.rc_blockcount) -1 ; + key->refc.rc_startblock =cpu_to_be32 (x); +} + +STATIC void +xfs_rtrefcountbt_init_rec_from_cur ( +struct xfs_btree_cur *cur, +union xfs_btree_rec *rec) +{ +const struct xfs_refcount_irec *irec = &cur->bc_rec.rc; +uint32_t start; + + start =xfs_refcount_encode_startblock (irec->rc_startblock, + irec->rc_domain); + rec->refc.rc_startblock =cpu_to_be32 (start); + rec->refc.rc_blockcount =cpu_to_be32 (cur->bc_rec.rc.rc_blockcount); + rec->refc.rc_refcount =cpu_to_be32 (cur->bc_rec.rc.rc_refcount); +} + +STATIC void +xfs_rtrefcountbt_init_ptr_from_cur ( +struct xfs_btree_cur *cur, +union xfs_btree_ptr *ptr) +{ + ptr->l =0 ; +} + +STATIC int64_t +xfs_rtrefcountbt_key_diff ( +struct xfs_btree_cur *cur, +const union xfs_btree_key *key) +{ +const struct xfs_refcount_key *kp = &key->refc; +const struct xfs_refcount_irec *irec = &cur->bc_rec.rc; +uint32_t start; + + start =xfs_refcount_encode_startblock (irec->rc_startblock, + irec->rc_domain); +return (int64_t )be32_to_cpu (kp->rc_startblock) - start; +} + +STATIC int64_t +xfs_rtrefcountbt_diff_two_keys ( +struct xfs_btree_cur *cur, +const union xfs_btree_key *k1, +const union xfs_btree_key *k2, +const union xfs_btree_key *mask) +{ +ASSERT (!mask || mask->refc.rc_startblock); + +return (int64_t )be32_to_cpu (k1->refc.rc_startblock) - +be32_to_cpu (k2->refc.rc_startblock); +} +static xfs_failaddr_t xfs_rtrefcountbt_verify (struct xfs_buf *bp)
@@ -111,6 +212,40 @@ const struct xfs_buf_ops xfs_rtrefcountbt_buf_ops = { .verify_struct = xfs_rtrefcountbt_verify, }; +STATIC int +xfs_rtrefcountbt_keys_inorder ( +struct xfs_btree_cur *cur, +const union xfs_btree_key *k1, +const union xfs_btree_key *k2) +{ +return be32_to_cpu (k1->refc.rc_startblock) < +be32_to_cpu (k2->refc.rc_startblock); +} + +STATIC int +xfs_rtrefcountbt_recs_inorder ( +struct xfs_btree_cur *cur, +const union xfs_btree_rec *r1, +const union xfs_btree_rec *r2) +{ +return be32_to_cpu (r1->refc.rc_startblock) + +be32_to_cpu (r1->refc.rc_blockcount) <= +be32_to_cpu (r2->refc.rc_startblock); +} + +STATIC enum xbtree_key_contig +xfs_rtrefcountbt_keys_contiguous ( +struct xfs_btree_cur *cur, +const union xfs_btree_key *key1, +const union xfs_btree_key *key2, +const union xfs_btree_key *mask) +{ +ASSERT (!mask || mask->refc.rc_startblock); + +return xbtree_key_contig (be32_to_cpu (key1->refc.rc_startblock), +be32_to_cpu (key2->refc.rc_startblock)); +} +const struct xfs_btree_ops xfs_rtrefcountbt_ops = { .name ="rtrefcount" , .type =XFS_BTREE_TYPE_INODE ,
@@ -124,7 +259,20 @@ const struct xfs_btree_ops xfs_rtrefcountbt_ops = { .statoff = XFS_STATS_CALC_INDEX(xs_rtrefcbt_2), .dup_cursor = xfs_rtrefcountbt_dup_cursor, + .alloc_block = xfs_btree_alloc_metafile_block, + .free_block = xfs_btree_free_metafile_block, + .get_minrecs = xfs_rtrefcountbt_get_minrecs, + .get_maxrecs = xfs_rtrefcountbt_get_maxrecs, + .init_key_from_rec = xfs_rtrefcountbt_init_key_from_rec, + .init_high_key_from_rec = xfs_rtrefcountbt_init_high_key_from_rec, + .init_rec_from_cur = xfs_rtrefcountbt_init_rec_from_cur, + .init_ptr_from_cur = xfs_rtrefcountbt_init_ptr_from_cur, + .key_diff = xfs_rtrefcountbt_key_diff, .buf_ops = &xfs_rtrefcountbt_buf_ops, + .diff_two_keys = xfs_rtrefcountbt_diff_two_keys, + .keys_inorder = xfs_rtrefcountbt_keys_inorder, + .recs_inorder = xfs_rtrefcountbt_recs_inorder, + .keys_contiguous = xfs_rtrefcountbt_keys_contiguous, };/* Allocate a new rt refcount btree cursor. */
PATCH 6/43 xfs: prepare refcount functions to deal with rtrefcountbt
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Prepare the high-level refcount functions to deal with the new realtime refcountbt and its slightly different conventions. Provide the ability to talk to either refcountbt or rtrefcountbt formats from the same high level code.
Note that we leave the _recover_cow_leftovers functions for a separate patch so that we can convert it all at once.
--- fs/xfs/libxfs/xfs_refcount.c | 53 ++++++++++++++++++++++++++++++++++++------ fs/xfs/libxfs/xfs_refcount.h | 3 ++ 2 files changed, 48 insertions(+), 8 deletions(-)
fs/xfs/libxfs/xfs_refcount.c +45 -8
@@ -25,6 +25,7 @@#include "xfs_ag.h" #include "xfs_health.h" #include "xfs_refcount_item.h" +#include "xfs_rtgroup.h" struct kmem_cache *xfs_refcount_intent_cache;
@@ -144,6 +145,37 @@ xfs_refcount_check_irec(return NULL ; } +xfs_failaddr_t +xfs_rtrefcount_check_irec ( +struct xfs_rtgroup *rtg, +const struct xfs_refcount_irec *irec) +{ +if (irec->rc_blockcount ==0 || irec->rc_blockcount >XFS_REFC_LEN_MAX ) +return __this_address; + +if (!xfs_refcount_check_domain (irec)) +return __this_address; + +/* check for valid extent range, including overflow */ +if (!xfs_verify_rgbext (rtg, irec->rc_startblock, irec->rc_blockcount)) +return __this_address; + +if (irec->rc_refcount ==0 || irec->rc_refcount >XFS_REFC_REFCOUNT_MAX ) +return __this_address; + +return NULL ; +} + +static inline xfs_failaddr_t +xfs_refcount_check_btrec ( +struct xfs_btree_cur *cur, +const struct xfs_refcount_irec *irec) +{ +if (xfs_btree_is_rtrefcount (cur->bc_ops)) +return xfs_rtrefcount_check_irec (to_rtg (cur->bc_group), irec); +return xfs_refcount_check_irec (to_perag (cur->bc_group), irec); +} + static inline int xfs_refcount_complain_bad_rec( struct xfs_btree_cur *cur,
@@ -152,9 +184,15 @@ xfs_refcount_complain_bad_rec( {struct xfs_mount *mp = cur->bc_mp; -xfs_warn (mp, +if (xfs_btree_is_rtrefcount (cur->bc_ops)) { +xfs_warn (mp, +"RT Refcount BTree record corruption in rtgroup %u detected at %pS!" , + cur->bc_group->xg_gno, fa); + }else { +xfs_warn (mp,"Refcount BTree record corruption in AG %d detected at %pS!" , cur->bc_group->xg_gno, fa); + }xfs_warn (mp,"Start block 0x%x, block count 0x%x, references 0x%x" , irec->rc_startblock, irec->rc_blockcount, irec->rc_refcount);
@@ -180,7 +218,7 @@ xfs_refcount_get_rec(return error;xfs_refcount_btrec_to_irec (rec, irec); - fa =xfs_refcount_check_irec (to_perag (cur->bc_group), irec); + fa =xfs_refcount_check_btrec (cur, irec);if (fa)return xfs_refcount_complain_bad_rec (cur, fa, irec);
@@ -1065,7 +1103,7 @@ xfs_refcount_still_have_space(*/ overhead =xfs_allocfree_block_count (cur->bc_mp, cur->bc_refc.shape_changes); - overhead += cur->bc_mp->m_refc_maxlevels; + overhead += cur->bc_maxlevels; overhead *= cur->bc_mp->m_sb.sb_blocksize;/*
@@ -1117,7 +1155,7 @@ xfs_refcount_adjust_extents(if (error) goto out_error;if (!found_rec || ext.rc_domain !=XFS_REFC_DOMAIN_SHARED ) { - ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks; + ext.rc_startblock =xfs_group_max_blocks (cur->bc_group); ext.rc_blockcount =0 ; ext.rc_refcount =0 ; ext.rc_domain =XFS_REFC_DOMAIN_SHARED ;
@@ -1666,7 +1704,7 @@ xfs_refcount_adjust_cow_extents( goto out_error; }if (!found_rec) { - ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks; + ext.rc_startblock =xfs_group_max_blocks (cur->bc_group); ext.rc_blockcount =0 ; ext.rc_refcount =0 ; ext.rc_domain =XFS_REFC_DOMAIN_COW ;
@@ -1877,8 +1915,7 @@ xfs_refcount_recover_extent(INIT_LIST_HEAD (&rr->rr_list);xfs_refcount_btrec_to_irec (rec, &rr->rr_rrec); -if (xfs_refcount_check_irec (to_perag (cur->bc_group), &rr->rr_rrec) != -NULL || +if (xfs_refcount_check_btrec (cur, &rr->rr_rrec) !=NULL ||XFS_IS_CORRUPT (cur->bc_mp, rr->rr_rrec.rc_domain !=XFS_REFC_DOMAIN_COW )) {xfs_btree_mark_sick (cur);
@@ -2026,7 +2063,7 @@ xfs_refcount_query_range_helper(xfs_failaddr_t fa;xfs_refcount_btrec_to_irec (rec, &irec); - fa =xfs_refcount_check_irec (to_perag (cur->bc_group), &irec); + fa =xfs_refcount_check_btrec (cur, &irec);if (fa)return xfs_refcount_complain_bad_rec (cur, fa, &irec);
fs/xfs/libxfs/xfs_refcount.h +3 -0
@@ -12,6 +12,7 @@ struct xfs_perag;struct xfs_btree_cur ;struct xfs_bmbt_irec ;struct xfs_refcount_irec ; +struct xfs_rtgroup ;extern int xfs_refcount_lookup_le (struct xfs_btree_cur *cur,enum xfs_refc_domain domain,xfs_agblock_t bno,int *stat);
@@ -120,6 +121,8 @@ extern void xfs_refcount_btrec_to_irec(const union xfs_btree_rec *rec, struct xfs_refcount_irec *irec);xfs_failaddr_t xfs_refcount_check_irec (struct xfs_perag *pag,const struct xfs_refcount_irec *irec); +xfs_failaddr_t xfs_rtrefcount_check_irec (struct xfs_rtgroup *rtg, +const struct xfs_refcount_irec *irec);extern int xfs_refcount_insert (struct xfs_btree_cur *cur,struct xfs_refcount_irec *irec,int *stat);
PATCH 7/43 xfs: add a realtime flag to the refcount update log redo items
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Extend the refcount update (CUI) log items with a new realtime flag that indicates that the updates apply against the realtime refcountbt. We'll wire up the actual refcount code later.
--- fs/xfs/libxfs/xfs_bmap.c | 10 +- fs/xfs/libxfs/xfs_defer.h | 1 fs/xfs/libxfs/xfs_log_format.h | 6 + fs/xfs/libxfs/xfs_log_recover.h | 2 fs/xfs/libxfs/xfs_refcount.c | 64 ++++++++--- fs/xfs/libxfs/xfs_refcount.h | 17 ++- fs/xfs/scrub/cow_repair.c | 2 fs/xfs/scrub/reap.c | 5 + fs/xfs/xfs_log_recover.c | 2 fs/xfs/xfs_refcount_item.c | 224 +++++++++++++++++++++++++++++++++++++-- fs/xfs/xfs_reflink.c | 19 ++- 11 files changed, 298 insertions(+), 54 deletions(-)
fs/xfs/libxfs/xfs_bmap.c +6 -4
@@ -4564,8 +4564,9 @@ xfs_bmapi_write(* the refcount btree for orphan recovery. */ if (whichfork ==XFS_COW_FORK ) -xfs_refcount_alloc_cow_extent (tp, bma.blkno, - bma.length); +xfs_refcount_alloc_cow_extent (tp, +XFS_IS_REALTIME_INODE (ip), + bma.blkno, bma.length); }/* Deal with the allocated space we found. */
@@ -4740,7 +4741,8 @@ xfs_bmapi_convert_one_delalloc( *seq =READ_ONCE (ifp->if_seq);if (whichfork ==XFS_COW_FORK ) -xfs_refcount_alloc_cow_extent (tp, bma.blkno, bma.length); +xfs_refcount_alloc_cow_extent (tp,XFS_IS_REALTIME_INODE (ip), + bma.blkno, bma.length); error =xfs_bmap_btree_to_extents (tp, ip, bma.cur, &bma.logflags, whichfork);
@@ -5388,7 +5390,7 @@ xfs_bmap_del_extent_real(bool isrt =xfs_ifork_is_realtime (ip, whichfork);if (xfs_is_reflink_inode (ip) && whichfork ==XFS_DATA_FORK ) { -xfs_refcount_decrease_extent (tp, del); +xfs_refcount_decrease_extent (tp, isrt, del); }else if (isrt && !xfs_has_rtgroups (mp)) { error =xfs_bmap_free_rtblocks (tp, del); }else {
fs/xfs/libxfs/xfs_defer.h +1 -0
@@ -68,6 +68,7 @@ struct xfs_defer_op_type {extern const struct xfs_defer_op_type xfs_bmap_update_defer_type;extern const struct xfs_defer_op_type xfs_refcount_update_defer_type; +extern const struct xfs_defer_op_type xfs_rtrefcount_update_defer_type;extern const struct xfs_defer_op_type xfs_rmap_update_defer_type;extern const struct xfs_defer_op_type xfs_rtrmap_update_defer_type;extern const struct xfs_defer_op_type xfs_extent_free_defer_type;
fs/xfs/libxfs/xfs_log_format.h +5 -1
@@ -252,6 +252,8 @@ typedef struct xfs_trans_header {#define XFS_LI_EFD_RT 0x124b/* realtime extent free done */ #define XFS_LI_RUI_RT 0x124c/* realtime rmap update intent */ #define XFS_LI_RUD_RT 0x124d/* realtime rmap update done */ +#define XFS_LI_CUI_RT 0x124e/* realtime refcount update intent */ +#define XFS_LI_CUD_RT 0x124f/* realtime refcount update done */ #define XFS_LI_TYPE_DESC \ { XFS_LI_EFI, "XFS_LI_EFI" }, \
@@ -275,7 +277,9 @@ typedef struct xfs_trans_header { { XFS_LI_EFI_RT, "XFS_LI_EFI_RT" }, \ { XFS_LI_EFD_RT, "XFS_LI_EFD_RT" }, \ { XFS_LI_RUI_RT, "XFS_LI_RUI_RT" }, \ - { XFS_LI_RUD_RT, "XFS_LI_RUD_RT" } + { XFS_LI_RUD_RT, "XFS_LI_RUD_RT" }, \ + { XFS_LI_CUI_RT, "XFS_LI_CUI_RT" }, \ + { XFS_LI_CUD_RT, "XFS_LI_CUD_RT" }/* * Inode Log Item Format definitions.
fs/xfs/libxfs/xfs_log_recover.h +2 -0
@@ -81,6 +81,8 @@ extern const struct xlog_recover_item_ops xlog_rtefi_item_ops;extern const struct xlog_recover_item_ops xlog_rtefd_item_ops;extern const struct xlog_recover_item_ops xlog_rtrui_item_ops;extern const struct xlog_recover_item_ops xlog_rtrud_item_ops; +extern const struct xlog_recover_item_ops xlog_rtcui_item_ops; +extern const struct xlog_recover_item_ops xlog_rtcud_item_ops;/* * Macros, structures, prototypes for internal log manager use.
fs/xfs/libxfs/xfs_refcount.c +46 -18
166 lines not on this page · raw message
fs/xfs/libxfs/xfs_refcount.h +10 -7
@@ -61,6 +61,7 @@ struct xfs_refcount_intent {enum xfs_refcount_intent_type ri_type;xfs_extlen_t ri_blockcount;xfs_fsblock_t ri_startblock; +bool ri_realtime; };/* Check that the refcount is appropriate for the record domain. */
@@ -75,22 +76,24 @@ xfs_refcount_check_domain(return true; } -void xfs_refcount_increase_extent (struct xfs_trans *tp, +void xfs_refcount_increase_extent (struct xfs_trans *tp,bool isrt,struct xfs_bmbt_irec *irec); -void xfs_refcount_decrease_extent (struct xfs_trans *tp, +void xfs_refcount_decrease_extent (struct xfs_trans *tp,bool isrt,struct xfs_bmbt_irec *irec); -extern int xfs_refcount_finish_one (struct xfs_trans *tp, +int xfs_refcount_finish_one (struct xfs_trans *tp, +struct xfs_refcount_intent *ri,struct xfs_btree_cur **pcur); +int xfs_rtrefcount_finish_one (struct xfs_trans *tp,struct xfs_refcount_intent *ri,struct xfs_btree_cur **pcur);extern int xfs_refcount_find_shared (struct xfs_btree_cur *cur,xfs_agblock_t agbno,xfs_extlen_t aglen,xfs_agblock_t *fbno,xfs_extlen_t *flen,bool find_end_of_shared); -void xfs_refcount_alloc_cow_extent (struct xfs_trans *tp,xfs_fsblock_t fsb, -xfs_extlen_t len); -void xfs_refcount_free_cow_extent (struct xfs_trans *tp,xfs_fsblock_t fsb, -xfs_extlen_t len); +void xfs_refcount_alloc_cow_extent (struct xfs_trans *tp,bool isrt, +xfs_fsblock_t fsb,xfs_extlen_t len); +void xfs_refcount_free_cow_extent (struct xfs_trans *tp,bool isrt, +xfs_fsblock_t fsb,xfs_extlen_t len);extern int xfs_refcount_recover_cow_leftovers (struct xfs_mount *mp,struct xfs_perag *pag);
fs/xfs/scrub/cow_repair.c +1 -1
@@ -343,7 +343,7 @@ xrep_cow_alloc(if (args.fsbno ==NULLFSBLOCK )return -ENOSPC ; -xfs_refcount_alloc_cow_extent (sc->tp, args.fsbno, args.len); +xfs_refcount_alloc_cow_extent (sc->tp, false, args.fsbno, args.len); repl->fsbno = args.fsbno; repl->len = args.len;
fs/xfs/scrub/reap.c +3 -2
@@ -419,7 +419,8 @@ xreap_agextent_iter(* records from the refcountbt, which will remove the * rmap record as well. */ -xfs_refcount_free_cow_extent (sc->tp, fsbno, *aglenp); +xfs_refcount_free_cow_extent (sc->tp, false, fsbno, + *aglenp);return 0 ; }
@@ -451,7 +452,7 @@ xreap_agextent_iter(if (rs->oinfo == &XFS_RMAP_OINFO_COW ) {ASSERT (rs->resv ==XFS_AG_RESV_NONE ); -xfs_refcount_free_cow_extent (sc->tp, fsbno, *aglenp); +xfs_refcount_free_cow_extent (sc->tp, false, fsbno, *aglenp); error =xfs_free_extent_later (sc->tp, fsbno, *aglenp,NULL , rs->resv,XFS_FREE_EXTENT_SKIP_DISCARD );if (error)
fs/xfs/xfs_log_recover.c +2 -0
@@ -1822,6 +1822,8 @@ static const struct xlog_recover_item_ops *xlog_recover_item_ops[] = { &xlog_rtefd_item_ops, &xlog_rtrui_item_ops, &xlog_rtrud_item_ops, + &xlog_rtcui_item_ops, + &xlog_rtcud_item_ops, }; static const struct xlog_recover_item_ops *
fs/xfs/xfs_refcount_item.c +210 -14
337 lines not on this page · raw message
fs/xfs/xfs_reflink.c +12 -7
@@ -571,6 +571,7 @@ xfs_reflink_cancel_cow_blocks(struct xfs_ifork *ifp =xfs_ifork_ptr (ip,XFS_COW_FORK );struct xfs_bmbt_irec got, del;struct xfs_iext_cursor icur; +bool isrt =XFS_IS_REALTIME_INODE (ip);int error =0 ;if (!xfs_inode_has_cow_data (ip))
@@ -598,12 +599,13 @@ xfs_reflink_cancel_cow_blocks(ASSERT ((*tpp)->t_highest_agno ==NULLAGNUMBER );/* Free the CoW orphan record. */ -xfs_refcount_free_cow_extent (*tpp, del.br_startblock, - del.br_blockcount); +xfs_refcount_free_cow_extent (*tpp, isrt, + del.br_startblock, del.br_blockcount); error =xfs_free_extent_later (*tpp, del.br_startblock, del.br_blockcount,NULL , -XFS_AG_RESV_NONE ,0 ); +XFS_AG_RESV_NONE , + isrt ?XFS_FREE_EXTENT_REALTIME :0 );if (error)break ;
@@ -710,6 +712,7 @@ xfs_reflink_end_cow_extent(struct xfs_ifork *ifp =xfs_ifork_ptr (ip,XFS_COW_FORK );unsigned int resblks;int nmaps; +bool isrt =XFS_IS_REALTIME_INODE (ip);int error; resblks =XFS_EXTENTADD_SPACE_RES (mp,XFS_DATA_FORK );
@@ -779,7 +782,7 @@ xfs_reflink_end_cow_extent(* or not), unmap the extent and drop its refcount. */ xfs_bmap_unmap_extent (tp, ip,XFS_DATA_FORK , &data); -xfs_refcount_decrease_extent (tp, &data); +xfs_refcount_decrease_extent (tp, isrt, &data);xfs_trans_mod_dquot_byino (tp, ip,XFS_TRANS_DQ_BCOUNT , -data.br_blockcount); }else if (data.br_startblock ==DELAYSTARTBLOCK ) {
@@ -799,7 +802,8 @@ xfs_reflink_end_cow_extent( }/* Free the CoW orphan record. */ -xfs_refcount_free_cow_extent (tp, del.br_startblock, del.br_blockcount); +xfs_refcount_free_cow_extent (tp, isrt, del.br_startblock, + del.br_blockcount);/* Map the new blocks into the data fork. */ xfs_bmap_map_extent (tp, ip,XFS_DATA_FORK , &del);
@@ -1135,6 +1139,7 @@ xfs_reflink_remap_extent(bool quota_reserved = true;bool smap_real;bool dmap_written =xfs_bmap_is_written_extent (dmap); +bool isrt =XFS_IS_REALTIME_INODE (ip);int iext_delta =0 ;int nimaps;int error;
@@ -1264,7 +1269,7 @@ xfs_reflink_remap_extent(* or not), unmap the extent and drop its refcount. */ xfs_bmap_unmap_extent (tp, ip,XFS_DATA_FORK , &smap); -xfs_refcount_decrease_extent (tp, &smap); +xfs_refcount_decrease_extent (tp, isrt, &smap); qdelta -= smap.br_blockcount; }else if (smap.br_startblock ==DELAYSTARTBLOCK ) {int done;
@@ -1287,7 +1292,7 @@ xfs_reflink_remap_extent(* its refcount and map it into the file. */ if (dmap_written) { -xfs_refcount_increase_extent (tp, dmap); +xfs_refcount_increase_extent (tp, isrt, dmap);xfs_bmap_map_extent (tp, ip,XFS_DATA_FORK , dmap); qdelta += dmap->br_blockcount; }
PATCH 8/43 xfs: support recovering refcount intent items targetting realtime extents
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Now that we have reflink on the realtime device, refcount intent items have to support remapping extents on the realtime volume.
--- fs/xfs/xfs_refcount_item.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
fs/xfs/xfs_refcount_item.c +11 -3
@@ -440,6 +440,7 @@ xfs_refcount_update_abort_intent(static inline bool xfs_cui_validate_phys (struct xfs_mount *mp, +bool isrt,struct xfs_phys_extent *pmap) {if (!xfs_has_reflink (mp))
@@ -458,6 +459,9 @@ xfs_cui_validate_phys(return false; } +if (isrt) +return xfs_verify_rtbext (mp, pmap->pe_startblock, pmap->pe_len); +return xfs_verify_fsbext (mp, pmap->pe_startblock, pmap->pe_len); }
@@ -465,6 +469,7 @@ static inline voidxfs_cui_recover_work ( struct xfs_mount *mp, struct xfs_defer_pending *dfp, + bool isrt, struct xfs_phys_extent *pmap) { struct xfs_refcount_intent *ri;
@@ -475,7 +480,8 @@ xfs_cui_recover_work( ri->ri_startblock = pmap->pe_startblock; ri->ri_blockcount = pmap->pe_len; ri->ri_group =xfs_group_intent_get (mp, pmap->pe_startblock, -XG_TYPE_AG ); + isrt ?XG_TYPE_RTG :XG_TYPE_AG ); + ri->ri_realtime = isrt;xfs_defer_add_item (dfp, &ri->ri_list); }
@@ -494,6 +500,7 @@ xfs_refcount_recover_work(struct xfs_cui_log_item *cuip =CUI_ITEM (lip);struct xfs_trans *tp;struct xfs_mount *mp = lip->li_log->l_mp; +bool isrt =xfs_cui_item_isrt (lip);int i;int error =0 ;
@@ -503,7 +510,7 @@ xfs_refcount_recover_work(* just toss the CUI. */ for (i =0 ; i < cuip->cui_format.cui_nextents; i++) { -if (!xfs_cui_validate_phys (mp, +if (!xfs_cui_validate_phys (mp, isrt, &cuip->cui_format.cui_extents[i])) { XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, &cuip->cui_format,
@@ -511,7 +518,8 @@ xfs_refcount_recover_work(return -EFSCORRUPTED ; } -xfs_cui_recover_work (mp, dfp, &cuip->cui_format.cui_extents[i]); +xfs_cui_recover_work (mp, dfp, isrt, + &cuip->cui_format.cui_extents[i]); }/*
PATCH 9/43 xfs: add realtime refcount btree block detection to log recovery
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Identify rt refcount btree blocks in the log correctly so that we can validate them during log recovery.
--- fs/xfs/xfs_buf_item_recover.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/xfs/xfs_buf_item_recover.c +4 -0
@@ -271,6 +271,9 @@ xlog_recover_validate_buf_type(case XFS_REFC_CRC_MAGIC : bp->b_ops = &xfs_refcountbt_buf_ops;break ; +case XFS_RTREFC_CRC_MAGIC : + bp->b_ops = &xfs_rtrefcountbt_buf_ops; +break ;default : warnmsg ="Bad btree block magic!" ;break ;
@@ -859,6 +862,7 @@ xlog_recover_get_buf_lsn(break ; }case XFS_RTRMAP_CRC_MAGIC : +case XFS_RTREFC_CRC_MAGIC :case XFS_BMAP_CRC_MAGIC :case XFS_BMAP_MAGIC : {struct xfs_btree_block *btb = blk;
PATCH 10/43 xfs: add realtime refcount btree inode to metadata directory
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Add a metadir path to select the realtime refcount btree inode and load it at mount time. The rtrefcountbt inode will have a unique extent format code, which means that we also have to update the inode validation and flush routines to look for it.
--- fs/xfs/libxfs/xfs_format.h | 4 +++- fs/xfs/libxfs/xfs_inode_buf.c | 5 +++++ fs/xfs/libxfs/xfs_inode_fork.c | 6 ++++++ fs/xfs/libxfs/xfs_rtgroup.c | 7 +++++++ fs/xfs/libxfs/xfs_rtgroup.h | 6 ++++++ fs/xfs/libxfs/xfs_rtrefcount_btree.c | 6 +++--- 6 files changed, 30 insertions(+), 4 deletions(-)
fs/xfs/libxfs/xfs_format.h +3 -1
@@ -858,6 +858,7 @@ enum xfs_metafile_type {XFS_METAFILE_RTBITMAP ,/* rt bitmap */ XFS_METAFILE_RTSUMMARY ,/* rt summary */ XFS_METAFILE_RTRMAP ,/* rt rmap */ +XFS_METAFILE_RTREFCOUNT ,/* rt refcount */ XFS_METAFILE_MAX } __packed;
@@ -870,7 +871,8 @@ enum xfs_metafile_type { { XFS_METAFILE_PRJQUOTA, "prjquota" }, \ { XFS_METAFILE_RTBITMAP, "rtbitmap" }, \ { XFS_METAFILE_RTSUMMARY, "rtsummary" }, \ - { XFS_METAFILE_RTRMAP, "rtrmap" } + { XFS_METAFILE_RTRMAP, "rtrmap" }, \ + { XFS_METAFILE_RTREFCOUNT, "rtrefcount" }/* * On-disk inode structure.
fs/xfs/libxfs/xfs_inode_buf.c +5 -0
@@ -456,6 +456,11 @@ xfs_dinode_verify_fork(if (!xfs_has_rmapbt (mp))return __this_address;break ; +case XFS_METAFILE_RTREFCOUNT : +/* same comment about growfs and rmap inodes applies */ +if (!xfs_has_reflink (mp)) +return __this_address; +break ;default :return __this_address; }
fs/xfs/libxfs/xfs_inode_fork.c +6 -0
@@ -272,6 +272,9 @@ xfs_iformat_data_fork(switch (ip->i_metatype) {case XFS_METAFILE_RTRMAP :return xfs_iformat_rtrmap (ip, dip); +case XFS_METAFILE_RTREFCOUNT : +ASSERT (0 );/* to be implemented later */ +return -EFSCORRUPTED ;default :break ; }
@@ -620,6 +623,9 @@ xfs_iflush_fork(case XFS_METAFILE_RTRMAP :xfs_iflush_rtrmap (ip, dip);break ; +case XFS_METAFILE_RTREFCOUNT : +ASSERT (0 );/* to be implemented later */ +break ;default :ASSERT (0 );break ;
fs/xfs/libxfs/xfs_rtgroup.c +7 -0
@@ -367,6 +367,13 @@ static const struct xfs_rtginode_ops xfs_rtginode_ops[XFS_RTGI_MAX] = { .enabled = xfs_has_rmapbt, .create = xfs_rtrmapbt_create, }, + [XFS_RTGI_REFCOUNT] = { + .name = "refcount", + .metafile_type = XFS_METAFILE_RTREFCOUNT, + .fmt_mask = 1U << XFS_DINODE_FMT_META_BTREE, +/* same comment about growfs and rmap inodes applies here */ + .enabled = xfs_has_reflink, + }, };/* Return the shortname of this rtgroup inode. */
fs/xfs/libxfs/xfs_rtgroup.h +6 -0
@@ -15,6 +15,7 @@ enum xfs_rtg_inodes {XFS_RTGI_BITMAP ,/* allocation bitmap */ XFS_RTGI_SUMMARY ,/* allocation summary */ XFS_RTGI_RMAP ,/* rmap btree inode */ +XFS_RTGI_REFCOUNT ,/* refcount btree inode */ XFS_RTGI_MAX, };
@@ -80,6 +81,11 @@ static inline struct xfs_inode *rtg_rmap(const struct xfs_rtgroup *rtg)return rtg->rtg_inodes[XFS_RTGI_RMAP ]; } +static inline struct xfs_inode *rtg_refcount (const struct xfs_rtgroup *rtg) +{ +return rtg->rtg_inodes[XFS_RTGI_REFCOUNT ]; +} +/* Passive rtgroup references */ static inline struct xfs_rtgroup * xfs_rtgroup_get(
fs/xfs/libxfs/xfs_rtrefcount_btree.c +3 -3
@@ -26,6 +26,7 @@#include "xfs_extent_busy.h" #include "xfs_rtgroup.h" #include "xfs_rtbitmap.h" +#include "xfs_metafile.h" static struct kmem_cache *xfs_rtrefcountbt_cur_cache;
@@ -281,12 +282,10 @@ xfs_rtrefcountbt_init_cursor(struct xfs_trans *tp, struct xfs_rtgroup *rtg) { - struct xfs_inode *ip = NULL; + struct xfs_inode *ip = rtg_refcount(rtg);struct xfs_mount *mp =rtg_mount (rtg);struct xfs_btree_cur *cur; -return NULL ;/* XXX */ -xfs_assert_ilocked (ip,XFS_ILOCK_SHARED |XFS_ILOCK_EXCL ); cur = xfs_btree_alloc_cursor(mp, tp, &xfs_rtrefcountbt_ops,
@@ -316,6 +315,7 @@ xfs_rtrefcountbt_commit_staged_btree(int flags =XFS_ILOG_CORE |XFS_ILOG_DBROOT ;ASSERT (cur->bc_flags &XFS_BTREE_STAGING ); +ASSERT (ifake->if_fork->if_format ==XFS_DINODE_FMT_META_BTREE );/* * Free any resources hanging off the real fork, then shallow-copy the
PATCH 11/43 xfs: add metadata reservations for realtime refcount btree
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Reserve some free blocks so that we will always have enough free blocks in the data volume to handle expansion of the realtime refcount btree.
--- fs/xfs/libxfs/xfs_rtrefcount_btree.c | 38 ++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_rtrefcount_btree.h | 4 ++++ fs/xfs/xfs_rtalloc.c | 6 +++++ 3 files changed, 48 insertions(+)
fs/xfs/libxfs/xfs_rtrefcount_btree.c +38 -0
@@ -419,3 +419,41 @@ xfs_rtrefcountbt_compute_maxlevels(/* Add one level to handle the inode root level. */ mp->m_rtrefc_maxlevels =min (d_maxlevels, r_maxlevels) +1 ; } + +/* Calculate the rtrefcount btree size for some records. */ +unsigned long long +xfs_rtrefcountbt_calc_size ( +struct xfs_mount *mp, +unsigned long long len) +{ +return xfs_btree_calc_size (mp->m_rtrefc_mnr, len); +} + +/* +* Calculate the maximum refcount btree size. +*/ +static unsigned long long +xfs_rtrefcountbt_max_size ( +struct xfs_mount *mp, +xfs_rtblock_t rtblocks) +{ +/* Bail out if we're uninitialized, which can happen in mkfs. */ +if (mp->m_rtrefc_mxr[0 ] ==0 ) +return 0 ; + +return xfs_rtrefcountbt_calc_size (mp, rtblocks); +} + +/* +* Figure out how many blocks to reserve and how many are used by this btree. +* We need enough space to hold one record for every rt extent in the rtgroup. +*/ +xfs_filblks_t +xfs_rtrefcountbt_calc_reserves ( +struct xfs_mount *mp) +{ +if (!xfs_has_rtreflink (mp)) +return 0 ; + +return xfs_rtrefcountbt_max_size (mp, mp->m_sb.sb_rgextents); +}
fs/xfs/libxfs/xfs_rtrefcount_btree.h +4 -0
@@ -67,4 +67,8 @@ unsigned int xfs_rtrefcountbt_maxlevels_ondisk(void);int __init xfs_rtrefcountbt_init_cur_cache (void );void xfs_rtrefcountbt_destroy_cur_cache (void ); +xfs_filblks_t xfs_rtrefcountbt_calc_reserves (struct xfs_mount *mp); +unsigned long long xfs_rtrefcountbt_calc_size (struct xfs_mount *mp, +unsigned long long len); +#endif /* __XFS_RTREFCOUNT_BTREE_H__ */
fs/xfs/xfs_rtalloc.c +6 -0
@@ -31,6 +31,7 @@#include "xfs_rtgroup.h" #include "xfs_error.h" #include "xfs_trace.h" +#include "xfs_rtrefcount_btree.h" /* * Return whether there are any free extents in the size range given
@@ -1547,6 +1548,11 @@ xfs_rt_resv_init( err2 =xfs_metafile_resv_init (rtg_rmap (rtg), ask);if (err2 && !error) error = err2; + + ask =xfs_rtrefcountbt_calc_reserves (mp); + err2 =xfs_metafile_resv_init (rtg_refcount (rtg), ask); +if (err2 && !error) + error = err2; }return error;
PATCH 12/43 xfs: wire up a new metafile type for the realtime refcount
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Plumb in the pieces we need to embed the root of the realtime refcount btree in an inode's data fork, complete with metafile type and on-disk interpretation functions.
--- fs/xfs/libxfs/xfs_format.h | 8 + fs/xfs/libxfs/xfs_inode_fork.c | 6 - fs/xfs/libxfs/xfs_ondisk.h | 1 fs/xfs/libxfs/xfs_rtrefcount_btree.c | 264 ++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_rtrefcount_btree.h | 112 ++++++++++++++ fs/xfs/xfs_inode_item_recover.c | 4 + 6 files changed, 392 insertions(+), 3 deletions(-)
fs/xfs/libxfs/xfs_format.h +8 -0
@@ -1805,6 +1805,14 @@ typedef __be32 xfs_refcount_ptr_t;*/ #define XFS_RTREFC_CRC_MAGIC 0x52434e54/* 'RCNT' */ +/* +* rt refcount root header, on-disk form only. +*/ +struct xfs_rtrefcount_root { +__be16 bb_level;/* 0 is a leaf */ +__be16 bb_numrecs;/* current # of data records */ +}; +/* inode-rooted btree pointer type */ typedef __be64 xfs_rtrefcount_ptr_t ;
fs/xfs/libxfs/xfs_inode_fork.c +3 -3
@@ -28,6 +28,7 @@#include "xfs_health.h" #include "xfs_symlink_remote.h" #include "xfs_rtrmap_btree.h" +#include "xfs_rtrefcount_btree.h" struct kmem_cache *xfs_ifork_cache;
@@ -273,8 +274,7 @@ xfs_iformat_data_fork(case XFS_METAFILE_RTRMAP :return xfs_iformat_rtrmap (ip, dip);case XFS_METAFILE_RTREFCOUNT : -ASSERT (0 );/* to be implemented later */ -return -EFSCORRUPTED ; +return xfs_iformat_rtrefcount (ip, dip);default :break ; }
@@ -624,7 +624,7 @@ xfs_iflush_fork(xfs_iflush_rtrmap (ip, dip);break ;case XFS_METAFILE_RTREFCOUNT : -ASSERT (0 );/* to be implemented later */ +xfs_iflush_rtrefcount (ip, dip);break ;default :ASSERT (0 );
fs/xfs/libxfs/xfs_ondisk.h +1 -0
@@ -86,6 +86,7 @@ xfs_check_ondisk_structs(void)XFS_CHECK_STRUCT_SIZE (xfs_rtrmap_ptr_t,8 ); XFS_CHECK_STRUCT_SIZE(struct xfs_rtrmap_root, 4);XFS_CHECK_STRUCT_SIZE (xfs_rtrefcount_ptr_t,8 ); + XFS_CHECK_STRUCT_SIZE(struct xfs_rtrefcount_root, 4);/* * m68k has problems with struct xfs_attr_leaf_name_remote, but we pad
fs/xfs/libxfs/xfs_rtrefcount_btree.c +264 -0
291 lines not on this page · raw message
fs/xfs/libxfs/xfs_rtrefcount_btree.h +112 -0
122 lines not on this page · raw message
fs/xfs/xfs_inode_item_recover.c +4 -0
@@ -23,6 +23,7 @@#include "xfs_icache.h" #include "xfs_bmap_btree.h" #include "xfs_rtrmap_btree.h" +#include "xfs_rtrefcount_btree.h" STATIC void xlog_recover_inode_ra_pass2(
@@ -286,6 +287,9 @@ xlog_recover_inode_dbroot(case XFS_METAFILE_RTRMAP :xfs_rtrmapbt_to_disk (mp, src, len, dfork, dsize);return 0 ; +case XFS_METAFILE_RTREFCOUNT : +xfs_rtrefcountbt_to_disk (mp, src, len, dfork, dsize); +return 0 ;default :ASSERT (0 );return -EFSCORRUPTED ;
PATCH 13/43 xfs: refactor xfs_reflink_find_shared
In reply to Darrick J. WongFrom: Christoph Hellwig <[email protected]>
Move lookup of the perag structure from the callers into the helpers, and return the offset into the extent of the shared region instead of the block number that needs post-processing. This prepares the callsites for the creation of an rt-specific variant in the next patch.
--- fs/xfs/xfs_reflink.c | 110 ++++++++++++++++++++++---------------------------- fs/xfs/xfs_reflink.h | 2 - 2 files changed, 50 insertions(+), 62 deletions(-)
fs/xfs/xfs_reflink.c +49 -61
@@ -120,38 +120,46 @@*/ /* -* Given an AG extent, find the lowest-numbered run of shared blocks -* within that range and return the range in fbno/flen. If -* find_end_of_shared is true, return the longest contiguous extent of -* shared blocks. If there are no shared extents, fbno and flen will -* be set to NULLAGBLOCK and 0, respectively. +* Given a file mapping for the data device, find the lowest-numbered run of +* shared blocks within that mapping and return it in shared_offset/shared_len. +* The offset is relative to the start of irec. +* +* If find_end_of_shared is true, return the longest contiguous extent of shared +* blocks. If there are no shared extents, shared_offset and shared_len will be +* set to 0; */ static int xfs_reflink_find_shared ( -struct xfs_perag *pag, +struct xfs_mount *mp,struct xfs_trans *tp, -xfs_agblock_t agbno, -xfs_extlen_t aglen, -xfs_agblock_t *fbno, -xfs_extlen_t *flen, +const struct xfs_bmbt_irec *irec, +xfs_extlen_t *shared_offset, +xfs_extlen_t *shared_len,bool find_end_of_shared) {struct xfs_buf *agbp; +struct xfs_perag *pag;struct xfs_btree_cur *cur;int error; +xfs_agblock_t orig_bno, found_bno; + + pag =xfs_perag_get (mp,XFS_FSB_TO_AGNO (mp, irec->br_startblock)); + orig_bno =XFS_FSB_TO_AGBNO (mp, irec->br_startblock); error =xfs_alloc_read_agf (pag, tp,0 , &agbp);if (error) -return error; - - cur =xfs_refcountbt_init_cursor (pag_mount (pag), tp, agbp, pag); - - error =xfs_refcount_find_shared (cur, agbno, aglen, fbno, flen, - find_end_of_shared); + goto out; + cur =xfs_refcountbt_init_cursor (mp, tp, agbp, pag); + error =xfs_refcount_find_shared (cur, orig_bno, irec->br_blockcount, + &found_bno, shared_len, find_end_of_shared);xfs_btree_del_cursor (cur, error); -xfs_trans_brelse (tp, agbp); + +if (!error && *shared_len) + *shared_offset = found_bno - orig_bno; +out: +xfs_perag_put (pag);return error; }
@@ -172,11 +180,7 @@ xfs_reflink_trim_around_shared( bool *shared) {struct xfs_mount *mp = ip->i_mount; -struct xfs_perag *pag; -xfs_agblock_t agbno; -xfs_extlen_t aglen; -xfs_agblock_t fbno; -xfs_extlen_t flen; +xfs_extlen_t shared_offset, shared_len;int error =0 ;/* Holes, unwritten, and delalloc extents cannot be shared */
@@ -187,41 +191,33 @@ xfs_reflink_trim_around_shared(trace_xfs_reflink_trim_around_shared (ip, irec); - pag =xfs_perag_get (mp,XFS_FSB_TO_AGNO (mp, irec->br_startblock)); - agbno =XFS_FSB_TO_AGBNO (mp, irec->br_startblock); - aglen = irec->br_blockcount; - - error =xfs_reflink_find_shared (pag,NULL , agbno, aglen, &fbno, &flen, - true); -xfs_perag_put (pag); + error =xfs_reflink_find_shared (mp,NULL , irec, &shared_offset, + &shared_len, true);if (error)return error; - *shared = false; -if (fbno ==NULLAGBLOCK ) { +if (!shared_len) {/* No shared blocks at all. */ -return 0 ; - } - -if (fbno == agbno) { + *shared = false; + }else if (!shared_offset) {/* -* The start of this extent is shared. Truncate the -* mapping at the end of the shared region so that a -* subsequent iteration starts at the start of the -* unshared region. +* The start of this mapping points to shared space. Truncate +* the mapping at the end of the shared region so that a +* subsequent iteration starts at the start of the unshared +* region. */ - irec->br_blockcount = flen; + irec->br_blockcount = shared_len; *shared = true; -return 0 ; + }else { +/* +* There's a shared region that doesn't start at the beginning +* of the mapping. Truncate the mapping at the start of the +* shared extent so that a subsequent iteration starts at the +* start of the shared region. +*/ + irec->br_blockcount = shared_offset; + *shared = false; } - -/* -* There's a shared extent midway through this extent. -* Truncate the mapping at the start of the shared -* extent so that a subsequent iteration starts at the -* start of the shared region. -*/ - irec->br_blockcount = fbno - agbno;return 0 ; }
@@ -1552,27 +1548,19 @@ xfs_reflink_inode_has_shared_extents( *has_shared = false; found =xfs_iext_lookup_extent (ip, ifp,0 , &icur, &got);while (found) { -struct xfs_perag *pag; -xfs_agblock_t agbno; -xfs_extlen_t aglen; -xfs_agblock_t rbno; -xfs_extlen_t rlen; +xfs_extlen_t shared_offset, shared_len;if (isnullstartblock (got.br_startblock) || got.br_state !=XFS_EXT_NORM ) goto next; - pag =xfs_perag_get (mp,XFS_FSB_TO_AGNO (mp, got.br_startblock)); - agbno =XFS_FSB_TO_AGBNO (mp, got.br_startblock); - aglen = got.br_blockcount; - error =xfs_reflink_find_shared (pag, tp, agbno, aglen, - &rbno, &rlen, false); -xfs_perag_put (pag); + error =xfs_reflink_find_shared (mp, tp, &got, &shared_offset, + &shared_len, false);if (error)return error;/* Is there still a shared block here? */ -if (rbno !=NULLAGBLOCK ) { +if (shared_len) { *has_shared = true;return 0 ; }
fs/xfs/xfs_reflink.h +1 -1
@@ -25,7 +25,7 @@ xfs_can_free_cowblocks(struct xfs_inode *ip)return true; } -extern int xfs_reflink_trim_around_shared (struct xfs_inode *ip, +int xfs_reflink_trim_around_shared (struct xfs_inode *ip,struct xfs_bmbt_irec *irec,bool *shared);int xfs_bmap_trim_cow (struct xfs_inode *ip,struct xfs_bmbt_irec *imap,bool *shared);
PATCH 14/43 xfs: wire up realtime refcount btree cursors
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Wire up realtime refcount btree cursors wherever they're needed throughout the code base.
--- fs/xfs/libxfs/xfs_btree.h | 2 - fs/xfs/libxfs/xfs_refcount.c | 100 +++++++++++++++++++++++++++++++++++++++++- fs/xfs/libxfs/xfs_rtgroup.c | 9 ++++ fs/xfs/libxfs/xfs_rtgroup.h | 5 ++ fs/xfs/xfs_fsmap.c | 25 +++++------ fs/xfs/xfs_reflink.c | 66 ++++++++++++++++++++++++++-- 6 files changed, 187 insertions(+), 20 deletions(-)
fs/xfs/libxfs/xfs_btree.h +1 -1
@@ -297,7 +297,7 @@ struct xfs_btree_curstruct {unsigned int nr_ops;/* # record updates */ unsigned int shape_changes;/* # of extent splits */ - } bc_refc;/* refcountbt */ + } bc_refc;/* refcountbt/rtrefcountbt */ };/* Must be at the end of the struct! */
fs/xfs/libxfs/xfs_refcount.c +98 -2
118 lines not on this page · raw message
fs/xfs/libxfs/xfs_rtgroup.c +9 -0
@@ -206,6 +206,9 @@ xfs_rtgroup_lock(if ((rtglock_flags &XFS_RTGLOCK_RMAP ) &&rtg_rmap (rtg))xfs_ilock (rtg_rmap (rtg),XFS_ILOCK_EXCL ); + +if ((rtglock_flags &XFS_RTGLOCK_REFCOUNT ) &&rtg_refcount (rtg)) +xfs_ilock (rtg_refcount (rtg),XFS_ILOCK_EXCL ); }/* Unlock metadata inodes associated with this rt group. */
@@ -218,6 +221,9 @@ xfs_rtgroup_unlock(ASSERT (!(rtglock_flags &XFS_RTGLOCK_BITMAP_SHARED ) || !(rtglock_flags &XFS_RTGLOCK_BITMAP )); +if ((rtglock_flags &XFS_RTGLOCK_REFCOUNT ) &&rtg_refcount (rtg)) +xfs_iunlock (rtg_refcount (rtg),XFS_ILOCK_EXCL ); +if ((rtglock_flags &XFS_RTGLOCK_RMAP ) &&rtg_rmap (rtg))xfs_iunlock (rtg_rmap (rtg),XFS_ILOCK_EXCL );
@@ -249,6 +255,9 @@ xfs_rtgroup_trans_join(if ((rtglock_flags &XFS_RTGLOCK_RMAP ) &&rtg_rmap (rtg))xfs_trans_ijoin (tp,rtg_rmap (rtg),XFS_ILOCK_EXCL ); + +if ((rtglock_flags &XFS_RTGLOCK_REFCOUNT ) &&rtg_refcount (rtg)) +xfs_trans_ijoin (tp,rtg_refcount (rtg),XFS_ILOCK_EXCL ); }/* Retrieve rt group geometry. */
fs/xfs/libxfs/xfs_rtgroup.h +4 -1
@@ -273,10 +273,13 @@ int xfs_update_last_rtgroup_size(struct xfs_mount *mp,#define XFS_RTGLOCK_BITMAP_SHARED (1U << 1)/* Lock the rt rmap inode in exclusive mode */ #define XFS_RTGLOCK_RMAP (1U << 2) +/* Lock the rt refcount inode in exclusive mode */ +#define XFS_RTGLOCK_REFCOUNT (1U << 3)#define XFS_RTGLOCK_ALL_FLAGS (XFS_RTGLOCK_BITMAP | \ XFS_RTGLOCK_BITMAP_SHARED | \ - XFS_RTGLOCK_RMAP) + XFS_RTGLOCK_RMAP | \ + XFS_RTGLOCK_REFCOUNT)void xfs_rtgroup_lock (struct xfs_rtgroup *rtg,unsigned int rtglock_flags);void xfs_rtgroup_unlock (struct xfs_rtgroup *rtg,unsigned int rtglock_flags);
fs/xfs/xfs_fsmap.c +13 -12
@@ -27,6 +27,7 @@#include "xfs_ag.h" #include "xfs_rtgroup.h" #include "xfs_rtrmap_btree.h" +#include "xfs_rtrefcount_btree.h" /* Convert an xfs_fsmap to an fsmap. */ static void
@@ -212,21 +213,20 @@ xfs_getfsmap_is_shared(struct xfs_mount *mp = tp->t_mountp;struct xfs_btree_cur *cur;xfs_agblock_t fbno; -xfs_extlen_t flen; +xfs_extlen_t flen =0 ;int error; *stat = false; -if (!xfs_has_reflink (mp)) -return 0 ; -/* rt files will have no perag structure */ -if (!info->group) +if (!xfs_has_reflink (mp) || !info->group)return 0 ; +if (info->group->xg_type ==XG_TYPE_RTG ) + cur =xfs_rtrefcountbt_init_cursor (tp,to_rtg (info->group)); +else + cur =xfs_refcountbt_init_cursor (mp, tp, info->agf_bp, +to_perag (info->group)); +/* Are there any shared blocks here? */ - flen =0 ; - cur =xfs_refcountbt_init_cursor (mp, tp, info->agf_bp, -to_perag (info->group)); - error =xfs_refcount_find_shared (cur, frec->rec_key,XFS_BB_TO_FSBT (mp, frec->len_daddr), &fbno, &flen, false);
@@ -863,7 +863,7 @@ xfs_getfsmap_rtdev_rmapbt_query(struct xfs_rtgroup *rtg =to_rtg (info->group);/* Query the rtrmapbt */ -xfs_rtgroup_lock (rtg,XFS_RTGLOCK_RMAP ); +xfs_rtgroup_lock (rtg,XFS_RTGLOCK_RMAP |XFS_RTGLOCK_REFCOUNT ); *curpp =xfs_rtrmapbt_init_cursor (tp, rtg);return xfs_rmap_query_range (*curpp, &info->low, &info->high, xfs_getfsmap_rtdev_rmapbt_helper, info);
@@ -950,7 +950,8 @@ xfs_getfsmap_rtdev_rmapbt(if (bt_cur) {xfs_rtgroup_unlock (to_rtg (bt_cur->bc_group), -XFS_RTGLOCK_RMAP ); +XFS_RTGLOCK_RMAP | +XFS_RTGLOCK_REFCOUNT );xfs_btree_del_cursor (bt_cur,XFS_BTREE_NOERROR ); bt_cur =NULL ; }
@@ -988,7 +989,7 @@ xfs_getfsmap_rtdev_rmapbt(if (bt_cur) {xfs_rtgroup_unlock (to_rtg (bt_cur->bc_group), -XFS_RTGLOCK_RMAP ); +XFS_RTGLOCK_RMAP |XFS_RTGLOCK_REFCOUNT );xfs_btree_del_cursor (bt_cur, error <0 ?XFS_BTREE_ERROR :XFS_BTREE_NOERROR ); }
fs/xfs/xfs_reflink.c +62 -4
90 lines not on this page · raw message
PATCH 15/43 xfs: create routine to allocate and initialize a realtime refcount btree inode
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Create a library routine to allocate and initialize an empty realtime refcountbt inode. We'll use this for growfs, mkfs, and repair.
--- fs/xfs/libxfs/xfs_rtgroup.c | 2 ++ fs/xfs/libxfs/xfs_rtrefcount_btree.c | 28 ++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_rtrefcount_btree.h | 3 +++ 3 files changed, 33 insertions(+)
fs/xfs/libxfs/xfs_rtgroup.c +2 -0
@@ -34,6 +34,7 @@#include "xfs_metafile.h" #include "xfs_metadir.h" #include "xfs_rtrmap_btree.h" +#include "xfs_rtrefcount_btree.h" /* Find the first usable fsblock in this rtgroup. */ static inline uint32_t
@@ -382,6 +383,7 @@ static const struct xfs_rtginode_ops xfs_rtginode_ops[XFS_RTGI_MAX] = { .fmt_mask = 1U << XFS_DINODE_FMT_META_BTREE, /* same comment about growfs and rmap inodes applies here */ .enabled = xfs_has_reflink, + .create = xfs_rtrefcountbt_create, }, };
fs/xfs/libxfs/xfs_rtrefcount_btree.c +28 -0
@@ -721,3 +721,31 @@ xfs_iflush_rtrefcount( ifp->if_broot_bytes, dfp, XFS_DFORK_SIZE(dip, ip->i_mount, XFS_DATA_FORK)); } + +/* +* Create a realtime refcount btree inode. +*/ +int +xfs_rtrefcountbt_create ( +struct xfs_rtgroup *rtg, +struct xfs_inode *ip, +struct xfs_trans *tp, +bool init) +{ +struct xfs_ifork *ifp =xfs_ifork_ptr (ip,XFS_DATA_FORK ); +struct xfs_mount *mp = ip->i_mount; +struct xfs_btree_block *broot; + + ifp->if_format =XFS_DINODE_FMT_META_BTREE ; +ASSERT (ifp->if_broot_bytes ==0 ); +ASSERT (ifp->if_bytes ==0 ); + +/* Initialize the empty incore btree root. */ + broot =xfs_broot_realloc (ifp, +xfs_rtrefcount_broot_space_calc (mp,0 ,0 )); +if (broot) +xfs_btree_init_block (mp, broot, &xfs_rtrefcountbt_ops,0 ,0 , + ip->i_ino); +xfs_trans_log_inode (tp, ip,XFS_ILOG_CORE |XFS_ILOG_DBROOT ); +return 0 ; +}
fs/xfs/libxfs/xfs_rtrefcount_btree.h +3 -0
@@ -183,4 +183,7 @@ void xfs_rtrefcountbt_to_disk(struct xfs_mount *mp, struct xfs_rtrefcount_root *dblock, int dblocklen);void xfs_iflush_rtrefcount (struct xfs_inode *ip,struct xfs_dinode *dip); +int xfs_rtrefcountbt_create (struct xfs_rtgroup *rtg,struct xfs_inode *ip, +struct xfs_trans *tp,bool init); +#endif /* __XFS_RTREFCOUNT_BTREE_H__ */
PATCH 16/43 xfs: update rmap to allow cow staging extents in the rt rmap
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Don't error out on CoW staging extent records when realtime reflink is enabled.
--- fs/xfs/libxfs/xfs_rmap.c | 7 +++++++ 1 file changed, 7 insertions(+)
fs/xfs/libxfs/xfs_rmap.c +7 -0
@@ -285,6 +285,13 @@ xfs_rtrmap_check_meta_irec(if (irec->rm_blockcount != mp->m_sb.sb_rextsize)return __this_address;return NULL ; +case XFS_RMAP_OWN_COW : +if (!xfs_has_rtreflink (mp)) +return __this_address; +if (!xfs_verify_rgbext (rtg, irec->rm_startblock, + irec->rm_blockcount)) +return __this_address; +return NULL ;default :return __this_address; }
PATCH 17/43 xfs: compute rtrmap btree max levels when reflink enabled
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Compute the maximum possible height of the realtime rmap btree when reflink is enabled.
--- fs/xfs/libxfs/xfs_rtrmap_btree.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-)
fs/xfs/libxfs/xfs_rtrmap_btree.c +26 -2
@@ -718,6 +718,7 @@ xfs_rtrmapbt_maxrecs(unsigned int xfs_rtrmapbt_maxlevels_ondisk (void ) { +unsigned long long max_dblocks;unsigned int minrecs[2 ];unsigned int blocklen;
@@ -726,8 +727,20 @@ xfs_rtrmapbt_maxlevels_ondisk(void) minrecs[0 ] =xfs_rtrmapbt_block_maxrecs (blocklen, true) /2 ; minrecs[1 ] =xfs_rtrmapbt_block_maxrecs (blocklen, false) /2 ; -/* We need at most one record for every block in an rt group. */ -return xfs_btree_compute_maxlevels (minrecs,XFS_MAX_RGBLOCKS ); +/* +* Compute the asymptotic maxlevels for an rtrmapbt on any rtreflink fs. +* +* On a reflink filesystem, each block in an rtgroup can have up to +* 2^32 (per the refcount record format) owners, which means that +* theoretically we could face up to 2^64 rmap records. However, we're +* likely to run out of blocks in the data device long before that +* happens, which means that we must compute the max height based on +* what the btree will look like if it consumes almost all the blocks +* in the data device due to maximal sharing factor. +*/ + max_dblocks =-1U ;/* max ag count */ + max_dblocks *=XFS_MAX_CRC_AG_BLOCKS ; +return xfs_btree_space_to_height (minrecs, max_dblocks); }int __init
@@ -766,9 +779,20 @@ xfs_rtrmapbt_compute_maxlevels(* maximum height is constrained by the size of the data device and * the height required to store one rmap record for each block in an * rt group. +* +* On a reflink filesystem, each rt block can have up to 2^32 (per the +* refcount record format) owners, which means that theoretically we +* could face up to 2^64 rmap records. This makes the computation of +* maxlevels based on record count meaningless, so we only consider the +* size of the data device. */ d_maxlevels =xfs_btree_space_to_height (mp->m_rtrmap_mnr, mp->m_sb.sb_dblocks); +if (xfs_has_rtreflink (mp)) { + mp->m_rtrmap_maxlevels = d_maxlevels +1 ; +return ; + } + r_maxlevels =xfs_btree_compute_maxlevels (mp->m_rtrmap_mnr, mp->m_groups[XG_TYPE_RTG ].blocks);
PATCH 18/43 xfs: refactor reflink quota updates
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Hoist all quota updates for reflink into a helper function, since things are about to become more complicated.
--- fs/xfs/xfs_reflink.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-)
fs/xfs/xfs_reflink.c +32 -5
@@ -739,6 +739,35 @@ xfs_reflink_cancel_cow_range(return error; } +#ifdef CONFIG_XFS_QUOTA +/* +* Update quota accounting for a remapping operation. When we're remapping +* something from the CoW fork to the data fork, we must update the quota +* accounting for delayed allocations. For remapping from the data fork to the +* data fork, use regular block accounting. +*/ +static inline void +xfs_reflink_update_quota ( +struct xfs_trans *tp, +struct xfs_inode *ip, +bool is_cow, +int64_t blocks) +{ +unsigned int qflag; + +if (XFS_IS_REALTIME_INODE (ip)) { + qflag = is_cow ?XFS_TRANS_DQ_DELRTBCOUNT : +XFS_TRANS_DQ_RTBCOUNT ; + }else { + qflag = is_cow ?XFS_TRANS_DQ_DELBCOUNT : +XFS_TRANS_DQ_BCOUNT ; + } +xfs_trans_mod_dquot_byino (tp, ip, qflag, blocks); +} +#else +# define xfs_reflink_update_quota (tp, ip, is_cow, blocks) ((void)0) +#endif +/* * Remap part of the CoW fork into the data fork. *
@@ -833,8 +862,7 @@ xfs_reflink_end_cow_extent(*/ xfs_bmap_unmap_extent (tp, ip,XFS_DATA_FORK , &data);xfs_refcount_decrease_extent (tp, isrt, &data); -xfs_trans_mod_dquot_byino (tp, ip,XFS_TRANS_DQ_BCOUNT , - -data.br_blockcount); +xfs_reflink_update_quota (tp, ip, false, -data.br_blockcount); }else if (data.br_startblock ==DELAYSTARTBLOCK ) {int done;
@@ -859,8 +887,7 @@ xfs_reflink_end_cow_extent(xfs_bmap_map_extent (tp, ip,XFS_DATA_FORK , &del);/* Charge this new data fork mapping to the on-disk quota. */ -xfs_trans_mod_dquot_byino (tp, ip,XFS_TRANS_DQ_DELBCOUNT , - (long )del.br_blockcount); +xfs_reflink_update_quota (tp, ip, true, del.br_blockcount);/* Remove the mapping from the CoW fork. */ xfs_bmap_del_extent_cow (ip, &icur, &got, &del);
@@ -1347,7 +1374,7 @@ xfs_reflink_remap_extent( qdelta += dmap->br_blockcount; } -xfs_trans_mod_dquot_byino (tp, ip,XFS_TRANS_DQ_BCOUNT , qdelta); +xfs_reflink_update_quota (tp, ip, false, qdelta);/* Update dest isize if needed. */ newlen =XFS_FSB_TO_B (mp, dmap->br_startoff + dmap->br_blockcount);
PATCH 19/43 xfs: enable CoW for realtime data
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Update our write paths to support copy on write on the rt volume. This works in more or less the same way as it does on the data device, with the major exception that we never do delalloc on the rt volume.
Because we consider unwritten CoW fork staging extents to be incore quota reservation, we update xfs_quota_reserve_blkres to support this case. Though xfs doesn't allow rt and quota together, the change is trivial and we shouldn't leave a logic bomb here.
--- fs/xfs/xfs_reflink.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-)
fs/xfs/xfs_reflink.c +28 -8
@@ -439,20 +439,26 @@ xfs_reflink_fill_cow_hole(struct xfs_mount *mp = ip->i_mount;struct xfs_trans *tp;xfs_filblks_t resaligned; -xfs_extlen_t resblks; +unsigned int dblocks =0 , rblocks =0 ;int nimaps;int error;bool found; resaligned =xfs_aligned_fsb_count (imap->br_startoff, imap->br_blockcount,xfs_get_cowextsz_hint (ip)); - resblks =XFS_DIOSTRAT_SPACE_RES (mp, resaligned); +if (XFS_IS_REALTIME_INODE (ip)) { + dblocks =XFS_DIOSTRAT_SPACE_RES (mp,0 ); + rblocks = resaligned; + }else { + dblocks =XFS_DIOSTRAT_SPACE_RES (mp, resaligned); + rblocks =0 ; + }xfs_iunlock (ip, *lockmode); *lockmode =0 ; - error =xfs_trans_alloc_inode (ip, &M_RES (mp)->tr_write, resblks,0 , - false, &tp); + error =xfs_trans_alloc_inode (ip, &M_RES (mp)->tr_write, dblocks, + rblocks, false, &tp);if (error)return error;
@@ -1212,7 +1218,7 @@ xfs_reflink_remap_extent(struct xfs_trans *tp;xfs_off_t newlen;int64_t qdelta =0 ; -unsigned int resblks; +unsigned int dblocks, rblocks, resblks;bool quota_reserved = true;bool smap_real;bool dmap_written =xfs_bmap_is_written_extent (dmap);
@@ -1243,8 +1249,15 @@ xfs_reflink_remap_extent(* we're remapping. */ resblks =XFS_EXTENTADD_SPACE_RES (mp,XFS_DATA_FORK ); +if (XFS_IS_REALTIME_INODE (ip)) { + dblocks = resblks; + rblocks = dmap->br_blockcount; + }else { + dblocks = resblks + dmap->br_blockcount; + rblocks =0 ; + } error =xfs_trans_alloc_inode (ip, &M_RES (mp)->tr_write, - resblks + dmap->br_blockcount,0 , false, &tp); + dblocks, rblocks, false, &tp);if (error == -EDQUOT || error == -ENOSPC ) { quota_reserved = false; error = xfs_trans_alloc_inode(ip, &M_RES(mp)->tr_write,
@@ -1324,8 +1337,15 @@ xfs_reflink_remap_extent(* done. */ if (!quota_reserved && !smap_real && dmap_written) { - error =xfs_trans_reserve_quota_nblks (tp, ip, - dmap->br_blockcount,0 , false); +if (XFS_IS_REALTIME_INODE (ip)) { + dblocks =0 ; + rblocks = dmap->br_blockcount; + }else { + dblocks = dmap->br_blockcount; + rblocks =0 ; + } + error =xfs_trans_reserve_quota_nblks (tp, ip, dblocks, rblocks, + false);if (error) goto out_cancel; }
PATCH 20/43 xfs: enable sharing of realtime file blocks
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Update the remapping routines to be able to handle realtime files.
--- fs/xfs/xfs_reflink.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-)
fs/xfs/xfs_reflink.c +20 -5
@@ -33,6 +33,7 @@#include "xfs_rtrefcount_btree.h" #include "xfs_rtalloc.h" #include "xfs_rtgroup.h" +#include "xfs_metafile.h" /* * Copy on Write of Shared Blocks
@@ -1187,14 +1188,28 @@ xfs_reflink_update_dest(static int xfs_reflink_ag_has_free_space (struct xfs_mount *mp, -xfs_agnumber_t agno) +struct xfs_inode *ip, +xfs_fsblock_t fsb) {struct xfs_perag *pag; +xfs_agnumber_t agno;int error =0 ;if (!xfs_has_rmapbt (mp))return 0 ; +if (XFS_IS_REALTIME_INODE (ip)) { +struct xfs_rtgroup *rtg; +xfs_rgnumber_t rgno; + rgno =xfs_rtb_to_rgno (mp, fsb); + rtg =xfs_rtgroup_get (mp, rgno); +if (xfs_metafile_resv_critical (rtg_rmap (rtg))) + error = -ENOSPC ; +xfs_rtgroup_put (rtg); +return error; + } + + agno =XFS_FSB_TO_AGNO (mp, fsb); pag =xfs_perag_get (mp, agno);if (xfs_ag_resv_critical (pag,XFS_AG_RESV_RMAPBT ) ||xfs_ag_resv_critical (pag,XFS_AG_RESV_METADATA ))
@@ -1308,8 +1323,8 @@ xfs_reflink_remap_extent(/* No reflinking if the AG of the dest mapping is low on space. */ if (dmap_written) { - error =xfs_reflink_ag_has_free_space (mp, -XFS_FSB_TO_AGNO (mp, dmap->br_startblock)); + error =xfs_reflink_ag_has_free_space (mp, ip, + dmap->br_startblock);if (error) goto out_cancel; }
@@ -1568,8 +1583,8 @@ xfs_reflink_remap_prep(/* Check file eligibility and prepare for block sharing. */ ret = -EINVAL ; -/* Don't reflink realtime inodes */ -if (XFS_IS_REALTIME_INODE (src) ||XFS_IS_REALTIME_INODE (dest)) +/* Can't reflink between data and rt volumes */ +if (XFS_IS_REALTIME_INODE (src) !=XFS_IS_REALTIME_INODE (dest)) goto out_unlock;/* Don't share DAX file data with non-DAX file. */
PATCH 21/43 xfs: allow inodes to have the realtime and reflink flags
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Now that we can share blocks between realtime files, allow this combination.
--- fs/xfs/libxfs/xfs_inode_buf.c | 3 ++- fs/xfs/scrub/inode.c | 5 +++-- fs/xfs/scrub/inode_repair.c | 6 ------ fs/xfs/xfs_ioctl.c | 4 ---- 4 files changed, 5 insertions(+), 13 deletions(-)
fs/xfs/libxfs/xfs_inode_buf.c +2 -1
@@ -748,7 +748,8 @@ xfs_dinode_verify(return __this_address;/* don't let reflink and realtime mix */ -if ((flags2 &XFS_DIFLAG2_REFLINK ) && (flags &XFS_DIFLAG_REALTIME )) +if ((flags2 &XFS_DIFLAG2_REFLINK ) && (flags &XFS_DIFLAG_REALTIME ) && + !xfs_has_rtreflink (mp))return __this_address;/* COW extent size hint validation */
fs/xfs/scrub/inode.c +3 -2
@@ -360,8 +360,9 @@ xchk_inode_flags2(if ((flags2 &XFS_DIFLAG2_REFLINK ) && !S_ISREG (mode)) goto bad; -/* realtime and reflink make no sense, currently */ -if ((flags &XFS_DIFLAG_REALTIME ) && (flags2 &XFS_DIFLAG2_REFLINK )) +/* realtime and reflink don't always go together */ +if ((flags &XFS_DIFLAG_REALTIME ) && (flags2 &XFS_DIFLAG2_REFLINK ) && + !xfs_has_rtreflink (mp)) goto bad;/* no bigtime iflag without the bigtime feature */
fs/xfs/scrub/inode_repair.c +0 -6
@@ -564,8 +564,6 @@ xrep_dinode_flags( flags2 |=XFS_DIFLAG2_REFLINK ; else flags2 &= ~(XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE); -if (flags &XFS_DIFLAG_REALTIME ) - flags2 &= ~XFS_DIFLAG2_REFLINK ;if (!xfs_has_bigtime (mp)) flags2 &= ~XFS_DIFLAG2_BIGTIME ;if (!xfs_has_large_extent_counts (mp))
@@ -1790,10 +1788,6 @@ xrep_inode_flags(/* DAX only applies to files and dirs. */ if (!(S_ISREG (mode) ||S_ISDIR (mode))) sc->ip->i_diflags2 &= ~XFS_DIFLAG2_DAX ; - -/* No reflink files on the realtime device. */ -if (sc->ip->i_diflags &XFS_DIFLAG_REALTIME ) - sc->ip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK ; }/*
fs/xfs/xfs_ioctl.c +0 -4
@@ -541,10 +541,6 @@ xfs_ioctl_setattr_xflags(if (mp->m_sb.sb_rblocks ==0 || mp->m_sb.sb_rextsize ==0 ||xfs_extlen_to_rtxmod (mp, ip->i_extsize))return -EINVAL ; - -/* Clear reflink if we are actually able to set the rt flag. */ -if (xfs_is_reflink_inode (ip)) - ip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK ; }/* diflags2 only valid for v3 inodes. */
PATCH 22/43 xfs: recover CoW leftovers in the realtime volume
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Scan the realtime refcount tree at mount time to get rid of leftover CoW staging extents.
--- fs/xfs/libxfs/xfs_refcount.c | 47 +++++++++++++++++++++++++++++------------- fs/xfs/libxfs/xfs_refcount.h | 3 +-- fs/xfs/xfs_reflink.c | 15 +++++++++++-- 3 files changed, 46 insertions(+), 19 deletions(-)
fs/xfs/libxfs/xfs_refcount.c +33 -14
@@ -2054,12 +2054,13 @@ xfs_refcount_recover_extent(/* Find and remove leftover CoW reservations. */ int xfs_refcount_recover_cow_leftovers ( -struct xfs_mount *mp, -struct xfs_perag *pag) +struct xfs_group *xg) { +struct xfs_mount *mp = xg->xg_mount; +bool isrt = xg->xg_type ==XG_TYPE_RTG ;struct xfs_trans *tp;struct xfs_btree_cur *cur; -struct xfs_buf *agbp; +struct xfs_buf *agbp =NULL ;struct xfs_refcount_recovery *rr, *n;struct list_head debris;union xfs_btree_irec low = {
@@ -2072,10 +2073,19 @@ xfs_refcount_recover_cow_leftovers(xfs_fsblock_t fsb;int error; -/* reflink filesystems mustn't have AGs larger than 2^31-1 blocks */ +/* reflink filesystems must not have groups larger than 2^31-1 blocks */ +BUILD_BUG_ON (XFS_MAX_RGBLOCKS >=XFS_REFC_COWFLAG );BUILD_BUG_ON (XFS_MAX_CRC_AG_BLOCKS >=XFS_REFC_COWFLAG ); -if (mp->m_sb.sb_agblocks >XFS_MAX_CRC_AG_BLOCKS ) -return -EOPNOTSUPP ; + +if (isrt) { +if (!xfs_has_rtgroups (mp)) +return 0 ; +if (xfs_group_max_blocks (xg) >=XFS_MAX_RGBLOCKS ) +return -EOPNOTSUPP ; + }else { +if (xfs_group_max_blocks (xg) >XFS_MAX_CRC_AG_BLOCKS ) +return -EOPNOTSUPP ; + }INIT_LIST_HEAD (&debris);
@@ -2093,16 +2103,24 @@ xfs_refcount_recover_cow_leftovers(if (error)return error; - error =xfs_alloc_read_agf (pag, tp,0 , &agbp); -if (error) - goto out_trans; - cur =xfs_refcountbt_init_cursor (mp, tp, agbp, pag); +if (isrt) { +xfs_rtgroup_lock (to_rtg (xg),XFS_RTGLOCK_REFCOUNT ); + cur =xfs_rtrefcountbt_init_cursor (tp,to_rtg (xg)); + }else { + error =xfs_alloc_read_agf (to_perag (xg), tp,0 , &agbp); +if (error) + goto out_trans; + cur =xfs_refcountbt_init_cursor (mp, tp, agbp,to_perag (xg)); + }/* Find all the leftover CoW staging extents. */ error =xfs_btree_query_range (cur, &low, &high, xfs_refcount_recover_extent, &debris);xfs_btree_del_cursor (cur, error); -xfs_trans_brelse (tp, agbp); +if (agbp) +xfs_trans_brelse (tp, agbp); +else +xfs_rtgroup_unlock (to_rtg (xg),XFS_RTGLOCK_REFCOUNT );xfs_trans_cancel (tp);if (error) goto out_free;
@@ -2115,14 +2133,15 @@ xfs_refcount_recover_cow_leftovers( goto out_free;/* Free the orphan record */ - fsb =xfs_agbno_to_fsb (pag, rr->rr_rrec.rc_startblock); -xfs_refcount_free_cow_extent (tp, false, fsb, + fsb =xfs_gbno_to_fsb (xg, rr->rr_rrec.rc_startblock); +xfs_refcount_free_cow_extent (tp, isrt, fsb, rr->rr_rrec.rc_blockcount);/* Free the block. */ error =xfs_free_extent_later (tp, fsb, rr->rr_rrec.rc_blockcount,NULL , -XFS_AG_RESV_NONE ,0 ); +XFS_AG_RESV_NONE , + isrt ?XFS_FREE_EXTENT_REALTIME :0 );if (error) goto out_trans;
fs/xfs/libxfs/xfs_refcount.h +1 -2
@@ -94,8 +94,7 @@ void xfs_refcount_alloc_cow_extent(struct xfs_trans *tp, bool isrt, xfs_fsblock_t fsb, xfs_extlen_t len);void xfs_refcount_free_cow_extent (struct xfs_trans *tp,bool isrt,xfs_fsblock_t fsb,xfs_extlen_t len); -extern int xfs_refcount_recover_cow_leftovers (struct xfs_mount *mp, -struct xfs_perag *pag); +int xfs_refcount_recover_cow_leftovers (struct xfs_group *xg);/* * While we're adjusting the refcounts records of an extent, we have
fs/xfs/xfs_reflink.c +12 -3
@@ -983,20 +983,29 @@ xfs_reflink_recover_cow( struct xfs_mount *mp) {struct xfs_perag *pag =NULL ; +struct xfs_rtgroup *rtg =NULL ;int error =0 ;if (!xfs_has_reflink (mp))return 0 ;while ((pag =xfs_perag_next (mp, pag))) { - error =xfs_refcount_recover_cow_leftovers (mp, pag); + error =xfs_refcount_recover_cow_leftovers (pag_group (pag));if (error) {xfs_perag_rele (pag); -break ; +return error; } } -return error; +while ((rtg =xfs_rtgroup_next (mp, rtg))) { + error =xfs_refcount_recover_cow_leftovers (rtg_group (rtg)); +if (error) { +xfs_rtgroup_rele (rtg); +return error; + } + } + +return 0 ; }/*
PATCH 23/43 xfs: fix xfs_get_extsz_hint behavior with realtime alwayscow files
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Currently, we (ab)use xfs_get_extsz_hint so that it always returns a nonzero value for realtime files. This apparently was done to disable delayed allocation for realtime files.
However, once we enable realtime reflink, we can also turn on the alwayscow flag to force CoW writes to realtime files. In this case, the logic will incorrectly send the write through the delalloc write path.
Fix this by adjusting the logic slightly.
--- fs/xfs/libxfs/xfs_bmap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
fs/xfs/libxfs/xfs_bmap.c +2 -3
@@ -6500,9 +6500,8 @@ xfs_get_extsz_hint(* No point in aligning allocations if we need to COW to actually * write to them. */ -if (xfs_is_always_cow_inode (ip)) -return 0 ; -if ((ip->i_diflags &XFS_DIFLAG_EXTSIZE ) && ip->i_extsize) +if (!xfs_is_always_cow_inode (ip) && + (ip->i_diflags &XFS_DIFLAG_EXTSIZE ) && ip->i_extsize)return ip->i_extsize;if (XFS_IS_REALTIME_INODE (ip) && ip->i_mount->m_sb.sb_rextsize >1 )
PATCH 24/43 xfs: apply rt extent alignment constraints to CoW extsize hint
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
The copy-on-write extent size hint is subject to the same alignment constraints as the regular extent size hint. Since we're in the process of adding reflink (and therefore CoW) to the realtime device, we must apply the same scattered rextsize alignment validation strategies to both hints to deal with the possibility of rextsize changing.
Therefore, fix the inode validator to perform rextsize alignment checks on regular realtime files, and to remove misaligned directory hints.
--- fs/xfs/libxfs/xfs_inode_buf.c | 25 ++++++++++++++++++++----- fs/xfs/xfs_inode_item.c | 14 ++++++++++++++ fs/xfs/xfs_ioctl.c | 17 +++++++++++++++-- 3 files changed, 49 insertions(+), 7 deletions(-)
fs/xfs/libxfs/xfs_inode_buf.c +20 -5
@@ -910,11 +910,29 @@ xfs_inode_validate_cowextsize(bool rt_flag;bool hint_flag;uint32_t cowextsize_bytes; +uint32_t blocksize_bytes; rt_flag = (flags &XFS_DIFLAG_REALTIME ); hint_flag = (flags2 &XFS_DIFLAG2_COWEXTSIZE ); cowextsize_bytes =XFS_FSB_TO_B (mp, cowextsize); +/* +* Similar to extent size hints, a directory can be configured to +* propagate realtime status and a CoW extent size hint to newly +* created files even if there is no realtime device, and the hints on +* disk can become misaligned if the sysadmin changes the rt extent +* size while adding the realtime device. +* +* Therefore, we can only enforce the rextsize alignment check against +* regular realtime files, and rely on callers to decide when alignment +* checks are appropriate, and fix things up as needed. +*/ + +if (rt_flag) + blocksize_bytes =XFS_FSB_TO_B (mp, mp->m_sb.sb_rextsize); +else + blocksize_bytes = mp->m_sb.sb_blocksize; +if (hint_flag && !xfs_has_reflink (mp))return __this_address;
@@ -928,16 +946,13 @@ xfs_inode_validate_cowextsize(if (mode && !hint_flag && cowextsize !=0 )return __this_address; -if (hint_flag && rt_flag) -return __this_address; - -if (cowextsize_bytes % mp->m_sb.sb_blocksize) +if (cowextsize_bytes % blocksize_bytes)return __this_address;if (cowextsize >XFS_MAX_BMBT_EXTLEN )return __this_address; -if (cowextsize > mp->m_sb.sb_agblocks /2 ) +if (!rt_flag && cowextsize > mp->m_sb.sb_agblocks /2 )return __this_address;return NULL ;
fs/xfs/xfs_inode_item.c +14 -0
@@ -157,6 +157,20 @@ xfs_inode_item_precommit(if (flags &XFS_ILOG_IVERSION ) flags = ((flags & ~XFS_ILOG_IVERSION ) |XFS_ILOG_CORE ); +/* +* Inode verifiers do not check that the CoW extent size hint is an +* integer multiple of the rt extent size on a directory with both +* rtinherit and cowextsize flags set. If we're logging a directory +* that is misconfigured in this way, clear the hint. +*/ +if ((ip->i_diflags &XFS_DIFLAG_RTINHERIT ) && + (ip->i_diflags2 &XFS_DIFLAG2_COWEXTSIZE ) && +xfs_extlen_to_rtxmod (ip->i_mount, ip->i_cowextsize) >0 ) { + ip->i_diflags2 &= ~XFS_DIFLAG2_COWEXTSIZE ; + ip->i_cowextsize =0 ; + flags |=XFS_ILOG_CORE ; + } +if (!iip->ili_item.li_buf) {struct xfs_buf *bp;int error;
fs/xfs/xfs_ioctl.c +15 -2
@@ -469,8 +469,21 @@ xfs_fill_fsxattr( } } -if (ip->i_diflags2 &XFS_DIFLAG2_COWEXTSIZE ) - fa->fsx_cowextsize =XFS_FSB_TO_B (mp, ip->i_cowextsize); +if (ip->i_diflags2 &XFS_DIFLAG2_COWEXTSIZE ) { +/* +* Don't let a misaligned CoW extent size hint on a directory +* escape to userspace if it won't pass the setattr checks +* later. +*/ +if ((ip->i_diflags &XFS_DIFLAG_RTINHERIT ) && + ip->i_cowextsize % mp->m_sb.sb_rextsize >0 ) { + fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE ; + fa->fsx_cowextsize =0 ; + }else { + fa->fsx_cowextsize =XFS_FSB_TO_B (mp, ip->i_cowextsize); + } + } + fa->fsx_projid = ip->i_projid;if (ifp && !xfs_need_iread_extents (ifp)) fa->fsx_nextents =xfs_iext_count (ifp);
PATCH 25/43 xfs: enable extent size hints for CoW operations
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Wire up the copy-on-write extent size hint for realtime files, and connect it to the rt allocator so that we avoid fragmentation on rt filesystems.
--- fs/xfs/libxfs/xfs_bmap.c | 8 +++++++- fs/xfs/xfs_rtalloc.c | 5 ++++- 2 files changed, 11 insertions(+), 2 deletions(-)
fs/xfs/libxfs/xfs_bmap.c +7 -1
@@ -6524,7 +6524,13 @@ xfs_get_cowextsz_hint( a =0 ;if (ip->i_diflags2 &XFS_DIFLAG2_COWEXTSIZE ) a = ip->i_cowextsize; - b =xfs_get_extsz_hint (ip); +if (XFS_IS_REALTIME_INODE (ip)) { + b =0 ; +if (ip->i_diflags &XFS_DIFLAG_EXTSIZE ) + b = ip->i_extsize; + }else { + b =xfs_get_extsz_hint (ip); + } a =max (a, b);if (a ==0 )
fs/xfs/xfs_rtalloc.c +4 -1
@@ -2021,7 +2021,10 @@ xfs_rtallocate_align(if (*noalign) { align = mp->m_sb.sb_rextsize; }else { - align =xfs_get_extsz_hint (ap->ip); +if (ap->flags &XFS_BMAPI_COWFORK ) + align =xfs_get_cowextsz_hint (ap->ip); +else + align =xfs_get_extsz_hint (ap->ip);if (!align) align =1 ;if (align == mp->m_sb.sb_rextsize)
PATCH 26/43 xfs: check that the rtrefcount maxlevels doesn't increase when growing fs
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
The size of filesystem transaction reservations depends on the maximum height (maxlevels) of the realtime btrees. Since we don't want a grow operation to increase the reservation size enough that we'll fail the minimum log size checks on the next mount, constrain growfs operations if they would cause an increase in the rt refcount btree maxlevels.
--- fs/xfs/xfs_fsops.c | 2 ++ fs/xfs/xfs_rtalloc.c | 2 ++ 2 files changed, 4 insertions(+)
fs/xfs/xfs_fsops.c +2 -0
@@ -23,6 +23,7 @@#include "xfs_trace.h" #include "xfs_rtalloc.h" #include "xfs_rtrmap_btree.h" +#include "xfs_rtrefcount_btree.h" /* * Write new AG headers to disk. Non-transactional, but need to be
@@ -231,6 +232,7 @@ xfs_growfs_data_private(/* Compute new maxlevels for rt btrees. */ xfs_rtrmapbt_compute_maxlevels (mp); +xfs_rtrefcountbt_compute_maxlevels (mp); }return error;
fs/xfs/xfs_rtalloc.c +2 -0
@@ -995,6 +995,7 @@ xfs_growfs_rt_bmblock(*/ mp->m_features |=XFS_FEAT_REALTIME ;xfs_rtrmapbt_compute_maxlevels (mp); +xfs_rtrefcountbt_compute_maxlevels (mp);kfree (nmp);return 0 ;
@@ -1178,6 +1179,7 @@ xfs_growfs_check_rtgeom( nmp->m_sb.sb_dblocks = dblocks;xfs_rtrmapbt_compute_maxlevels (nmp); +xfs_rtrefcountbt_compute_maxlevels (nmp);xfs_trans_resv_calc (nmp,M_RES (nmp));/*
PATCH 27/43 xfs: report realtime refcount btree corruption errors to the health system
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Whenever we encounter corrupt realtime refcount btree blocks, we should report that to the health monitoring system for later reporting.
--- fs/xfs/libxfs/xfs_fs.h | 1 + fs/xfs/libxfs/xfs_health.h | 4 +++- fs/xfs/libxfs/xfs_rtgroup.c | 1 + fs/xfs/libxfs/xfs_rtrefcount_btree.c | 10 ++++++++-- fs/xfs/xfs_health.c | 1 + 5 files changed, 14 insertions(+), 3 deletions(-)
fs/xfs/libxfs/xfs_fs.h +1 -0
@@ -996,6 +996,7 @@ struct xfs_rtgroup_geometry {#define XFS_RTGROUP_GEOM_SICK_BITMAP (1U << 1)/* rtbitmap */ #define XFS_RTGROUP_GEOM_SICK_SUMMARY (1U << 2)/* rtsummary */ #define XFS_RTGROUP_GEOM_SICK_RMAPBT (1U << 3)/* reverse mappings */ +#define XFS_RTGROUP_GEOM_SICK_REFCNTBT (1U << 4)/* reference counts */ /* * ioctl commands that are used by Linux filesystems
fs/xfs/libxfs/xfs_health.h +3 -1
@@ -71,6 +71,7 @@ struct xfs_rtgroup;#define XFS_SICK_RG_BITMAP (1 << 1)/* rt group bitmap */ #define XFS_SICK_RG_SUMMARY (1 << 2)/* rt groups summary */ #define XFS_SICK_RG_RMAPBT (1 << 3)/* reverse mappings */ +#define XFS_SICK_RG_REFCNTBT (1 << 4)/* reference counts */ /* Observable health issues for AG metadata. */ #define XFS_SICK_AG_SB (1 << 0)/* superblock */
@@ -117,7 +118,8 @@ struct xfs_rtgroup;#define XFS_SICK_RG_PRIMARY (XFS_SICK_RG_SUPER | \ XFS_SICK_RG_BITMAP | \ XFS_SICK_RG_SUMMARY | \ - XFS_SICK_RG_RMAPBT) + XFS_SICK_RG_RMAPBT | \ + XFS_SICK_RG_REFCNTBT)#define XFS_SICK_AG_PRIMARY (XFS_SICK_AG_SB | \ XFS_SICK_AG_AGF | \
fs/xfs/libxfs/xfs_rtgroup.c +1 -0
@@ -380,6 +380,7 @@ static const struct xfs_rtginode_ops xfs_rtginode_ops[XFS_RTGI_MAX] = { [XFS_RTGI_REFCOUNT] = { .name = "refcount", .metafile_type = XFS_METAFILE_RTREFCOUNT, + .sick = XFS_SICK_RG_REFCNTBT, .fmt_mask = 1U << XFS_DINODE_FMT_META_BTREE,/* same comment about growfs and rmap inodes applies here */ .enabled = xfs_has_reflink,
fs/xfs/libxfs/xfs_rtrefcount_btree.c +8 -2
@@ -27,6 +27,7 @@#include "xfs_rtgroup.h" #include "xfs_rtbitmap.h" #include "xfs_metafile.h" +#include "xfs_health.h" static struct kmem_cache *xfs_rtrefcountbt_cur_cache;
@@ -374,6 +375,7 @@ const struct xfs_btree_ops xfs_rtrefcountbt_ops = { .lru_refs = XFS_REFC_BTREE_REF, .statoff = XFS_STATS_CALC_INDEX(xs_rtrefcbt_2), + .sick_mask = XFS_SICK_RG_REFCNTBT, .dup_cursor = xfs_rtrefcountbt_dup_cursor, .alloc_block = xfs_btree_alloc_metafile_block,
@@ -640,16 +642,20 @@ xfs_iformat_rtrefcount(* volume to the filesystem, so we cannot use the rtrefcount predicate * here. */ -if (!xfs_has_reflink (ip->i_mount)) +if (!xfs_has_reflink (ip->i_mount)) { +xfs_inode_mark_sick (ip,XFS_SICK_INO_CORE );return -EFSCORRUPTED ; + } dsize =XFS_DFORK_SIZE (dip, mp,XFS_DATA_FORK ); numrecs =be16_to_cpu (dfp->bb_numrecs); level =be16_to_cpu (dfp->bb_level);if (level > mp->m_rtrefc_maxlevels || -xfs_rtrefcount_droot_space_calc (level, numrecs) > dsize) +xfs_rtrefcount_droot_space_calc (level, numrecs) > dsize) { +xfs_inode_mark_sick (ip,XFS_SICK_INO_CORE );return -EFSCORRUPTED ; + } broot =xfs_broot_alloc (xfs_ifork_ptr (ip,XFS_DATA_FORK ),xfs_rtrefcount_broot_space_calc (mp, level, numrecs));
fs/xfs/xfs_health.c +1 -0
@@ -448,6 +448,7 @@ static const struct ioctl_sick_map rtgroup_map[] = { { XFS_SICK_RG_BITMAP, XFS_RTGROUP_GEOM_SICK_BITMAP }, { XFS_SICK_RG_SUMMARY, XFS_RTGROUP_GEOM_SICK_SUMMARY }, { XFS_SICK_RG_RMAPBT, XFS_RTGROUP_GEOM_SICK_RMAPBT }, + { XFS_SICK_RG_REFCNTBT, XFS_RTGROUP_GEOM_SICK_REFCNTBT }, };/* Fill out rtgroup geometry health info. */
PATCH 28/43 xfs: scrub the realtime refcount btree
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Add code to scrub realtime refcount btrees. Similar to the refcount btree checking code for the data device, we walk the rmap btree for each refcount record to confirm that the reference counts are correct.
--- fs/xfs/Makefile | 1 fs/xfs/libxfs/xfs_fs.h | 3 fs/xfs/scrub/common.c | 10 + fs/xfs/scrub/common.h | 5 fs/xfs/scrub/health.c | 1 fs/xfs/scrub/rtrefcount.c | 487 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 7 + fs/xfs/scrub/scrub.h | 3 fs/xfs/scrub/stats.c | 1 fs/xfs/scrub/trace.h | 4 10 files changed, 519 insertions(+), 3 deletions(-) create mode 100644 fs/xfs/scrub/rtrefcount.c
fs/xfs/Makefile +1 -0
@@ -195,6 +195,7 @@ xfs-$(CONFIG_XFS_ONLINE_SCRUB_STATS) += scrub/stats.o xfs-$(CONFIG_XFS_RT) += $(addprefix scrub/, \ rgsuper.o \ rtbitmap.o \ + rtrefcount.o \ rtrmap.o \ rtsummary.o \ )
fs/xfs/libxfs/xfs_fs.h +2 -1
@@ -738,9 +738,10 @@ struct xfs_scrub_metadata {#define XFS_SCRUB_TYPE_METAPATH 29/* metadata directory tree paths */ #define XFS_SCRUB_TYPE_RGSUPER 30/* realtime superblock */ #define XFS_SCRUB_TYPE_RTRMAPBT 31/* rtgroup reverse mapping btree */ +#define XFS_SCRUB_TYPE_RTREFCBT 32/* realtime reference count btree */ /* Number of scrub subcommands. */ -#define XFS_SCRUB_TYPE_NR 32 +#define XFS_SCRUB_TYPE_NR 33/* * This special type code only applies to the vectored scrub implementation.
fs/xfs/scrub/common.c +10 -0
@@ -37,6 +37,7 @@#include "xfs_rtgroup.h" #include "xfs_rtrmap_btree.h" #include "xfs_bmap_util.h" +#include "xfs_rtrefcount_btree.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/trace.h"
@@ -797,6 +798,9 @@ xchk_rtgroup_lock(if (xfs_has_rtrmapbt (sc->mp) && (rtglock_flags &XFS_RTGLOCK_RMAP )) sr->rmap_cur =xfs_rtrmapbt_init_cursor (sc->tp, sr->rtg); +if (xfs_has_rtreflink (sc->mp) && (rtglock_flags &XFS_RTGLOCK_REFCOUNT )) + sr->refc_cur =xfs_rtrefcountbt_init_cursor (sc->tp, sr->rtg); +return 0 ; }
@@ -811,7 +815,10 @@ xchk_rtgroup_btcur_free( {if (sr->rmap_cur)xfs_btree_del_cursor (sr->rmap_cur,XFS_BTREE_ERROR ); +if (sr->refc_cur) +xfs_btree_del_cursor (sr->refc_cur,XFS_BTREE_ERROR ); + sr->refc_cur =NULL ; sr->rmap_cur =NULL ; }
@@ -1687,6 +1694,9 @@ xchk_meta_btree_count_blocks(case XFS_METAFILE_RTRMAP : cur =xfs_rtrmapbt_init_cursor (sc->tp, sc->sr.rtg);break ; +case XFS_METAFILE_RTREFCOUNT : + cur =xfs_rtrefcountbt_init_cursor (sc->tp, sc->sr.rtg); +break ;default :ASSERT (0 );return -EFSCORRUPTED ;
fs/xfs/scrub/common.h +4 -1
@@ -82,11 +82,13 @@ int xchk_setup_rtbitmap(struct xfs_scrub *sc);int xchk_setup_rtsummary (struct xfs_scrub *sc);int xchk_setup_rgsuperblock (struct xfs_scrub *sc);int xchk_setup_rtrmapbt (struct xfs_scrub *sc); +int xchk_setup_rtrefcountbt (struct xfs_scrub *sc);#else # define xchk_setup_rtbitmap xchk_setup_nothing# define xchk_setup_rtsummary xchk_setup_nothing# define xchk_setup_rgsuperblock xchk_setup_nothing# define xchk_setup_rtrmapbt xchk_setup_nothing +# define xchk_setup_rtrefcountbt xchk_setup_nothing#endif #ifdef CONFIG_XFS_QUOTA int xchk_ino_dqattach (struct xfs_scrub *sc);
@@ -129,7 +131,8 @@ xchk_ag_init_existing(/* All the locks we need to check an rtgroup. */ #define XCHK_RTGLOCK_ALL (XFS_RTGLOCK_BITMAP | \ - XFS_RTGLOCK_RMAP) + XFS_RTGLOCK_RMAP | \ + XFS_RTGLOCK_REFCOUNT)int xchk_rtgroup_init (struct xfs_scrub *sc,xfs_rgnumber_t rgno,struct xchk_rt *sr);
fs/xfs/scrub/health.c +1 -0
@@ -115,6 +115,7 @@ static const struct xchk_health_map type_to_health_flag[XFS_SCRUB_TYPE_NR] = { [XFS_SCRUB_TYPE_METAPATH] = { XHG_FS, XFS_SICK_FS_METAPATH }, [XFS_SCRUB_TYPE_RGSUPER] = { XHG_RTGROUP, XFS_SICK_RG_SUPER }, [XFS_SCRUB_TYPE_RTRMAPBT] = { XHG_RTGROUP, XFS_SICK_RG_RMAPBT }, + [XFS_SCRUB_TYPE_RTREFCBT] = { XHG_RTGROUP, XFS_SICK_RG_REFCNTBT }, };/* Return the health status mask for this scrub type. */
fs/xfs/scrub/rtrefcount.c new file +487 -0
487 lines not on this page · raw message
fs/xfs/scrub/scrub.c +7 -0
@@ -467,6 +467,13 @@ static const struct xchk_meta_ops meta_scrub_ops[] = { .has = xfs_has_rtrmapbt, .repair = xrep_rtrmapbt, }, + [XFS_SCRUB_TYPE_RTREFCBT] = { /* realtime refcountbt */ + .type = ST_RTGROUP, + .setup = xchk_setup_rtrefcountbt, + .scrub = xchk_rtrefcountbt, + .has = xfs_has_rtreflink, + .repair = xrep_notsupported, + }, }; static int
fs/xfs/scrub/scrub.h +3 -0
@@ -129,6 +129,7 @@ struct xchk_rt {/* rtgroup btrees */ struct xfs_btree_cur *rmap_cur; +struct xfs_btree_cur *refc_cur; };struct xfs_scrub {
@@ -284,11 +285,13 @@ int xchk_rtbitmap(struct xfs_scrub *sc);int xchk_rtsummary (struct xfs_scrub *sc);int xchk_rgsuperblock (struct xfs_scrub *sc);int xchk_rtrmapbt (struct xfs_scrub *sc); +int xchk_rtrefcountbt (struct xfs_scrub *sc);#else # define xchk_rtbitmap xchk_nothing# define xchk_rtsummary xchk_nothing# define xchk_rgsuperblock xchk_nothing# define xchk_rtrmapbt xchk_nothing +# define xchk_rtrefcountbt xchk_nothing#endif #ifdef CONFIG_XFS_QUOTA int xchk_quota (struct xfs_scrub *sc);
fs/xfs/scrub/stats.c +1 -0
@@ -83,6 +83,7 @@ static const char *name_map[XFS_SCRUB_TYPE_NR] = { [XFS_SCRUB_TYPE_METAPATH] = "metapath", [XFS_SCRUB_TYPE_RGSUPER] = "rgsuper", [XFS_SCRUB_TYPE_RTRMAPBT] = "rtrmapbt", + [XFS_SCRUB_TYPE_RTREFCBT] = "rtrefcountbt", };/* Format the scrub stats into a text buffer, similar to pcp style. */
fs/xfs/scrub/trace.h +3 -1
@@ -77,6 +77,7 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_BARRIER);TRACE_DEFINE_ENUM (XFS_SCRUB_TYPE_METAPATH );TRACE_DEFINE_ENUM (XFS_SCRUB_TYPE_RGSUPER );TRACE_DEFINE_ENUM (XFS_SCRUB_TYPE_RTRMAPBT ); +TRACE_DEFINE_ENUM (XFS_SCRUB_TYPE_RTREFCBT );#define XFS_SCRUB_TYPE_STRINGS \ { XFS_SCRUB_TYPE_PROBE, "probe" }, \
@@ -111,7 +112,8 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_RTRMAPBT); { XFS_SCRUB_TYPE_BARRIER, "barrier" }, \ { XFS_SCRUB_TYPE_METAPATH, "metapath" }, \ { XFS_SCRUB_TYPE_RGSUPER, "rgsuper" }, \ - { XFS_SCRUB_TYPE_RTRMAPBT, "rtrmapbt" } + { XFS_SCRUB_TYPE_RTRMAPBT, "rtrmapbt" }, \ + { XFS_SCRUB_TYPE_RTREFCBT, "rtrefcountbt" } #define XFS_SCRUB_FLAG_STRINGS \ { XFS_SCRUB_IFLAG_REPAIR, "repair" }, \
PATCH 29/43 xfs: cross-reference checks with the rt refcount btree
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Use the realtime refcount btree to implement cross-reference checks in other data structures.
--- fs/xfs/scrub/bmap.c | 30 +++++++++++++--- fs/xfs/scrub/rtbitmap.c | 2 + fs/xfs/scrub/rtrefcount.c | 86 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/rtrmap.c | 37 +++++++++++++++++++ fs/xfs/scrub/scrub.h | 9 +++++ 5 files changed, 158 insertions(+), 6 deletions(-)
fs/xfs/scrub/bmap.c +24 -6
@@ -347,13 +347,31 @@ xchk_bmap_rt_iextent_xref( goto out_cur; rgbno =xfs_rtb_to_rgbno (info->sc->mp, irec->br_startblock); -xchk_bmap_xref_rmap (info, irec, rgbno); - -xfs_rmap_ino_owner (&oinfo, info->sc->ip->i_ino, info->whichfork, - irec->br_startoff); -xchk_xref_is_only_rt_owned_by (info->sc, rgbno, - irec->br_blockcount, &oinfo); +switch (info->whichfork) { +case XFS_DATA_FORK : +xchk_bmap_xref_rmap (info, irec, rgbno); +if (!xfs_is_reflink_inode (info->sc->ip)) { +xfs_rmap_ino_owner (&oinfo, info->sc->ip->i_ino, + info->whichfork, irec->br_startoff); +xchk_xref_is_only_rt_owned_by (info->sc, rgbno, + irec->br_blockcount, &oinfo); +xchk_xref_is_not_rt_shared (info->sc, rgbno, + irec->br_blockcount); + } +xchk_xref_is_not_rt_cow_staging (info->sc, rgbno, + irec->br_blockcount); +break ; +case XFS_COW_FORK : +xchk_bmap_xref_rmap_cow (info, irec, rgbno); +xchk_xref_is_only_rt_owned_by (info->sc, rgbno, + irec->br_blockcount, &XFS_RMAP_OINFO_COW ); +xchk_xref_is_rt_cow_staging (info->sc, rgbno, + irec->br_blockcount); +xchk_xref_is_not_rt_shared (info->sc, rgbno, + irec->br_blockcount); +break ; + } out_cur:xchk_rtgroup_btcur_free (&info->sc->sr); out_free:
fs/xfs/scrub/rtbitmap.c +2 -0
@@ -105,6 +105,8 @@ xchk_rtbitmap_xref(return ;xchk_xref_has_no_rt_owner (sc, rgbno, blockcount); +xchk_xref_is_not_rt_shared (sc, rgbno, blockcount); +xchk_xref_is_not_rt_cow_staging (sc, rgbno, blockcount);if (rtb->next_free_rgbno < rgbno) xchk_xref_has_rt_owner(sc, rtb->next_free_rgbno,
fs/xfs/scrub/rtrefcount.c +86 -0
89 lines not on this page · raw message
fs/xfs/scrub/rtrmap.c +37 -0
@@ -22,6 +22,7 @@#include "xfs_rtalloc.h" #include "xfs_rtgroup.h" #include "xfs_metafile.h" +#include "xfs_refcount.h" #include "scrub/xfs_scrub.h" #include "scrub/scrub.h" #include "scrub/common.h"
@@ -149,6 +150,37 @@ xchk_rtrmapbt_check_mergeable(memcpy (&cr->prev_rec, irec,sizeof (struct xfs_rmap_irec )); } +/* Cross-reference a rmap against the refcount btree. */ +STATIC void +xchk_rtrmapbt_xref_rtrefc ( +struct xfs_scrub *sc, +struct xfs_rmap_irec *irec) +{ +xfs_rgblock_t fbno; +xfs_extlen_t flen; +bool is_inode; +bool is_bmbt; +bool is_attr; +bool is_unwritten; +int error; + +if (!sc->sr.refc_cur ||xchk_skip_xref (sc->sm)) +return ; + + is_inode = !XFS_RMAP_NON_INODE_OWNER (irec->rm_owner); + is_bmbt = irec->rm_flags &XFS_RMAP_BMBT_BLOCK ; + is_attr = irec->rm_flags &XFS_RMAP_ATTR_FORK ; + is_unwritten = irec->rm_flags &XFS_RMAP_UNWRITTEN ; + +/* If this is shared, must be a data fork extent. */ + error =xfs_refcount_find_shared (sc->sr.refc_cur, irec->rm_startblock, + irec->rm_blockcount, &fbno, &flen, false); +if (!xchk_should_check_xref (sc, &error, &sc->sr.refc_cur)) +return ; +if (flen !=0 && (!is_inode || is_attr || is_bmbt || is_unwritten)) +xchk_btree_xref_set_corrupt (sc, sc->sr.refc_cur,0 ); +} +/* Cross-reference with other metadata. */ STATIC void xchk_rtrmapbt_xref(
@@ -161,6 +193,11 @@ xchk_rtrmapbt_xref(xchk_xref_is_used_rt_space (sc,xfs_rgbno_to_rtb (sc->sr.rtg, irec->rm_startblock), irec->rm_blockcount); +if (irec->rm_owner ==XFS_RMAP_OWN_COW ) +xchk_xref_is_cow_staging (sc, irec->rm_startblock, + irec->rm_blockcount); +else +xchk_rtrmapbt_xref_rtrefc (sc, irec); }/* Scrub a realtime rmapbt record. */
fs/xfs/scrub/scrub.h +9 -0
@@ -331,11 +331,20 @@ void xchk_xref_has_rt_owner(struct xfs_scrub *sc, xfs_rgblock_t rgbno, xfs_extlen_t len);void xchk_xref_is_only_rt_owned_by (struct xfs_scrub *sc,xfs_rgblock_t rgbno,xfs_extlen_t len,const struct xfs_owner_info *oinfo); +void xchk_xref_is_rt_cow_staging (struct xfs_scrub *sc,xfs_rgblock_t rgbno, +xfs_extlen_t len); +void xchk_xref_is_not_rt_shared (struct xfs_scrub *sc,xfs_rgblock_t rgbno, +xfs_extlen_t len); +void xchk_xref_is_not_rt_cow_staging (struct xfs_scrub *sc,xfs_rgblock_t rgbno, +xfs_extlen_t len);#else # define xchk_xref_is_used_rt_space (sc, rtbno, len) do { } while (0)# define xchk_xref_has_no_rt_owner (sc, rtbno, len) do { } while (0)# define xchk_xref_has_rt_owner (sc, rtbno, len) do { } while (0)# define xchk_xref_is_only_rt_owned_by (sc, bno, len, oinfo) do { } while (0) +# define xchk_xref_is_rt_cow_staging (sc, bno, len) do { } while (0) +# define xchk_xref_is_not_rt_shared (sc, bno, len) do { } while (0) +# define xchk_xref_is_not_rt_cow_staging (sc, bno, len) do { } while (0)#endif #endif /* __XFS_SCRUB_SCRUB_H__ */
PATCH 30/43 xfs: allow overlapping rtrmapbt records for shared data extents
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Allow overlapping realtime reverse mapping records if they both describe shared data extents and the fs supports reflink on the realtime volume.
--- fs/xfs/scrub/rtrmap.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-)
fs/xfs/scrub/rtrmap.c +16 -1
@@ -78,6 +78,18 @@ struct xchk_rtrmap {struct xfs_rmap_irec prev_rec; }; +static inline bool +xchk_rtrmapbt_is_shareable ( +struct xfs_scrub *sc, +const struct xfs_rmap_irec *irec) +{ +if (!xfs_has_rtreflink (sc->mp)) +return false; +if (irec->rm_flags &XFS_RMAP_UNWRITTEN ) +return false; +return true; +} +/* Flag failures for records that overlap but cannot. */ STATIC void xchk_rtrmapbt_check_overlapping(
@@ -99,7 +111,10 @@ xchk_rtrmapbt_check_overlapping(if (pnext <= irec->rm_startblock) goto set_prev; -xchk_btree_set_corrupt (bs->sc, bs->cur,0 ); +/* Overlap is only allowed if both records are data fork mappings. */ +if (!xchk_rtrmapbt_is_shareable (bs->sc, &cr->overlap_rec) || + !xchk_rtrmapbt_is_shareable (bs->sc, irec)) +xchk_btree_set_corrupt (bs->sc, bs->cur,0 );/* Save whichever rmap record extends furthest. */ inext = irec->rm_startblock + irec->rm_blockcount;
PATCH 31/43 xfs: check reference counts of gaps between rt refcount records
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
If there's a gap between records in the rt refcount btree, we ought to cross-reference the gap with the rtrmap records to make sure that there aren't any overlapping records for a region that doesn't have any shared ownership.
--- fs/xfs/scrub/rtrefcount.c | 81 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-)
fs/xfs/scrub/rtrefcount.c +80 -1
@@ -17,6 +17,7 @@#include "xfs_rtgroup.h" #include "xfs_metafile.h" #include "xfs_rtrefcount_btree.h" +#include "xfs_rtalloc.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/btree.h"
@@ -348,8 +349,14 @@ struct xchk_rtrefcbt_records {/* Previous refcount record. */ struct xfs_refcount_irec prev_rec; +/* The next rtgroup block where we aren't expecting shared extents. */ +xfs_rgblock_t next_unshared_rgbno; +/* Number of CoW blocks we expect. */ xfs_extlen_t cow_blocks; + +/* Was the last record a shared or CoW staging extent? */ +enum xfs_refc_domain prev_domain; }; static inline bool
@@ -390,6 +397,53 @@ xchk_rtrefcountbt_check_mergeable(memcpy (&rrc->prev_rec, irec,sizeof (struct xfs_refcount_irec )); } +STATIC int +xchk_rtrefcountbt_rmap_check_gap ( +struct xfs_btree_cur *cur, +const struct xfs_rmap_irec *rec, +void *priv) +{ +xfs_rgblock_t *next_bno = priv; + +if (*next_bno !=NULLRGBLOCK && rec->rm_startblock < *next_bno) +return -ECANCELED ; + + *next_bno = rec->rm_startblock + rec->rm_blockcount; +return 0 ; +} + +/* +* Make sure that a gap in the reference count records does not correspond to +* overlapping records (i.e. shared extents) in the reverse mappings. +*/ +static inline void +xchk_rtrefcountbt_xref_gaps ( +struct xfs_scrub *sc, +struct xchk_rtrefcbt_records *rrc, +xfs_rtblock_t bno) +{ +struct xfs_rmap_irec low; +struct xfs_rmap_irec high; +xfs_rgblock_t next_bno =NULLRGBLOCK ; +int error; + +if (bno <= rrc->next_unshared_rgbno || !sc->sr.rmap_cur || +xchk_skip_xref (sc->sm)) +return ; + +memset (&low,0 ,sizeof (low)); + low.rm_startblock = rrc->next_unshared_rgbno; +memset (&high,0xFF ,sizeof (high)); + high.rm_startblock = bno -1 ; + + error =xfs_rmap_query_range (sc->sr.rmap_cur, &low, &high, + xchk_rtrefcountbt_rmap_check_gap, &next_bno); +if (error == -ECANCELED ) +xchk_btree_xref_set_corrupt (sc, sc->sr.rmap_cur,0 ); +else +xchk_should_check_xref (sc, &error, &sc->sr.rmap_cur); +} +/* Scrub a rtrefcountbt record. */ STATIC int xchk_rtrefcountbt_rec(
@@ -419,9 +473,26 @@ xchk_rtrefcountbt_rec(if (irec.rc_domain ==XFS_REFC_DOMAIN_COW ) rrc->cow_blocks += irec.rc_blockcount; +/* Shared records always come before CoW records. */ +if (irec.rc_domain ==XFS_REFC_DOMAIN_SHARED && + rrc->prev_domain ==XFS_REFC_DOMAIN_COW ) +xchk_btree_set_corrupt (bs->sc, bs->cur,0 ); + rrc->prev_domain = irec.rc_domain; +xchk_rtrefcountbt_check_mergeable (bs, rrc, &irec);xchk_rtrefcountbt_xref (bs->sc, &irec); +/* +* If this is a record for a shared extent, check that all blocks +* between the previous record and this one have at most one reverse +* mapping. +*/ +if (irec.rc_domain ==XFS_REFC_DOMAIN_SHARED ) { +xchk_rtrefcountbt_xref_gaps (bs->sc, rrc, irec.rc_startblock); + rrc->next_unshared_rgbno = irec.rc_startblock + + irec.rc_blockcount; + } +return 0 ; }
@@ -466,7 +537,9 @@ xchk_rtrefcountbt( {struct xfs_owner_info btree_oinfo;struct xchk_rtrefcbt_records rrc = { - .cow_blocks =0 , + .cow_blocks =0 , + .next_unshared_rgbno =0 , + .prev_domain =XFS_REFC_DOMAIN_SHARED , };int error;
@@ -481,6 +554,12 @@ xchk_rtrefcountbt(if (error || (sc->sm->sm_flags &XFS_SCRUB_OFLAG_CORRUPT ))return error; +/* +* Check that all blocks between the last refcount > 1 record and the +* end of the rt volume have at most one reverse mapping. +*/ +xchk_rtrefcountbt_xref_gaps (sc, &rrc, sc->mp->m_sb.sb_rblocks); +xchk_refcount_xref_rmap (sc, &btree_oinfo, rrc.cow_blocks);return 0 ;
PATCH 32/43 xfs: allow dquot rt block count to exceed rt blocks on reflink fs
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Update the quota scrubber to allow dquots where the realtime block count exceeds the block count of the rt volume if reflink is enabled.
--- fs/xfs/scrub/quota.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
fs/xfs/scrub/quota.c +7 -1
@@ -212,12 +212,18 @@ xchk_quota_item(if (mp->m_sb.sb_dblocks < dq->q_blk.count)xchk_fblock_set_warning (sc,XFS_DATA_FORK , offset); +if (mp->m_sb.sb_rblocks < dq->q_rtb.count) +xchk_fblock_set_warning (sc,XFS_DATA_FORK , + offset); }else {if (mp->m_sb.sb_dblocks < dq->q_blk.count)xchk_fblock_set_corrupt (sc,XFS_DATA_FORK , offset); +if (mp->m_sb.sb_rblocks < dq->q_rtb.count) +xchk_fblock_set_corrupt (sc,XFS_DATA_FORK , + offset); } -if (dq->q_ino.count > fs_icount || dq->q_rtb.count > mp->m_sb.sb_rblocks) +if (dq->q_ino.count > fs_icount)xchk_fblock_set_corrupt (sc,XFS_DATA_FORK , offset);/*
PATCH 33/43 xfs: detect and repair misaligned rtinherit directory cowextsize hints
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
If we encounter a directory that has been configured to pass on a CoW extent size hint to a new realtime file and the hint isn't an integer multiple of the rt extent size, we should flag the hint for administrative review and/or turn it off because that is a misconfiguration.
--- fs/xfs/scrub/inode.c | 26 +++++++++++++++++--------- fs/xfs/scrub/inode_repair.c | 15 +++++++++++++++ 2 files changed, 32 insertions(+), 9 deletions(-)
fs/xfs/scrub/inode.c +17 -9
@@ -260,12 +260,7 @@ xchk_inode_extsize(xchk_ino_set_warning (sc, ino); } -/* -* Validate di_cowextsize hint. -* -* The rules are documented at xfs_ioctl_setattr_check_cowextsize(). -* These functions must be kept in sync with each other. -*/ +/* Validate di_cowextsize hint. */ STATIC void xchk_inode_cowextsize( struct xfs_scrub *sc,
@@ -276,12 +271,25 @@ xchk_inode_cowextsize( uint64_t flags2) {xfs_failaddr_t fa; +uint32_t value =be32_to_cpu (dip->di_cowextsize); - fa =xfs_inode_validate_cowextsize (sc->mp, -be32_to_cpu (dip->di_cowextsize), mode, flags, - flags2); + fa =xfs_inode_validate_cowextsize (sc->mp, value, mode, flags, flags2);if (fa)xchk_ino_set_corrupt (sc, ino); + +/* +* XFS allows a sysadmin to change the rt extent size when adding a rt +* section to a filesystem after formatting. If there are any +* directories with cowextsize and rtinherit set, the hint could become +* misaligned with the new rextsize. The verifier doesn't check this, +* because we allow rtinherit directories even without an rt device. +* Flag this as an administrative warning since we will clean this up +* eventually. +*/ +if ((flags &XFS_DIFLAG_RTINHERIT ) && + (flags2 &XFS_DIFLAG2_COWEXTSIZE ) && + value % sc->mp->m_sb.sb_rextsize >0 ) +xchk_ino_set_warning (sc, ino); }/* Make sure the di_flags make sense for the inode. */
fs/xfs/scrub/inode_repair.c +15 -0
@@ -1903,6 +1903,20 @@ xrep_inode_pptr( sizeof(struct xfs_attr_sf_hdr), true); } +/* Fix COW extent size hint problems. */ +STATIC void +xrep_inode_cowextsize ( +struct xfs_scrub *sc) +{ +/* Fix misaligned CoW extent size hints on a directory. */ +if ((sc->ip->i_diflags &XFS_DIFLAG_RTINHERIT ) && + (sc->ip->i_diflags2 &XFS_DIFLAG2_COWEXTSIZE ) && + sc->ip->i_extsize % sc->mp->m_sb.sb_rextsize >0 ) { + sc->ip->i_cowextsize =0 ; + sc->ip->i_diflags2 &= ~XFS_DIFLAG2_COWEXTSIZE ; + } +} +/* Fix any irregularities in an inode that the verifiers don't catch. */ STATIC int xrep_inode_problems(
@@ -1926,6 +1940,7 @@ xrep_inode_problems(if (S_ISDIR (VFS_I (sc->ip)->i_mode))xrep_inode_dir_size (sc);xrep_inode_extsize (sc); +xrep_inode_cowextsize (sc);trace_xrep_inode_fixed (sc);xfs_trans_log_inode (sc->tp, sc->ip,XFS_ILOG_CORE );
PATCH 34/43 xfs: scrub the metadir path of rt refcount btree files
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Add a new XFS_SCRUB_METAPATH subtype so that we can scrub the metadata directory tree path to the refcount btree file for each rt group.
--- fs/xfs/libxfs/xfs_fs.h | 3 ++- fs/xfs/scrub/metapath.c | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-)
fs/xfs/libxfs/xfs_fs.h +2 -1
@@ -832,9 +832,10 @@ struct xfs_scrub_vec_head {#define XFS_SCRUB_METAPATH_GRPQUOTA (6)/* group quota */ #define XFS_SCRUB_METAPATH_PRJQUOTA (7)/* project quota */ #define XFS_SCRUB_METAPATH_RTRMAPBT (8)/* realtime reverse mapping */ +#define XFS_SCRUB_METAPATH_RTREFCOUNTBT (9)/* realtime refcount */ /* Number of metapath sm_ino values */ -#define XFS_SCRUB_METAPATH_NR (9) +#define XFS_SCRUB_METAPATH_NR (10)/* * ioctl limits
fs/xfs/scrub/metapath.c +3 -0
@@ -22,6 +22,7 @@#include "xfs_attr.h" #include "xfs_rtgroup.h" #include "xfs_rtrmap_btree.h" +#include "xfs_rtrefcount_btree.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/trace.h"
@@ -249,6 +250,8 @@ xchk_setup_metapath(return xchk_setup_metapath_dqinode (sc,XFS_DQTYPE_PROJ );case XFS_SCRUB_METAPATH_RTRMAPBT :return xchk_setup_metapath_rtginode (sc,XFS_RTGI_RMAP ); +case XFS_SCRUB_METAPATH_RTREFCOUNTBT : +return xchk_setup_metapath_rtginode (sc,XFS_RTGI_REFCOUNT );default :return -ENOENT ; }
PATCH 35/43 xfs: don't flag quota rt block usage on rtreflink filesystems
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Quota space usage is allowed to exceed the size of the physical storage when reflink is enabled. Now that we have reflink for the realtime volume, apply this same logic to the rtb repair logic.
--- fs/xfs/scrub/quota_repair.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/scrub/quota_repair.c +1 -1
@@ -233,7 +233,7 @@ xrep_quota_item( rqi->need_quotacheck = true; dirty = true; } -if (dq->q_rtb.count > mp->m_sb.sb_rblocks) { +if (!xfs_has_reflink (mp) && dq->q_rtb.count > mp->m_sb.sb_rblocks) { dq->q_rtb.reserved -= dq->q_rtb.count; dq->q_rtb.reserved += mp->m_sb.sb_rblocks; dq->q_rtb.count = mp->m_sb.sb_rblocks;
PATCH 36/43 xfs: check new rtbitmap records against rt refcount btree
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
When we're rebuilding the realtime bitmap, check the proposed free extents against the rt refcount btree to make sure we don't commit any grievous errors.
--- fs/xfs/scrub/repair.c | 6 ++++++ fs/xfs/scrub/rtbitmap_repair.c | 24 +++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-)
fs/xfs/scrub/repair.c +6 -0
@@ -42,6 +42,7 @@#include "xfs_rtgroup.h" #include "xfs_rtalloc.h" #include "xfs_metafile.h" +#include "xfs_rtrefcount_btree.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/trace.h"
@@ -1009,6 +1010,11 @@ xrep_rtgroup_btcur_init( (sr->rtlock_flags &XFS_RTGLOCK_RMAP ) && xfs_has_rtrmapbt(mp)) sr->rmap_cur = xfs_rtrmapbt_init_cursor(sc->tp, sr->rtg); + +if (sc->sm->sm_type !=XFS_SCRUB_TYPE_RTREFCBT && + (sr->rtlock_flags &XFS_RTGLOCK_REFCOUNT ) && +xfs_has_rtreflink (mp)) + sr->refc_cur =xfs_rtrefcountbt_init_cursor (sc->tp, sr->rtg); }/*
fs/xfs/scrub/rtbitmap_repair.c +23 -1
@@ -23,6 +23,7 @@#include "xfs_rtbitmap.h" #include "xfs_rtgroup.h" #include "xfs_extent_busy.h" +#include "xfs_refcount.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/trace.h"
@@ -183,7 +184,8 @@ xrep_rtbitmap_mark_free( xfs_rgblock_t rgbno) {struct xfs_mount *mp = rtb->sc->mp; -struct xfs_rtgroup *rtg = rtb->sc->sr.rtg; +struct xchk_rt *sr = &rtb->sc->sr; +struct xfs_rtgroup *rtg = sr->rtg;xfs_rtxnum_t startrtx;xfs_rtxnum_t nextrtx;xrep_wordoff_t wordoff, nextwordoff;
@@ -191,6 +193,7 @@ xrep_rtbitmap_mark_free(unsigned int bufwsize;xfs_extlen_t mod;xfs_rtword_t mask; +enum xbtree_recpacking outcome;int error;if (!xfs_verify_rgbext (rtg, rtb->next_rgbno, rgbno - rtb->next_rgbno))
@@ -210,6 +213,25 @@ xrep_rtbitmap_mark_free(if (mod != mp->m_sb.sb_rextsize -1 )return -EFSCORRUPTED ; +/* Must not be shared or CoW staging. */ +if (sr->refc_cur) { + error =xfs_refcount_has_records (sr->refc_cur, +XFS_REFC_DOMAIN_SHARED , rtb->next_rgbno, + rgbno - rtb->next_rgbno, &outcome); +if (error) +return error; +if (outcome !=XBTREE_RECPACKING_EMPTY ) +return -EFSCORRUPTED ; + + error =xfs_refcount_has_records (sr->refc_cur, +XFS_REFC_DOMAIN_COW , rtb->next_rgbno, + rgbno - rtb->next_rgbno, &outcome); +if (error) +return error; +if (outcome !=XBTREE_RECPACKING_EMPTY ) +return -EFSCORRUPTED ; + } +trace_xrep_rtbitmap_record_free (mp, startrtx, nextrtx -1 );/* Set bits as needed to round startrtx up to the nearest word. */
PATCH 37/43 xfs: walk the rt reference count tree when rebuilding rmap
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
When we're rebuilding the data device rmap, if we encounter a "refcount" format fork, we have to walk the (realtime) refcount btree inode to build the appropriate mappings.
--- fs/xfs/scrub/rmap_repair.c | 7 +++++++ 1 file changed, 7 insertions(+)
fs/xfs/scrub/rmap_repair.c +7 -0
@@ -33,6 +33,7 @@#include "xfs_ag.h" #include "xfs_rtrmap_btree.h" #include "xfs_rtgroup.h" +#include "xfs_rtrefcount_btree.h" #include "scrub/xfs_scrub.h" #include "scrub/scrub.h" #include "scrub/common.h"
@@ -519,6 +520,9 @@ xrep_rmap_scan_meta_btree(case XFS_METAFILE_RTRMAP : type =XFS_RTGI_RMAP ;break ; +case XFS_METAFILE_RTREFCOUNT : + type =XFS_RTGI_REFCOUNT ; +break ;default :ASSERT (0 );return -EFSCORRUPTED ;
@@ -545,6 +549,9 @@ xrep_rmap_scan_meta_btree(case XFS_METAFILE_RTRMAP : cur =xfs_rtrmapbt_init_cursor (sc->tp, rtg);break ; +case XFS_METAFILE_RTREFCOUNT : + cur =xfs_rtrefcountbt_init_cursor (sc->tp, rtg); +break ;default :ASSERT (0 ); error = -EFSCORRUPTED ;
PATCH 38/43 xfs: capture realtime CoW staging extents when rebuilding rt rmapbt
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Walk the realtime refcount btree to find the CoW staging extents when we're rebuilding the realtime rmap btree.
--- fs/xfs/scrub/repair.h | 1 fs/xfs/scrub/rgb_bitmap.h | 37 +++++++++++++++ fs/xfs/scrub/rtrmap_repair.c | 103 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 fs/xfs/scrub/rgb_bitmap.h
fs/xfs/scrub/repair.h +1 -0
@@ -50,6 +50,7 @@ xrep_trans_commit(struct xbitmap ;struct xagb_bitmap ; +struct xrgb_bitmap ;struct xfsb_bitmap ;int xrep_fix_freelist (struct xfs_scrub *sc,int alloc_flags);
fs/xfs/scrub/rgb_bitmap.h new file +37 -0
@@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* +* Copyright (c) 2020-2024 Oracle. All Rights Reserved. +* Author: Darrick J. Wong <[email protected]> +*/ +#ifndef __XFS_SCRUB_RGB_BITMAP_H__ +#define __XFS_SCRUB_RGB_BITMAP_H__ + +/* Bitmaps, but for type-checked for xfs_rgblock_t */ + +struct xrgb_bitmap { +struct xbitmap32 rgbitmap; +}; + +static inline void xrgb_bitmap_init (struct xrgb_bitmap *bitmap) +{ +xbitmap32_init (&bitmap->rgbitmap); +} + +static inline void xrgb_bitmap_destroy (struct xrgb_bitmap *bitmap) +{ +xbitmap32_destroy (&bitmap->rgbitmap); +} + +static inline int xrgb_bitmap_set (struct xrgb_bitmap *bitmap, +xfs_rgblock_t start,xfs_extlen_t len) +{ +return xbitmap32_set (&bitmap->rgbitmap, start, len); +} + +static inline int xrgb_bitmap_walk (struct xrgb_bitmap *bitmap, +xbitmap32_walk_fn fn,void *priv) +{ +return xbitmap32_walk (&bitmap->rgbitmap, fn, priv); +} + +#endif /* __XFS_SCRUB_RGB_BITMAP_H__ */
fs/xfs/scrub/rtrmap_repair.c +103 -0
127 lines not on this page · raw message
PATCH 39/43 xfs: online repair of the realtime refcount btree
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Port the data device's refcount btree repair code to the realtime refcount btree.
--- fs/xfs/Makefile | 1 fs/xfs/scrub/refcount_repair.c | 2 fs/xfs/scrub/repair.h | 5 fs/xfs/scrub/rtrefcount.c | 9 fs/xfs/scrub/rtrefcount_repair.c | 783 ++++++++++++++++++++++++++++++++++++++ fs/xfs/scrub/scrub.c | 2 fs/xfs/scrub/trace.h | 14 - 7 files changed, 809 insertions(+), 7 deletions(-) create mode 100644 fs/xfs/scrub/rtrefcount_repair.c
fs/xfs/Makefile +1 -0
@@ -236,6 +236,7 @@ xfs-y += $(addprefix scrub/, \ xfs-$(CONFIG_XFS_RT) += $(addprefix scrub/, \ rtbitmap_repair.o \ + rtrefcount_repair.o \ rtrmap_repair.o \ rtsummary_repair.o \ )
fs/xfs/scrub/refcount_repair.c +1 -1
@@ -189,7 +189,7 @@ xrep_refc_stash(if (error)return error; -trace_xrep_refc_found (sc->sa.pag, &irec); +trace_xrep_refc_found (pag_group (sc->sa.pag), &irec);return xfarray_append (rr->refcount_records, &irec); }
fs/xfs/scrub/repair.h +5 -0
@@ -99,6 +99,7 @@ int xrep_setup_nlinks(struct xfs_scrub *sc);int xrep_setup_symlink (struct xfs_scrub *sc,unsigned int *resblks);int xrep_setup_dirtree (struct xfs_scrub *sc);int xrep_setup_rtrmapbt (struct xfs_scrub *sc); +int xrep_setup_rtrefcountbt (struct xfs_scrub *sc);/* Repair setup functions */ int xrep_setup_ag_allocbt (struct xfs_scrub *sc);
@@ -158,11 +159,13 @@ int xrep_rtbitmap(struct xfs_scrub *sc);int xrep_rtsummary (struct xfs_scrub *sc);int xrep_rgsuperblock (struct xfs_scrub *sc);int xrep_rtrmapbt (struct xfs_scrub *sc); +int xrep_rtrefcountbt (struct xfs_scrub *sc);#else # define xrep_rtbitmap xrep_notsupported# define xrep_rtsummary xrep_notsupported# define xrep_rgsuperblock xrep_notsupported# define xrep_rtrmapbt xrep_notsupported +# define xrep_rtrefcountbt xrep_notsupported#endif /* CONFIG_XFS_RT */ #ifdef CONFIG_XFS_QUOTA
@@ -236,6 +239,7 @@ xrep_setup_nothing(#define xrep_setup_dirtree xrep_setup_nothing#define xrep_setup_metapath xrep_setup_nothing#define xrep_setup_rtrmapbt xrep_setup_nothing +#define xrep_setup_rtrefcountbt xrep_setup_nothing#define xrep_setup_inode (sc, imap) ((void)0)
@@ -274,6 +278,7 @@ static inline int xrep_setup_symlink(struct xfs_scrub *sc, unsigned int *x)#define xrep_metapath xrep_notsupported#define xrep_rgsuperblock xrep_notsupported#define xrep_rtrmapbt xrep_notsupported +#define xrep_rtrefcountbt xrep_notsupported#endif /* CONFIG_XFS_ONLINE_REPAIR */
fs/xfs/scrub/rtrefcount.c +9 -0
@@ -7,8 +7,10 @@#include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" +#include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" +#include "xfs_trans.h" #include "xfs_btree.h" #include "xfs_rmap.h" #include "xfs_refcount.h"
@@ -21,6 +23,7 @@#include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/btree.h" +#include "scrub/repair.h" /* Set us up with the realtime refcount metadata locked. */ int
@@ -32,6 +35,12 @@ xchk_setup_rtrefcountbt(if (xchk_need_intent_drain (sc))xchk_fsgates_enable (sc,XCHK_FSGATES_DRAIN ); +if (xchk_could_repair (sc)) { + error =xrep_setup_rtrefcountbt (sc); +if (error) +return error; + } + error =xchk_rtgroup_init (sc, sc->sm->sm_agno, &sc->sr);if (error)return error;
fs/xfs/scrub/rtrefcount_repair.c new file +783 -0
783 lines not on this page · raw message
fs/xfs/scrub/scrub.c +1 -1
@@ -472,7 +472,7 @@ static const struct xchk_meta_ops meta_scrub_ops[] = { .setup = xchk_setup_rtrefcountbt, .scrub = xchk_rtrefcountbt, .has = xfs_has_rtreflink, - .repair = xrep_notsupported, + .repair = xrep_rtrefcountbt, }, };
fs/xfs/scrub/trace.h +9 -5
@@ -2116,29 +2116,33 @@ TRACE_EVENT(xrep_ibt_found, )TRACE_EVENT (xrep_refc_found, - TP_PROTO(const struct xfs_perag *pag, + TP_PROTO(const struct xfs_group *xg, const struct xfs_refcount_irec *rec), -TP_ARGS (pag, rec), +TP_ARGS (xg, rec),TP_STRUCT__entry ( __field(dev_t, dev) __field(xfs_agnumber_t, agno) __field(enum xfs_refc_domain, domain) + __field(enum xfs_group_type, type) __field(xfs_agblock_t, startblock) __field(xfs_extlen_t, blockcount)__field (xfs_nlink_t, refcount) ),TP_fast_assign ( - __entry->dev = pag_mount(pag)->m_super->s_dev; - __entry->agno = pag_agno(pag); + __entry->dev = xg->xg_mount->m_super->s_dev; + __entry->agno = xg->xg_gno; + __entry->type = xg->xg_type; __entry->domain = rec->rc_domain; __entry->startblock = rec->rc_startblock; __entry->blockcount = rec->rc_blockcount; __entry->refcount = rec->rc_refcount; ), -TP_printk ("dev %d:%d agno 0x%x dom %s agbno 0x%x fsbcount 0x%x refcount %u" , +TP_printk ("dev %d:%d %sno 0x%x dom %s %sbno 0x%x fsbcount 0x%x refcount %u" ,MAJOR (__entry->dev),MINOR (__entry->dev), +__print_symbolic (__entry->type,XG_TYPE_STRINGS ), __entry->agno,__print_symbolic (__entry->domain,XFS_REFC_DOMAIN_STRINGS ), +__print_symbolic (__entry->type,XG_TYPE_STRINGS ), __entry->startblock, __entry->blockcount, __entry->refcount)
PATCH 40/43 xfs: repair inodes that have a refcount btree in the data fork
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
Plumb knowledge of refcount btrees into the inode core repair code.
--- fs/xfs/scrub/inode_repair.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)
fs/xfs/scrub/inode_repair.c +36 -0
@@ -40,6 +40,7 @@#include "xfs_symlink_remote.h" #include "xfs_rtgroup.h" #include "xfs_rtrmap_btree.h" +#include "xfs_rtrefcount_btree.h" #include "scrub/xfs_scrub.h" #include "scrub/scrub.h" #include "scrub/common.h"
@@ -970,6 +971,34 @@ xrep_dinode_bad_rtrmapbt_fork(return false; } +/* Return true if this refcount-format ifork looks like garbage. */ +STATIC bool +xrep_dinode_bad_rtrefcountbt_fork ( +struct xfs_scrub *sc, +struct xfs_dinode *dip, +unsigned int dfork_size) +{ +struct xfs_rtrefcount_root *dfp; +unsigned int nrecs; +unsigned int level; + +if (dfork_size <sizeof (struct xfs_rtrefcount_root )) +return true; + + dfp =XFS_DFORK_PTR (dip,XFS_DATA_FORK ); + nrecs =be16_to_cpu (dfp->bb_numrecs); + level =be16_to_cpu (dfp->bb_level); + +if (level > sc->mp->m_rtrefc_maxlevels) +return true; +if (xfs_rtrefcount_droot_space_calc (level, nrecs) > dfork_size) +return true; +if (level >0 && nrecs ==0 ) +return true; + +return false; +} +/* Check a metadata-btree fork. */ STATIC bool xrep_dinode_bad_metabt_fork(
@@ -984,6 +1013,8 @@ xrep_dinode_bad_metabt_fork(switch (be16_to_cpu (dip->di_metatype)) {case XFS_METAFILE_RTRMAP :return xrep_dinode_bad_rtrmapbt_fork (sc, dip, dfork_size); +case XFS_METAFILE_RTREFCOUNT : +return xrep_dinode_bad_rtrefcountbt_fork (sc, dip, dfork_size);default :return true; }
@@ -1249,6 +1280,7 @@ xrep_dinode_ensure_forkoff( {struct xfs_bmdr_block *bmdr;struct xfs_rtrmap_root *rmdr; +struct xfs_rtrefcount_root *rcdr;struct xfs_scrub *sc = ri->sc;xfs_extnum_t attr_extents, data_extents;size_t bmdr_minsz =xfs_bmdr_space_calc (1 );
@@ -1361,6 +1393,10 @@ xrep_dinode_ensure_forkoff( rmdr =XFS_DFORK_PTR (dip,XFS_DATA_FORK ); dfork_min =xfs_rtrmap_broot_space (sc->mp, rmdr);break ; +case XFS_METAFILE_RTREFCOUNT : + rcdr =XFS_DFORK_PTR (dip,XFS_DATA_FORK ); + dfork_min =xfs_rtrefcount_broot_space (sc->mp, rcdr); +break ;default : dfork_min =0 ;break ;
PATCH 41/43 xfs: check for shared rt extents when rebuilding rt file's data fork
In reply to Darrick J. WongFrom: Darrick J. Wong <[email protected]>
When we're rebuilding the data fork of a realtime file, we need to cross-reference each mapping with the rt refcount btree to ensure that the reflink flag is set if there are any shared extents found.
--- fs/xfs/scrub/bmap_repair.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-)
fs/xfs/scrub/bmap_repair.c +13 -8
@@ -101,14 +101,21 @@ xrep_bmap_discover_shared( xfs_filblks_t blockcount) {struct xfs_scrub *sc = rb->sc; +struct xfs_btree_cur *cur;xfs_agblock_t agbno;xfs_agblock_t fbno;xfs_extlen_t flen;int error; - agbno =XFS_FSB_TO_AGBNO (sc->mp, startblock); - error =xfs_refcount_find_shared (sc->sa.refc_cur, agbno, blockcount, - &fbno, &flen, false); +if (XFS_IS_REALTIME_INODE (sc->ip)) { + agbno =xfs_rtb_to_rgbno (sc->mp, startblock); + cur = sc->sr.refc_cur; + }else { + agbno =XFS_FSB_TO_AGBNO (sc->mp, startblock); + cur = sc->sa.refc_cur; + } + error =xfs_refcount_find_shared (cur, agbno, blockcount, &fbno, &flen, + false);if (error)return error;
@@ -450,7 +457,9 @@ xrep_bmap_scan_rtgroup(return 0 ; error =xrep_rtgroup_init (sc, rtg, &sc->sr, -XFS_RTGLOCK_RMAP |XFS_RTGLOCK_BITMAP_SHARED ); +XFS_RTGLOCK_RMAP | +XFS_RTGLOCK_REFCOUNT | +XFS_RTGLOCK_BITMAP_SHARED );if (error)return error;
@@ -903,10 +912,6 @@ xrep_bmap_init_reflink_scan(if (whichfork !=XFS_DATA_FORK )return RLS_IRRELEVANT ; -/* cannot share realtime extents */ -if (XFS_IS_REALTIME_INODE (sc->ip)) -return RLS_IRRELEVANT ; -return RLS_UNKNOWN ; }