Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
79ad5761
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
79ad5761
编写于
10月 03, 2016
作者:
D
Dave Chinner
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'xfs-4.9-reflink-prep' into for-next
上级
b036b970
3fd129b6
变更
20
隐藏空白更改
内联
并排
Showing
20 changed file
with
719 addition
and
116 deletion
+719
-116
fs/xfs/Makefile
fs/xfs/Makefile
+1
-0
fs/xfs/libxfs/xfs_ag_resv.c
fs/xfs/libxfs/xfs_ag_resv.c
+325
-0
fs/xfs/libxfs/xfs_ag_resv.h
fs/xfs/libxfs/xfs_ag_resv.h
+35
-0
fs/xfs/libxfs/xfs_alloc.c
fs/xfs/libxfs/xfs_alloc.c
+78
-34
fs/xfs/libxfs/xfs_alloc.h
fs/xfs/libxfs/xfs_alloc.h
+5
-3
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_bmap.c
+4
-2
fs/xfs/libxfs/xfs_btree.c
fs/xfs/libxfs/xfs_btree.c
+53
-6
fs/xfs/libxfs/xfs_btree.h
fs/xfs/libxfs/xfs_btree.h
+10
-18
fs/xfs/libxfs/xfs_defer.c
fs/xfs/libxfs/xfs_defer.c
+72
-7
fs/xfs/libxfs/xfs_ialloc_btree.c
fs/xfs/libxfs/xfs_ialloc_btree.c
+1
-1
fs/xfs/libxfs/xfs_log_format.h
fs/xfs/libxfs/xfs_log_format.h
+9
-1
fs/xfs/xfs_filestream.c
fs/xfs/xfs_filestream.c
+3
-1
fs/xfs/xfs_fsops.c
fs/xfs/xfs_fsops.c
+1
-1
fs/xfs/xfs_mount.h
fs/xfs/xfs_mount.h
+36
-0
fs/xfs/xfs_rmap_item.c
fs/xfs/xfs_rmap_item.c
+9
-27
fs/xfs/xfs_rmap_item.h
fs/xfs/xfs_rmap_item.h
+8
-0
fs/xfs/xfs_super.c
fs/xfs/xfs_super.c
+2
-3
fs/xfs/xfs_trace.h
fs/xfs/xfs_trace.h
+65
-10
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans.c
+0
-1
fs/xfs/xfs_trans_extfree.c
fs/xfs/xfs_trans_extfree.c
+2
-1
未找到文件。
fs/xfs/Makefile
浏览文件 @
79ad5761
...
...
@@ -52,6 +52,7 @@ xfs-y += $(addprefix libxfs/, \
xfs_inode_fork.o
\
xfs_inode_buf.o
\
xfs_log_rlimit.o
\
xfs_ag_resv.o
\
xfs_rmap.o
\
xfs_rmap_btree.o
\
xfs_sb.o
\
...
...
fs/xfs/libxfs/xfs_ag_resv.c
0 → 100644
浏览文件 @
79ad5761
/*
* Copyright (C) 2016 Oracle. All Rights Reserved.
*
* Author: Darrick J. Wong <darrick.wong@oracle.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_shared.h"
#include "xfs_format.h"
#include "xfs_log_format.h"
#include "xfs_trans_resv.h"
#include "xfs_sb.h"
#include "xfs_mount.h"
#include "xfs_defer.h"
#include "xfs_alloc.h"
#include "xfs_error.h"
#include "xfs_trace.h"
#include "xfs_cksum.h"
#include "xfs_trans.h"
#include "xfs_bit.h"
#include "xfs_bmap.h"
#include "xfs_bmap_btree.h"
#include "xfs_ag_resv.h"
#include "xfs_trans_space.h"
#include "xfs_rmap_btree.h"
#include "xfs_btree.h"
/*
* Per-AG Block Reservations
*
* For some kinds of allocation group metadata structures, it is advantageous
* to reserve a small number of blocks in each AG so that future expansions of
* that data structure do not encounter ENOSPC because errors during a btree
* split cause the filesystem to go offline.
*
* Prior to the introduction of reflink, this wasn't an issue because the free
* space btrees maintain a reserve of space (the AGFL) to handle any expansion
* that may be necessary; and allocations of other metadata (inodes, BMBT,
* dir/attr) aren't restricted to a single AG. However, with reflink it is
* possible to allocate all the space in an AG, have subsequent reflink/CoW
* activity expand the refcount btree, and discover that there's no space left
* to handle that expansion. Since we can calculate the maximum size of the
* refcount btree, we can reserve space for it and avoid ENOSPC.
*
* Handling per-AG reservations consists of three changes to the allocator's
* behavior: First, because these reservations are always needed, we decrease
* the ag_max_usable counter to reflect the size of the AG after the reserved
* blocks are taken. Second, the reservations must be reflected in the
* fdblocks count to maintain proper accounting. Third, each AG must maintain
* its own reserved block counter so that we can calculate the amount of space
* that must remain free to maintain the reservations. Fourth, the "remaining
* reserved blocks" count must be used when calculating the length of the
* longest free extent in an AG and to clamp maxlen in the per-AG allocation
* functions. In other words, we maintain a virtual allocation via in-core
* accounting tricks so that we don't have to clean up after a crash. :)
*
* Reserved blocks can be managed by passing one of the enum xfs_ag_resv_type
* values via struct xfs_alloc_arg or directly to the xfs_free_extent
* function. It might seem a little funny to maintain a reservoir of blocks
* to feed another reservoir, but the AGFL only holds enough blocks to get
* through the next transaction. The per-AG reservation is to ensure (we
* hope) that each AG never runs out of blocks. Each data structure wanting
* to use the reservation system should update ask/used in xfs_ag_resv_init.
*/
/*
* Are we critically low on blocks? For now we'll define that as the number
* of blocks we can get our hands on being less than 10% of what we reserved
* or less than some arbitrary number (maximum btree height).
*/
bool
xfs_ag_resv_critical
(
struct
xfs_perag
*
pag
,
enum
xfs_ag_resv_type
type
)
{
xfs_extlen_t
avail
;
xfs_extlen_t
orig
;
switch
(
type
)
{
case
XFS_AG_RESV_METADATA
:
avail
=
pag
->
pagf_freeblks
-
pag
->
pag_agfl_resv
.
ar_reserved
;
orig
=
pag
->
pag_meta_resv
.
ar_asked
;
break
;
case
XFS_AG_RESV_AGFL
:
avail
=
pag
->
pagf_freeblks
+
pag
->
pagf_flcount
-
pag
->
pag_meta_resv
.
ar_reserved
;
orig
=
pag
->
pag_agfl_resv
.
ar_asked
;
break
;
default:
ASSERT
(
0
);
return
false
;
}
trace_xfs_ag_resv_critical
(
pag
,
type
,
avail
);
/* Critically low if less than 10% or max btree height remains. */
return
avail
<
orig
/
10
||
avail
<
XFS_BTREE_MAXLEVELS
;
}
/*
* How many blocks are reserved but not used, and therefore must not be
* allocated away?
*/
xfs_extlen_t
xfs_ag_resv_needed
(
struct
xfs_perag
*
pag
,
enum
xfs_ag_resv_type
type
)
{
xfs_extlen_t
len
;
len
=
pag
->
pag_meta_resv
.
ar_reserved
+
pag
->
pag_agfl_resv
.
ar_reserved
;
switch
(
type
)
{
case
XFS_AG_RESV_METADATA
:
case
XFS_AG_RESV_AGFL
:
len
-=
xfs_perag_resv
(
pag
,
type
)
->
ar_reserved
;
break
;
case
XFS_AG_RESV_NONE
:
/* empty */
break
;
default:
ASSERT
(
0
);
}
trace_xfs_ag_resv_needed
(
pag
,
type
,
len
);
return
len
;
}
/* Clean out a reservation */
static
int
__xfs_ag_resv_free
(
struct
xfs_perag
*
pag
,
enum
xfs_ag_resv_type
type
)
{
struct
xfs_ag_resv
*
resv
;
xfs_extlen_t
oldresv
;
int
error
;
trace_xfs_ag_resv_free
(
pag
,
type
,
0
);
resv
=
xfs_perag_resv
(
pag
,
type
);
pag
->
pag_mount
->
m_ag_max_usable
+=
resv
->
ar_asked
;
/*
* AGFL blocks are always considered "free", so whatever
* was reserved at mount time must be given back at umount.
*/
if
(
type
==
XFS_AG_RESV_AGFL
)
oldresv
=
resv
->
ar_orig_reserved
;
else
oldresv
=
resv
->
ar_reserved
;
error
=
xfs_mod_fdblocks
(
pag
->
pag_mount
,
oldresv
,
true
);
resv
->
ar_reserved
=
0
;
resv
->
ar_asked
=
0
;
if
(
error
)
trace_xfs_ag_resv_free_error
(
pag
->
pag_mount
,
pag
->
pag_agno
,
error
,
_RET_IP_
);
return
error
;
}
/* Free a per-AG reservation. */
int
xfs_ag_resv_free
(
struct
xfs_perag
*
pag
)
{
int
error
;
int
err2
;
error
=
__xfs_ag_resv_free
(
pag
,
XFS_AG_RESV_AGFL
);
err2
=
__xfs_ag_resv_free
(
pag
,
XFS_AG_RESV_METADATA
);
if
(
err2
&&
!
error
)
error
=
err2
;
return
error
;
}
static
int
__xfs_ag_resv_init
(
struct
xfs_perag
*
pag
,
enum
xfs_ag_resv_type
type
,
xfs_extlen_t
ask
,
xfs_extlen_t
used
)
{
struct
xfs_mount
*
mp
=
pag
->
pag_mount
;
struct
xfs_ag_resv
*
resv
;
int
error
;
resv
=
xfs_perag_resv
(
pag
,
type
);
if
(
used
>
ask
)
ask
=
used
;
resv
->
ar_asked
=
ask
;
resv
->
ar_reserved
=
resv
->
ar_orig_reserved
=
ask
-
used
;
mp
->
m_ag_max_usable
-=
ask
;
trace_xfs_ag_resv_init
(
pag
,
type
,
ask
);
error
=
xfs_mod_fdblocks
(
mp
,
-
(
int64_t
)
resv
->
ar_reserved
,
true
);
if
(
error
)
trace_xfs_ag_resv_init_error
(
pag
->
pag_mount
,
pag
->
pag_agno
,
error
,
_RET_IP_
);
return
error
;
}
/* Create a per-AG block reservation. */
int
xfs_ag_resv_init
(
struct
xfs_perag
*
pag
)
{
xfs_extlen_t
ask
;
xfs_extlen_t
used
;
int
error
=
0
;
/* Create the metadata reservation. */
if
(
pag
->
pag_meta_resv
.
ar_asked
==
0
)
{
ask
=
used
=
0
;
error
=
__xfs_ag_resv_init
(
pag
,
XFS_AG_RESV_METADATA
,
ask
,
used
);
if
(
error
)
goto
out
;
}
/* Create the AGFL metadata reservation */
if
(
pag
->
pag_agfl_resv
.
ar_asked
==
0
)
{
ask
=
used
=
0
;
error
=
__xfs_ag_resv_init
(
pag
,
XFS_AG_RESV_AGFL
,
ask
,
used
);
if
(
error
)
goto
out
;
}
out:
return
error
;
}
/* Allocate a block from the reservation. */
void
xfs_ag_resv_alloc_extent
(
struct
xfs_perag
*
pag
,
enum
xfs_ag_resv_type
type
,
struct
xfs_alloc_arg
*
args
)
{
struct
xfs_ag_resv
*
resv
;
xfs_extlen_t
len
;
uint
field
;
trace_xfs_ag_resv_alloc_extent
(
pag
,
type
,
args
->
len
);
switch
(
type
)
{
case
XFS_AG_RESV_METADATA
:
case
XFS_AG_RESV_AGFL
:
resv
=
xfs_perag_resv
(
pag
,
type
);
break
;
default:
ASSERT
(
0
);
/* fall through */
case
XFS_AG_RESV_NONE
:
field
=
args
->
wasdel
?
XFS_TRANS_SB_RES_FDBLOCKS
:
XFS_TRANS_SB_FDBLOCKS
;
xfs_trans_mod_sb
(
args
->
tp
,
field
,
-
(
int64_t
)
args
->
len
);
return
;
}
len
=
min_t
(
xfs_extlen_t
,
args
->
len
,
resv
->
ar_reserved
);
resv
->
ar_reserved
-=
len
;
if
(
type
==
XFS_AG_RESV_AGFL
)
return
;
/* Allocations of reserved blocks only need on-disk sb updates... */
xfs_trans_mod_sb
(
args
->
tp
,
XFS_TRANS_SB_RES_FDBLOCKS
,
-
(
int64_t
)
len
);
/* ...but non-reserved blocks need in-core and on-disk updates. */
if
(
args
->
len
>
len
)
xfs_trans_mod_sb
(
args
->
tp
,
XFS_TRANS_SB_FDBLOCKS
,
-
((
int64_t
)
args
->
len
-
len
));
}
/* Free a block to the reservation. */
void
xfs_ag_resv_free_extent
(
struct
xfs_perag
*
pag
,
enum
xfs_ag_resv_type
type
,
struct
xfs_trans
*
tp
,
xfs_extlen_t
len
)
{
xfs_extlen_t
leftover
;
struct
xfs_ag_resv
*
resv
;
trace_xfs_ag_resv_free_extent
(
pag
,
type
,
len
);
switch
(
type
)
{
case
XFS_AG_RESV_METADATA
:
case
XFS_AG_RESV_AGFL
:
resv
=
xfs_perag_resv
(
pag
,
type
);
break
;
default:
ASSERT
(
0
);
/* fall through */
case
XFS_AG_RESV_NONE
:
xfs_trans_mod_sb
(
tp
,
XFS_TRANS_SB_FDBLOCKS
,
(
int64_t
)
len
);
return
;
}
leftover
=
min_t
(
xfs_extlen_t
,
len
,
resv
->
ar_asked
-
resv
->
ar_reserved
);
resv
->
ar_reserved
+=
leftover
;
if
(
type
==
XFS_AG_RESV_AGFL
)
return
;
/* Freeing into the reserved pool only requires on-disk update... */
xfs_trans_mod_sb
(
tp
,
XFS_TRANS_SB_RES_FDBLOCKS
,
len
);
/* ...but freeing beyond that requires in-core and on-disk update. */
if
(
len
>
leftover
)
xfs_trans_mod_sb
(
tp
,
XFS_TRANS_SB_FDBLOCKS
,
len
-
leftover
);
}
fs/xfs/libxfs/xfs_ag_resv.h
0 → 100644
浏览文件 @
79ad5761
/*
* Copyright (C) 2016 Oracle. All Rights Reserved.
*
* Author: Darrick J. Wong <darrick.wong@oracle.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __XFS_AG_RESV_H__
#define __XFS_AG_RESV_H__
int
xfs_ag_resv_free
(
struct
xfs_perag
*
pag
);
int
xfs_ag_resv_init
(
struct
xfs_perag
*
pag
);
bool
xfs_ag_resv_critical
(
struct
xfs_perag
*
pag
,
enum
xfs_ag_resv_type
type
);
xfs_extlen_t
xfs_ag_resv_needed
(
struct
xfs_perag
*
pag
,
enum
xfs_ag_resv_type
type
);
void
xfs_ag_resv_alloc_extent
(
struct
xfs_perag
*
pag
,
enum
xfs_ag_resv_type
type
,
struct
xfs_alloc_arg
*
args
);
void
xfs_ag_resv_free_extent
(
struct
xfs_perag
*
pag
,
enum
xfs_ag_resv_type
type
,
struct
xfs_trans
*
tp
,
xfs_extlen_t
len
);
#endif
/* __XFS_AG_RESV_H__ */
fs/xfs/libxfs/xfs_alloc.c
浏览文件 @
79ad5761
...
...
@@ -37,6 +37,7 @@
#include "xfs_trans.h"
#include "xfs_buf_item.h"
#include "xfs_log.h"
#include "xfs_ag_resv.h"
struct
workqueue_struct
*
xfs_alloc_wq
;
...
...
@@ -74,14 +75,8 @@ xfs_prealloc_blocks(
* extents need to be actually allocated. To get around this, we explicitly set
* aside a few blocks which will not be reserved in delayed allocation.
*
* When rmap is disabled, we need to reserve 4 fsbs _per AG_ for the freelist
* and 4 more to handle a potential split of the file's bmap btree.
*
* When rmap is enabled, we must also be able to handle two rmap btree inserts
* to record both the file data extent and a new bmbt block. The bmbt block
* might not be in the same AG as the file data extent. In the worst case
* the bmap btree splits multiple levels and all the new blocks come from
* different AGs, so set aside enough to handle rmap btree splits in all AGs.
* We need to reserve 4 fsbs _per AG_ for the freelist and 4 more to handle a
* potential split of the file's bmap btree.
*/
unsigned
int
xfs_alloc_set_aside
(
...
...
@@ -90,8 +85,6 @@ xfs_alloc_set_aside(
unsigned
int
blocks
;
blocks
=
4
+
(
mp
->
m_sb
.
sb_agcount
*
XFS_ALLOC_AGFL_RESERVE
);
if
(
xfs_sb_version_hasrmapbt
(
&
mp
->
m_sb
))
blocks
+=
mp
->
m_sb
.
sb_agcount
*
mp
->
m_rmap_maxlevels
;
return
blocks
;
}
...
...
@@ -680,12 +673,29 @@ xfs_alloc_ag_vextent(
xfs_alloc_arg_t
*
args
)
/* argument structure for allocation */
{
int
error
=
0
;
xfs_extlen_t
reservation
;
xfs_extlen_t
oldmax
;
ASSERT
(
args
->
minlen
>
0
);
ASSERT
(
args
->
maxlen
>
0
);
ASSERT
(
args
->
minlen
<=
args
->
maxlen
);
ASSERT
(
args
->
mod
<
args
->
prod
);
ASSERT
(
args
->
alignment
>
0
);
/*
* Clamp maxlen to the amount of free space minus any reservations
* that have been made.
*/
oldmax
=
args
->
maxlen
;
reservation
=
xfs_ag_resv_needed
(
args
->
pag
,
args
->
resv
);
if
(
args
->
maxlen
>
args
->
pag
->
pagf_freeblks
-
reservation
)
args
->
maxlen
=
args
->
pag
->
pagf_freeblks
-
reservation
;
if
(
args
->
maxlen
==
0
)
{
args
->
agbno
=
NULLAGBLOCK
;
args
->
maxlen
=
oldmax
;
return
0
;
}
/*
* Branch to correct routine based on the type.
*/
...
...
@@ -705,12 +715,14 @@ xfs_alloc_ag_vextent(
/* NOTREACHED */
}
args
->
maxlen
=
oldmax
;
if
(
error
||
args
->
agbno
==
NULLAGBLOCK
)
return
error
;
ASSERT
(
args
->
len
>=
args
->
minlen
);
ASSERT
(
args
->
len
<=
args
->
maxlen
);
ASSERT
(
!
args
->
wasfromfl
||
!
args
->
isfl
);
ASSERT
(
!
args
->
wasfromfl
||
args
->
resv
!=
XFS_AG_RESV_AGFL
);
ASSERT
(
args
->
agbno
%
args
->
alignment
==
0
);
/* if not file data, insert new block into the reverse map btree */
...
...
@@ -732,12 +744,7 @@ xfs_alloc_ag_vextent(
args
->
agbno
,
args
->
len
));
}
if
(
!
args
->
isfl
)
{
xfs_trans_mod_sb
(
args
->
tp
,
args
->
wasdel
?
XFS_TRANS_SB_RES_FDBLOCKS
:
XFS_TRANS_SB_FDBLOCKS
,
-
((
long
)(
args
->
len
)));
}
xfs_ag_resv_alloc_extent
(
args
->
pag
,
args
->
resv
,
args
);
XFS_STATS_INC
(
args
->
mp
,
xs_allocx
);
XFS_STATS_ADD
(
args
->
mp
,
xs_allocb
,
args
->
len
);
...
...
@@ -1583,6 +1590,7 @@ xfs_alloc_ag_vextent_small(
int
*
stat
)
/* status: 0-freelist, 1-normal/none */
{
struct
xfs_owner_info
oinfo
;
struct
xfs_perag
*
pag
;
int
error
;
xfs_agblock_t
fbno
;
xfs_extlen_t
flen
;
...
...
@@ -1600,7 +1608,8 @@ xfs_alloc_ag_vextent_small(
* to respect minleft even when pulling from the
* freelist.
*/
else
if
(
args
->
minlen
==
1
&&
args
->
alignment
==
1
&&
!
args
->
isfl
&&
else
if
(
args
->
minlen
==
1
&&
args
->
alignment
==
1
&&
args
->
resv
!=
XFS_AG_RESV_AGFL
&&
(
be32_to_cpu
(
XFS_BUF_TO_AGF
(
args
->
agbp
)
->
agf_flcount
)
>
args
->
minleft
))
{
error
=
xfs_alloc_get_freelist
(
args
->
tp
,
args
->
agbp
,
&
fbno
,
0
);
...
...
@@ -1629,13 +1638,18 @@ xfs_alloc_ag_vextent_small(
/*
* If we're feeding an AGFL block to something that
* doesn't live in the free space, we need to clear
* out the OWN_AG rmap.
* out the OWN_AG rmap and add the block back to
* the AGFL per-AG reservation.
*/
xfs_rmap_ag_owner
(
&
oinfo
,
XFS_RMAP_OWN_AG
);
error
=
xfs_rmap_free
(
args
->
tp
,
args
->
agbp
,
args
->
agno
,
fbno
,
1
,
&
oinfo
);
if
(
error
)
goto
error0
;
pag
=
xfs_perag_get
(
args
->
mp
,
args
->
agno
);
xfs_ag_resv_free_extent
(
pag
,
XFS_AG_RESV_AGFL
,
args
->
tp
,
1
);
xfs_perag_put
(
pag
);
*
stat
=
0
;
return
0
;
...
...
@@ -1683,7 +1697,7 @@ xfs_free_ag_extent(
xfs_agblock_t
bno
,
xfs_extlen_t
len
,
struct
xfs_owner_info
*
oinfo
,
int
isfl
)
enum
xfs_ag_resv_type
type
)
{
xfs_btree_cur_t
*
bno_cur
;
/* cursor for by-block btree */
xfs_btree_cur_t
*
cnt_cur
;
/* cursor for by-size btree */
...
...
@@ -1911,21 +1925,22 @@ xfs_free_ag_extent(
*/
pag
=
xfs_perag_get
(
mp
,
agno
);
error
=
xfs_alloc_update_counters
(
tp
,
pag
,
agbp
,
len
);
xfs_ag_resv_free_extent
(
pag
,
type
,
tp
,
len
);
xfs_perag_put
(
pag
);
if
(
error
)
goto
error0
;
if
(
!
isfl
)
xfs_trans_mod_sb
(
tp
,
XFS_TRANS_SB_FDBLOCKS
,
(
long
)
len
);
XFS_STATS_INC
(
mp
,
xs_freex
);
XFS_STATS_ADD
(
mp
,
xs_freeb
,
len
);
trace_xfs_free_extent
(
mp
,
agno
,
bno
,
len
,
isfl
,
haveleft
,
haveright
);
trace_xfs_free_extent
(
mp
,
agno
,
bno
,
len
,
type
==
XFS_AG_RESV_AGFL
,
haveleft
,
haveright
);
return
0
;
error0:
trace_xfs_free_extent
(
mp
,
agno
,
bno
,
len
,
isfl
,
-
1
,
-
1
);
trace_xfs_free_extent
(
mp
,
agno
,
bno
,
len
,
type
==
XFS_AG_RESV_AGFL
,
-
1
,
-
1
);
if
(
bno_cur
)
xfs_btree_del_cursor
(
bno_cur
,
XFS_BTREE_ERROR
);
if
(
cnt_cur
)
...
...
@@ -1950,21 +1965,43 @@ xfs_alloc_compute_maxlevels(
}
/*
* Find the length of the longest extent in an AG.
* Find the length of the longest extent in an AG. The 'need' parameter
* specifies how much space we're going to need for the AGFL and the
* 'reserved' parameter tells us how many blocks in this AG are reserved for
* other callers.
*/
xfs_extlen_t
xfs_alloc_longest_free_extent
(
struct
xfs_mount
*
mp
,
struct
xfs_perag
*
pag
,
xfs_extlen_t
need
)
xfs_extlen_t
need
,
xfs_extlen_t
reserved
)
{
xfs_extlen_t
delta
=
0
;
/*
* If the AGFL needs a recharge, we'll have to subtract that from the
* longest extent.
*/
if
(
need
>
pag
->
pagf_flcount
)
delta
=
need
-
pag
->
pagf_flcount
;
/*
* If we cannot maintain others' reservations with space from the
* not-longest freesp extents, we'll have to subtract /that/ from
* the longest extent too.
*/
if
(
pag
->
pagf_freeblks
-
pag
->
pagf_longest
<
reserved
)
delta
+=
reserved
-
(
pag
->
pagf_freeblks
-
pag
->
pagf_longest
);
/*
* If the longest extent is long enough to satisfy all the
* reservations and AGFL rules in place, we can return this extent.
*/
if
(
pag
->
pagf_longest
>
delta
)
return
pag
->
pagf_longest
-
delta
;
/* Otherwise, let the caller try for 1 block if there's space. */
return
pag
->
pagf_flcount
>
0
||
pag
->
pagf_longest
>
0
;
}
...
...
@@ -2004,20 +2041,24 @@ xfs_alloc_space_available(
{
struct
xfs_perag
*
pag
=
args
->
pag
;
xfs_extlen_t
longest
;
xfs_extlen_t
reservation
;
/* blocks that are still reserved */
int
available
;
if
(
flags
&
XFS_ALLOC_FLAG_FREEING
)
return
true
;
reservation
=
xfs_ag_resv_needed
(
pag
,
args
->
resv
);
/* do we have enough contiguous free space for the allocation? */
longest
=
xfs_alloc_longest_free_extent
(
args
->
mp
,
pag
,
min_free
);
longest
=
xfs_alloc_longest_free_extent
(
args
->
mp
,
pag
,
min_free
,
reservation
);
if
((
args
->
minlen
+
args
->
alignment
+
args
->
minalignslop
-
1
)
>
longest
)
return
false
;
/* do have enough free space remaining for the allocation? */
/* do
we
have enough free space remaining for the allocation? */
available
=
(
int
)(
pag
->
pagf_freeblks
+
pag
->
pagf_flcount
-
min_free
-
args
->
total
);
if
(
available
<
(
int
)
args
->
minleft
)
reservation
-
min_free
-
args
->
total
);
if
(
available
<
(
int
)
args
->
minleft
||
available
<=
0
)
return
false
;
return
true
;
...
...
@@ -2124,7 +2165,7 @@ xfs_alloc_fix_freelist(
if
(
error
)
goto
out_agbp_relse
;
error
=
xfs_free_ag_extent
(
tp
,
agbp
,
args
->
agno
,
bno
,
1
,
&
targs
.
oinfo
,
1
);
&
targs
.
oinfo
,
XFS_AG_RESV_AGFL
);
if
(
error
)
goto
out_agbp_relse
;
bp
=
xfs_btree_get_bufs
(
mp
,
tp
,
args
->
agno
,
bno
,
0
);
...
...
@@ -2135,7 +2176,7 @@ xfs_alloc_fix_freelist(
targs
.
mp
=
mp
;
targs
.
agbp
=
agbp
;
targs
.
agno
=
args
->
agno
;
targs
.
alignment
=
targs
.
minlen
=
targs
.
prod
=
targs
.
isfl
=
1
;
targs
.
alignment
=
targs
.
minlen
=
targs
.
prod
=
1
;
targs
.
type
=
XFS_ALLOCTYPE_THIS_AG
;
targs
.
pag
=
pag
;
error
=
xfs_alloc_read_agfl
(
mp
,
tp
,
targs
.
agno
,
&
agflbp
);
...
...
@@ -2146,6 +2187,7 @@ xfs_alloc_fix_freelist(
while
(
pag
->
pagf_flcount
<
need
)
{
targs
.
agbno
=
0
;
targs
.
maxlen
=
need
-
pag
->
pagf_flcount
;
targs
.
resv
=
XFS_AG_RESV_AGFL
;
/* Allocate as many blocks as possible at once. */
error
=
xfs_alloc_ag_vextent
(
&
targs
);
...
...
@@ -2825,7 +2867,8 @@ xfs_free_extent(
struct
xfs_trans
*
tp
,
/* transaction pointer */
xfs_fsblock_t
bno
,
/* starting block number of extent */
xfs_extlen_t
len
,
/* length of extent */
struct
xfs_owner_info
*
oinfo
)
/* extent owner */
struct
xfs_owner_info
*
oinfo
,
/* extent owner */
enum
xfs_ag_resv_type
type
)
/* block reservation type */
{
struct
xfs_mount
*
mp
=
tp
->
t_mountp
;
struct
xfs_buf
*
agbp
;
...
...
@@ -2834,6 +2877,7 @@ xfs_free_extent(
int
error
;
ASSERT
(
len
!=
0
);
ASSERT
(
type
!=
XFS_AG_RESV_AGFL
);
if
(
XFS_TEST_ERROR
(
false
,
mp
,
XFS_ERRTAG_FREE_EXTENT
,
...
...
@@ -2851,7 +2895,7 @@ xfs_free_extent(
agbno
+
len
<=
be32_to_cpu
(
XFS_BUF_TO_AGF
(
agbp
)
->
agf_length
),
err
);
error
=
xfs_free_ag_extent
(
tp
,
agbp
,
agno
,
agbno
,
len
,
oinfo
,
0
);
error
=
xfs_free_ag_extent
(
tp
,
agbp
,
agno
,
agbno
,
len
,
oinfo
,
type
);
if
(
error
)
goto
err
;
...
...
fs/xfs/libxfs/xfs_alloc.h
浏览文件 @
79ad5761
...
...
@@ -87,10 +87,10 @@ typedef struct xfs_alloc_arg {
xfs_alloctype_t
otype
;
/* original allocation type */
char
wasdel
;
/* set if allocation was prev delayed */
char
wasfromfl
;
/* set if allocation is from freelist */
char
isfl
;
/* set if is freelist blocks - !acctg */
char
userdata
;
/* mask defining userdata treatment */
xfs_fsblock_t
firstblock
;
/* io first block allocated */
struct
xfs_owner_info
oinfo
;
/* owner of blocks being allocated */
enum
xfs_ag_resv_type
resv
;
/* block reservation to use */
}
xfs_alloc_arg_t
;
/*
...
...
@@ -106,7 +106,8 @@ unsigned int xfs_alloc_set_aside(struct xfs_mount *mp);
unsigned
int
xfs_alloc_ag_max_usable
(
struct
xfs_mount
*
mp
);
xfs_extlen_t
xfs_alloc_longest_free_extent
(
struct
xfs_mount
*
mp
,
struct
xfs_perag
*
pag
,
xfs_extlen_t
need
);
struct
xfs_perag
*
pag
,
xfs_extlen_t
need
,
xfs_extlen_t
reserved
);
unsigned
int
xfs_alloc_min_freelist
(
struct
xfs_mount
*
mp
,
struct
xfs_perag
*
pag
);
...
...
@@ -184,7 +185,8 @@ xfs_free_extent(
struct
xfs_trans
*
tp
,
/* transaction pointer */
xfs_fsblock_t
bno
,
/* starting block number of extent */
xfs_extlen_t
len
,
/* length of extent */
struct
xfs_owner_info
*
oinfo
);
/* extent owner */
struct
xfs_owner_info
*
oinfo
,
/* extent owner */
enum
xfs_ag_resv_type
type
);
/* block reservation type */
int
/* error */
xfs_alloc_lookup_ge
(
...
...
fs/xfs/libxfs/xfs_bmap.c
浏览文件 @
79ad5761
...
...
@@ -47,6 +47,7 @@
#include "xfs_attr_leaf.h"
#include "xfs_filestream.h"
#include "xfs_rmap.h"
#include "xfs_ag_resv.h"
kmem_zone_t
*
xfs_bmap_free_item_zone
;
...
...
@@ -3501,7 +3502,8 @@ xfs_bmap_longest_free_extent(
}
longest
=
xfs_alloc_longest_free_extent
(
mp
,
pag
,
xfs_alloc_min_freelist
(
mp
,
pag
));
xfs_alloc_min_freelist
(
mp
,
pag
),
xfs_ag_resv_needed
(
pag
,
XFS_AG_RESV_NONE
));
if
(
*
blen
<
longest
)
*
blen
=
longest
;
...
...
@@ -3781,7 +3783,7 @@ xfs_bmap_btalloc(
}
args
.
minleft
=
ap
->
minleft
;
args
.
wasdel
=
ap
->
wasdel
;
args
.
isfl
=
0
;
args
.
resv
=
XFS_AG_RESV_NONE
;
args
.
userdata
=
ap
->
userdata
;
if
(
ap
->
userdata
&
XFS_ALLOC_USERDATA_ZERO
)
args
.
ip
=
ap
->
ip
;
...
...
fs/xfs/libxfs/xfs_btree.c
浏览文件 @
79ad5761
...
...
@@ -2070,7 +2070,7 @@ __xfs_btree_updkeys(
struct
xfs_buf
*
bp0
,
bool
force_all
)
{
union
xfs_btree_
big
key
key
;
/* keys from current level */
union
xfs_btree_key
key
;
/* keys from current level */
union
xfs_btree_key
*
lkey
;
/* keys from the next level up */
union
xfs_btree_key
*
hkey
;
union
xfs_btree_key
*
nlkey
;
/* keys from the next level up */
...
...
@@ -2086,7 +2086,7 @@ __xfs_btree_updkeys(
trace_xfs_btree_updkeys
(
cur
,
level
,
bp0
);
lkey
=
(
union
xfs_btree_key
*
)
&
key
;
lkey
=
&
key
;
hkey
=
xfs_btree_high_key_from_key
(
cur
,
lkey
);
xfs_btree_get_keys
(
cur
,
block
,
lkey
);
for
(
level
++
;
level
<
cur
->
bc_nlevels
;
level
++
)
{
...
...
@@ -3226,7 +3226,7 @@ xfs_btree_insrec(
struct
xfs_buf
*
bp
;
/* buffer for block */
union
xfs_btree_ptr
nptr
;
/* new block ptr */
struct
xfs_btree_cur
*
ncur
;
/* new btree cursor */
union
xfs_btree_
big
key
nkey
;
/* new block key */
union
xfs_btree_key
nkey
;
/* new block key */
union
xfs_btree_key
*
lkey
;
int
optr
;
/* old key/record index */
int
ptr
;
/* key/record index */
...
...
@@ -3241,7 +3241,7 @@ xfs_btree_insrec(
XFS_BTREE_TRACE_ARGIPR
(
cur
,
level
,
*
ptrp
,
&
rec
);
ncur
=
NULL
;
lkey
=
(
union
xfs_btree_key
*
)
&
nkey
;
lkey
=
&
nkey
;
/*
* If we have an external root pointer, and we've made it to the
...
...
@@ -3444,14 +3444,14 @@ xfs_btree_insert(
union
xfs_btree_ptr
nptr
;
/* new block number (split result) */
struct
xfs_btree_cur
*
ncur
;
/* new cursor (split result) */
struct
xfs_btree_cur
*
pcur
;
/* previous level's cursor */
union
xfs_btree_
big
key
bkey
;
/* key of block to insert */
union
xfs_btree_key
bkey
;
/* key of block to insert */
union
xfs_btree_key
*
key
;
union
xfs_btree_rec
rec
;
/* record to insert */
level
=
0
;
ncur
=
NULL
;
pcur
=
cur
;
key
=
(
union
xfs_btree_key
*
)
&
bkey
;
key
=
&
bkey
;
xfs_btree_set_ptr_null
(
cur
,
&
nptr
);
...
...
@@ -4797,3 +4797,50 @@ xfs_btree_query_range(
return
xfs_btree_overlapped_query_range
(
cur
,
&
low_key
,
&
high_key
,
fn
,
priv
);
}
/*
* Calculate the number of blocks needed to store a given number of records
* in a short-format (per-AG metadata) btree.
*/
xfs_extlen_t
xfs_btree_calc_size
(
struct
xfs_mount
*
mp
,
uint
*
limits
,
unsigned
long
long
len
)
{
int
level
;
int
maxrecs
;
xfs_extlen_t
rval
;
maxrecs
=
limits
[
0
];
for
(
level
=
0
,
rval
=
0
;
len
>
1
;
level
++
)
{
len
+=
maxrecs
-
1
;
do_div
(
len
,
maxrecs
);
maxrecs
=
limits
[
1
];
rval
+=
len
;
}
return
rval
;
}
int
xfs_btree_count_blocks_helper
(
struct
xfs_btree_cur
*
cur
,
int
level
,
void
*
data
)
{
xfs_extlen_t
*
blocks
=
data
;
(
*
blocks
)
++
;
return
0
;
}
/* Count the blocks in a btree and return the result in *blocks. */
int
xfs_btree_count_blocks
(
struct
xfs_btree_cur
*
cur
,
xfs_extlen_t
*
blocks
)
{
*
blocks
=
0
;
return
xfs_btree_visit_blocks
(
cur
,
xfs_btree_count_blocks_helper
,
blocks
);
}
fs/xfs/libxfs/xfs_btree.h
浏览文件 @
79ad5761
...
...
@@ -37,30 +37,18 @@ union xfs_btree_ptr {
__be64
l
;
/* long form ptr */
};
union
xfs_btree_key
{
struct
xfs_bmbt_key
bmbt
;
xfs_bmdr_key_t
bmbr
;
/* bmbt root block */
xfs_alloc_key_t
alloc
;
struct
xfs_inobt_key
inobt
;
struct
xfs_rmap_key
rmap
;
};
/*
* In-core key that holds both low and high keys for overlapped btrees.
* The two keys are packed next to each other on disk, so do the same
* in memory. Preserve the existing xfs_btree_key as a single key to
* avoid the mental model breakage that would happen if we passed a
* bigkey into a function that operates on a single key.
* The in-core btree key. Overlapping btrees actually store two keys
* per pointer, so we reserve enough memory to hold both. The __*bigkey
* items should never be accessed directly.
*/
union
xfs_btree_
big
key
{
union
xfs_btree_key
{
struct
xfs_bmbt_key
bmbt
;
xfs_bmdr_key_t
bmbr
;
/* bmbt root block */
xfs_alloc_key_t
alloc
;
struct
xfs_inobt_key
inobt
;
struct
{
struct
xfs_rmap_key
rmap
;
struct
xfs_rmap_key
rmap_hi
;
};
struct
xfs_rmap_key
rmap
;
struct
xfs_rmap_key
__rmap_bigkey
[
2
];
};
union
xfs_btree_rec
{
...
...
@@ -513,6 +501,8 @@ bool xfs_btree_sblock_v5hdr_verify(struct xfs_buf *bp);
bool
xfs_btree_sblock_verify
(
struct
xfs_buf
*
bp
,
unsigned
int
max_recs
);
uint
xfs_btree_compute_maxlevels
(
struct
xfs_mount
*
mp
,
uint
*
limits
,
unsigned
long
len
);
xfs_extlen_t
xfs_btree_calc_size
(
struct
xfs_mount
*
mp
,
uint
*
limits
,
unsigned
long
long
len
);
/* return codes */
#define XFS_BTREE_QUERY_RANGE_CONTINUE 0
/* keep iterating */
...
...
@@ -529,4 +519,6 @@ typedef int (*xfs_btree_visit_blocks_fn)(struct xfs_btree_cur *cur, int level,
int
xfs_btree_visit_blocks
(
struct
xfs_btree_cur
*
cur
,
xfs_btree_visit_blocks_fn
fn
,
void
*
data
);
int
xfs_btree_count_blocks
(
struct
xfs_btree_cur
*
cur
,
xfs_extlen_t
*
blocks
);
#endif
/* __XFS_BTREE_H__ */
fs/xfs/libxfs/xfs_defer.c
浏览文件 @
79ad5761
...
...
@@ -81,6 +81,10 @@
* - For each work item attached to the log intent item,
* * Perform the described action.
* * Attach the work item to the log done item.
* * If the result of doing the work was -EAGAIN, ->finish work
* wants a new transaction. See the "Requesting a Fresh
* Transaction while Finishing Deferred Work" section below for
* details.
*
* The key here is that we must log an intent item for all pending
* work items every time we roll the transaction, and that we must log
...
...
@@ -88,6 +92,34 @@
* we can perform complex remapping operations, chaining intent items
* as needed.
*
* Requesting a Fresh Transaction while Finishing Deferred Work
*
* If ->finish_item decides that it needs a fresh transaction to
* finish the work, it must ask its caller (xfs_defer_finish) for a
* continuation. The most likely cause of this circumstance are the
* refcount adjust functions deciding that they've logged enough items
* to be at risk of exceeding the transaction reservation.
*
* To get a fresh transaction, we want to log the existing log done
* item to prevent the log intent item from replaying, immediately log
* a new log intent item with the unfinished work items, roll the
* transaction, and re-call ->finish_item wherever it left off. The
* log done item and the new log intent item must be in the same
* transaction or atomicity cannot be guaranteed; defer_finish ensures
* that this happens.
*
* This requires some coordination between ->finish_item and
* defer_finish. Upon deciding to request a new transaction,
* ->finish_item should update the current work item to reflect the
* unfinished work. Next, it should reset the log done item's list
* count to the number of items finished, and return -EAGAIN.
* defer_finish sees the -EAGAIN, logs the new log intent item
* with the remaining work items, and leaves the xfs_defer_pending
* item at the head of the dop_work queue. Then it rolls the
* transaction and picks up processing where it left off. It is
* required that ->finish_item must be careful to leave enough
* transaction reservation to fit the new log intent item.
*
* This is an example of remapping the extent (E, E+B) into file X at
* offset A and dealing with the extent (C, C+B) already being mapped
* there:
...
...
@@ -104,21 +136,26 @@
* | Intent to add rmap (X, E, A, B) |
* +-------------------------------------------------+
* | Reduce refcount for extent (C, B) | t2
* | Done reducing refcount for extent (C, B) |
* | Done reducing refcount for extent (C, 9) |
* | Intent to reduce refcount for extent (C+9, B-9) |
* | (ran out of space after 9 refcount updates) |
* +-------------------------------------------------+
* | Reduce refcount for extent (C+9, B+9) | t3
* | Done reducing refcount for extent (C+9, B-9) |
* | Increase refcount for extent (E, B) |
* | Done increasing refcount for extent (E, B) |
* | Intent to free extent (C, B) |
* | Intent to free extent (F, 1) (refcountbt block) |
* | Intent to remove rmap (F, 1, REFC) |
* +-------------------------------------------------+
* | Remove rmap (X, C, A, B) | t
3
* | Remove rmap (X, C, A, B) | t
4
* | Done removing rmap (X, C, A, B) |
* | Add rmap (X, E, A, B) |
* | Done adding rmap (X, E, A, B) |
* | Remove rmap (F, 1, REFC) |
* | Done removing rmap (F, 1, REFC) |
* +-------------------------------------------------+
* | Free extent (C, B) | t
4
* | Free extent (C, B) | t
5
* | Done freeing extent (C, B) |
* | Free extent (D, 1) |
* | Done freeing extent (D, 1) |
...
...
@@ -141,6 +178,9 @@
* - Intent to free extent (C, B)
* - Intent to free extent (F, 1) (refcountbt block)
* - Intent to remove rmap (F, 1, REFC)
*
* Note that the continuation requested between t2 and t3 is likely to
* reoccur.
*/
static
const
struct
xfs_defer_op_type
*
defer_op_types
[
XFS_DEFER_OPS_TYPE_MAX
];
...
...
@@ -323,7 +363,16 @@ xfs_defer_finish(
dfp
->
dfp_count
--
;
error
=
dfp
->
dfp_type
->
finish_item
(
*
tp
,
dop
,
li
,
dfp
->
dfp_done
,
&
state
);
if
(
error
)
{
if
(
error
==
-
EAGAIN
)
{
/*
* Caller wants a fresh transaction;
* put the work item back on the list
* and jump out.
*/
list_add
(
li
,
&
dfp
->
dfp_work
);
dfp
->
dfp_count
++
;
break
;
}
else
if
(
error
)
{
/*
* Clean up after ourselves and jump out.
* xfs_defer_cancel will take care of freeing
...
...
@@ -335,9 +384,25 @@ xfs_defer_finish(
goto
out
;
}
}
/* Done with the dfp, free it. */
list_del
(
&
dfp
->
dfp_list
);
kmem_free
(
dfp
);
if
(
error
==
-
EAGAIN
)
{
/*
* Caller wants a fresh transaction, so log a
* new log intent item to replace the old one
* and roll the transaction. See "Requesting
* a Fresh Transaction while Finishing
* Deferred Work" above.
*/
dfp
->
dfp_intent
=
dfp
->
dfp_type
->
create_intent
(
*
tp
,
dfp
->
dfp_count
);
dfp
->
dfp_done
=
NULL
;
list_for_each
(
li
,
&
dfp
->
dfp_work
)
dfp
->
dfp_type
->
log_item
(
*
tp
,
dfp
->
dfp_intent
,
li
);
}
else
{
/* Done with the dfp, free it. */
list_del
(
&
dfp
->
dfp_list
);
kmem_free
(
dfp
);
}
if
(
cleanup_fn
)
cleanup_fn
(
*
tp
,
state
,
error
);
...
...
fs/xfs/libxfs/xfs_ialloc_btree.c
浏览文件 @
79ad5761
...
...
@@ -132,7 +132,7 @@ xfs_inobt_free_block(
xfs_rmap_ag_owner
(
&
oinfo
,
XFS_RMAP_OWN_INOBT
);
return
xfs_free_extent
(
cur
->
bc_tp
,
XFS_DADDR_TO_FSB
(
cur
->
bc_mp
,
XFS_BUF_ADDR
(
bp
)),
1
,
&
oinfo
);
&
oinfo
,
XFS_AG_RESV_NONE
);
}
STATIC
int
...
...
fs/xfs/libxfs/xfs_log_format.h
浏览文件 @
79ad5761
...
...
@@ -647,9 +647,17 @@ struct xfs_rui_log_format {
__uint16_t
rui_size
;
/* size of this item */
__uint32_t
rui_nextents
;
/* # extents to free */
__uint64_t
rui_id
;
/* rui identifier */
struct
xfs_map_extent
rui_extents
[
1
];
/* array of extents to rmap */
struct
xfs_map_extent
rui_extents
[];
/* array of extents to rmap */
};
static
inline
size_t
xfs_rui_log_format_sizeof
(
unsigned
int
nr
)
{
return
sizeof
(
struct
xfs_rui_log_format
)
+
nr
*
sizeof
(
struct
xfs_map_extent
);
}
/*
* This is the structure used to lay out an rud log item in the
* log. The rud_extents array is a variable size array whose
...
...
fs/xfs/xfs_filestream.c
浏览文件 @
79ad5761
...
...
@@ -30,6 +30,7 @@
#include "xfs_mru_cache.h"
#include "xfs_filestream.h"
#include "xfs_trace.h"
#include "xfs_ag_resv.h"
struct
xfs_fstrm_item
{
struct
xfs_mru_cache_elem
mru
;
...
...
@@ -198,7 +199,8 @@ xfs_filestream_pick_ag(
}
longest
=
xfs_alloc_longest_free_extent
(
mp
,
pag
,
xfs_alloc_min_freelist
(
mp
,
pag
));
xfs_alloc_min_freelist
(
mp
,
pag
),
xfs_ag_resv_needed
(
pag
,
XFS_AG_RESV_NONE
));
if
(((
minlen
&&
longest
>=
minlen
)
||
(
!
minlen
&&
pag
->
pagf_freeblks
>=
minfree
))
&&
(
!
pag
->
pagf_metadata
||
!
(
flags
&
XFS_PICK_USERDATA
)
||
...
...
fs/xfs/xfs_fsops.c
浏览文件 @
79ad5761
...
...
@@ -553,7 +553,7 @@ xfs_growfs_data_private(
error
=
xfs_free_extent
(
tp
,
XFS_AGB_TO_FSB
(
mp
,
agno
,
be32_to_cpu
(
agf
->
agf_length
)
-
new
),
new
,
&
oinfo
);
new
,
&
oinfo
,
XFS_AG_RESV_NONE
);
if
(
error
)
goto
error0
;
}
...
...
fs/xfs/xfs_mount.h
浏览文件 @
79ad5761
...
...
@@ -331,6 +331,22 @@ xfs_mp_fail_writes(struct xfs_mount *mp)
}
#endif
/* per-AG block reservation data structures*/
enum
xfs_ag_resv_type
{
XFS_AG_RESV_NONE
=
0
,
XFS_AG_RESV_METADATA
,
XFS_AG_RESV_AGFL
,
};
struct
xfs_ag_resv
{
/* number of blocks originally reserved here */
xfs_extlen_t
ar_orig_reserved
;
/* number of blocks reserved here */
xfs_extlen_t
ar_reserved
;
/* number of blocks originally asked for */
xfs_extlen_t
ar_asked
;
};
/*
* Per-ag incore structure, copies of information in agf and agi, to improve the
* performance of allocation group selection.
...
...
@@ -378,8 +394,28 @@ typedef struct xfs_perag {
/* for rcu-safe freeing */
struct
rcu_head
rcu_head
;
int
pagb_count
;
/* pagb slots in use */
/* Blocks reserved for all kinds of metadata. */
struct
xfs_ag_resv
pag_meta_resv
;
/* Blocks reserved for just AGFL-based metadata. */
struct
xfs_ag_resv
pag_agfl_resv
;
}
xfs_perag_t
;
static
inline
struct
xfs_ag_resv
*
xfs_perag_resv
(
struct
xfs_perag
*
pag
,
enum
xfs_ag_resv_type
type
)
{
switch
(
type
)
{
case
XFS_AG_RESV_METADATA
:
return
&
pag
->
pag_meta_resv
;
case
XFS_AG_RESV_AGFL
:
return
&
pag
->
pag_agfl_resv
;
default:
return
NULL
;
}
}
extern
void
xfs_uuid_table_free
(
void
);
extern
int
xfs_log_sbcount
(
xfs_mount_t
*
);
extern
__uint64_t
xfs_default_resblks
(
xfs_mount_t
*
mp
);
...
...
fs/xfs/xfs_rmap_item.c
浏览文件 @
79ad5761
...
...
@@ -51,28 +51,16 @@ xfs_rui_item_free(
kmem_zone_free
(
xfs_rui_zone
,
ruip
);
}
/*
* This returns the number of iovecs needed to log the given rui item.
* We only need 1 iovec for an rui item. It just logs the rui_log_format
* structure.
*/
static
inline
int
xfs_rui_item_sizeof
(
struct
xfs_rui_log_item
*
ruip
)
{
return
sizeof
(
struct
xfs_rui_log_format
)
+
(
ruip
->
rui_format
.
rui_nextents
-
1
)
*
sizeof
(
struct
xfs_map_extent
);
}
STATIC
void
xfs_rui_item_size
(
struct
xfs_log_item
*
lip
,
int
*
nvecs
,
int
*
nbytes
)
{
struct
xfs_rui_log_item
*
ruip
=
RUI_ITEM
(
lip
);
*
nvecs
+=
1
;
*
nbytes
+=
xfs_rui_
item_sizeof
(
RUI_ITEM
(
lip
)
);
*
nbytes
+=
xfs_rui_
log_format_sizeof
(
ruip
->
rui_format
.
rui_nextents
);
}
/*
...
...
@@ -97,7 +85,7 @@ xfs_rui_item_format(
ruip
->
rui_format
.
rui_size
=
1
;
xlog_copy_iovec
(
lv
,
&
vecp
,
XLOG_REG_TYPE_RUI_FORMAT
,
&
ruip
->
rui_format
,
xfs_rui_
item_sizeof
(
ruip
));
xfs_rui_
log_format_sizeof
(
ruip
->
rui_format
.
rui_nextents
));
}
/*
...
...
@@ -205,16 +193,12 @@ xfs_rui_init(
{
struct
xfs_rui_log_item
*
ruip
;
uint
size
;
ASSERT
(
nextents
>
0
);
if
(
nextents
>
XFS_RUI_MAX_FAST_EXTENTS
)
{
size
=
(
uint
)(
sizeof
(
struct
xfs_rui_log_item
)
+
((
nextents
-
1
)
*
sizeof
(
struct
xfs_map_extent
)));
ruip
=
kmem_zalloc
(
size
,
KM_SLEEP
);
}
else
{
if
(
nextents
>
XFS_RUI_MAX_FAST_EXTENTS
)
ruip
=
kmem_zalloc
(
xfs_rui_log_item_sizeof
(
nextents
),
KM_SLEEP
);
else
ruip
=
kmem_zone_zalloc
(
xfs_rui_zone
,
KM_SLEEP
);
}
xfs_log_item_init
(
mp
,
&
ruip
->
rui_item
,
XFS_LI_RUI
,
&
xfs_rui_item_ops
);
ruip
->
rui_format
.
rui_nextents
=
nextents
;
...
...
@@ -239,14 +223,12 @@ xfs_rui_copy_format(
uint
len
;
src_rui_fmt
=
buf
->
i_addr
;
len
=
sizeof
(
struct
xfs_rui_log_format
)
+
(
src_rui_fmt
->
rui_nextents
-
1
)
*
sizeof
(
struct
xfs_map_extent
);
len
=
xfs_rui_log_format_sizeof
(
src_rui_fmt
->
rui_nextents
);
if
(
buf
->
i_len
!=
len
)
return
-
EFSCORRUPTED
;
memcpy
(
(
char
*
)
dst_rui_fmt
,
(
char
*
)
src_rui_fmt
,
len
);
memcpy
(
dst_rui_fmt
,
src_rui_fmt
,
len
);
return
0
;
}
...
...
fs/xfs/xfs_rmap_item.h
浏览文件 @
79ad5761
...
...
@@ -70,6 +70,14 @@ struct xfs_rui_log_item {
struct
xfs_rui_log_format
rui_format
;
};
static
inline
size_t
xfs_rui_log_item_sizeof
(
unsigned
int
nr
)
{
return
offsetof
(
struct
xfs_rui_log_item
,
rui_format
)
+
xfs_rui_log_format_sizeof
(
nr
);
}
/*
* This is the "rmap update done" log item. It is used to log the fact that
* some rmapbt updates mentioned in an earlier rui item have been performed.
...
...
fs/xfs/xfs_super.c
浏览文件 @
79ad5761
...
...
@@ -1782,9 +1782,8 @@ xfs_init_zones(void)
if
(
!
xfs_rud_zone
)
goto
out_destroy_icreate_zone
;
xfs_rui_zone
=
kmem_zone_init
((
sizeof
(
struct
xfs_rui_log_item
)
+
((
XFS_RUI_MAX_FAST_EXTENTS
-
1
)
*
sizeof
(
struct
xfs_map_extent
))),
xfs_rui_zone
=
kmem_zone_init
(
xfs_rui_log_item_sizeof
(
XFS_RUI_MAX_FAST_EXTENTS
),
"xfs_rui_item"
);
if
(
!
xfs_rui_zone
)
goto
out_destroy_rud_zone
;
...
...
fs/xfs/xfs_trace.h
浏览文件 @
79ad5761
...
...
@@ -1570,14 +1570,15 @@ TRACE_EVENT(xfs_agf,
TRACE_EVENT
(
xfs_free_extent
,
TP_PROTO
(
struct
xfs_mount
*
mp
,
xfs_agnumber_t
agno
,
xfs_agblock_t
agbno
,
xfs_extlen_t
len
,
bool
isfl
,
int
haveleft
,
int
haveright
),
TP_ARGS
(
mp
,
agno
,
agbno
,
len
,
isfl
,
haveleft
,
haveright
),
xfs_extlen_t
len
,
enum
xfs_ag_resv_type
resv
,
int
haveleft
,
int
haveright
),
TP_ARGS
(
mp
,
agno
,
agbno
,
len
,
resv
,
haveleft
,
haveright
),
TP_STRUCT__entry
(
__field
(
dev_t
,
dev
)
__field
(
xfs_agnumber_t
,
agno
)
__field
(
xfs_agblock_t
,
agbno
)
__field
(
xfs_extlen_t
,
len
)
__field
(
int
,
isfl
)
__field
(
int
,
resv
)
__field
(
int
,
haveleft
)
__field
(
int
,
haveright
)
),
...
...
@@ -1586,16 +1587,16 @@ TRACE_EVENT(xfs_free_extent,
__entry
->
agno
=
agno
;
__entry
->
agbno
=
agbno
;
__entry
->
len
=
len
;
__entry
->
isfl
=
isfl
;
__entry
->
resv
=
resv
;
__entry
->
haveleft
=
haveleft
;
__entry
->
haveright
=
haveright
;
),
TP_printk
(
"dev %d:%d agno %u agbno %u len %u
isfl
%d %s"
,
TP_printk
(
"dev %d:%d agno %u agbno %u len %u
resv
%d %s"
,
MAJOR
(
__entry
->
dev
),
MINOR
(
__entry
->
dev
),
__entry
->
agno
,
__entry
->
agbno
,
__entry
->
len
,
__entry
->
isfl
,
__entry
->
resv
,
__entry
->
haveleft
?
(
__entry
->
haveright
?
"both"
:
"left"
)
:
(
__entry
->
haveright
?
"right"
:
"none"
))
...
...
@@ -1622,7 +1623,7 @@ DECLARE_EVENT_CLASS(xfs_alloc_class,
__field
(
short
,
otype
)
__field
(
char
,
wasdel
)
__field
(
char
,
wasfromfl
)
__field
(
char
,
isfl
)
__field
(
int
,
resv
)
__field
(
char
,
userdata
)
__field
(
xfs_fsblock_t
,
firstblock
)
),
...
...
@@ -1643,13 +1644,13 @@ DECLARE_EVENT_CLASS(xfs_alloc_class,
__entry
->
otype
=
args
->
otype
;
__entry
->
wasdel
=
args
->
wasdel
;
__entry
->
wasfromfl
=
args
->
wasfromfl
;
__entry
->
isfl
=
args
->
isfl
;
__entry
->
resv
=
args
->
resv
;
__entry
->
userdata
=
args
->
userdata
;
__entry
->
firstblock
=
args
->
firstblock
;
),
TP_printk
(
"dev %d:%d agno %u agbno %u minlen %u maxlen %u mod %u "
"prod %u minleft %u total %u alignment %u minalignslop %u "
"len %u type %s otype %s wasdel %d wasfromfl %d
isfl
%d "
"len %u type %s otype %s wasdel %d wasfromfl %d
resv
%d "
"userdata %d firstblock 0x%llx"
,
MAJOR
(
__entry
->
dev
),
MINOR
(
__entry
->
dev
),
__entry
->
agno
,
...
...
@@ -1667,7 +1668,7 @@ DECLARE_EVENT_CLASS(xfs_alloc_class,
__print_symbolic
(
__entry
->
otype
,
XFS_ALLOC_TYPES
),
__entry
->
wasdel
,
__entry
->
wasfromfl
,
__entry
->
isfl
,
__entry
->
resv
,
__entry
->
userdata
,
(
unsigned
long
long
)
__entry
->
firstblock
)
)
...
...
@@ -2558,6 +2559,60 @@ DEFINE_RMAPBT_EVENT(xfs_rmap_lookup_le_range_result);
DEFINE_RMAPBT_EVENT
(
xfs_rmap_find_right_neighbor_result
);
DEFINE_RMAPBT_EVENT
(
xfs_rmap_find_left_neighbor_result
);
/* per-AG reservation */
DECLARE_EVENT_CLASS
(
xfs_ag_resv_class
,
TP_PROTO
(
struct
xfs_perag
*
pag
,
enum
xfs_ag_resv_type
resv
,
xfs_extlen_t
len
),
TP_ARGS
(
pag
,
resv
,
len
),
TP_STRUCT__entry
(
__field
(
dev_t
,
dev
)
__field
(
xfs_agnumber_t
,
agno
)
__field
(
int
,
resv
)
__field
(
xfs_extlen_t
,
freeblks
)
__field
(
xfs_extlen_t
,
flcount
)
__field
(
xfs_extlen_t
,
reserved
)
__field
(
xfs_extlen_t
,
asked
)
__field
(
xfs_extlen_t
,
len
)
),
TP_fast_assign
(
struct
xfs_ag_resv
*
r
=
xfs_perag_resv
(
pag
,
resv
);
__entry
->
dev
=
pag
->
pag_mount
->
m_super
->
s_dev
;
__entry
->
agno
=
pag
->
pag_agno
;
__entry
->
resv
=
resv
;
__entry
->
freeblks
=
pag
->
pagf_freeblks
;
__entry
->
flcount
=
pag
->
pagf_flcount
;
__entry
->
reserved
=
r
?
r
->
ar_reserved
:
0
;
__entry
->
asked
=
r
?
r
->
ar_asked
:
0
;
__entry
->
len
=
len
;
),
TP_printk
(
"dev %d:%d agno %u resv %d freeblks %u flcount %u resv %u ask %u len %u
\n
"
,
MAJOR
(
__entry
->
dev
),
MINOR
(
__entry
->
dev
),
__entry
->
agno
,
__entry
->
resv
,
__entry
->
freeblks
,
__entry
->
flcount
,
__entry
->
reserved
,
__entry
->
asked
,
__entry
->
len
)
)
#define DEFINE_AG_RESV_EVENT(name) \
DEFINE_EVENT(xfs_ag_resv_class, name, \
TP_PROTO(struct xfs_perag *pag, enum xfs_ag_resv_type type, \
xfs_extlen_t len), \
TP_ARGS(pag, type, len))
/* per-AG reservation tracepoints */
DEFINE_AG_RESV_EVENT
(
xfs_ag_resv_init
);
DEFINE_AG_RESV_EVENT
(
xfs_ag_resv_free
);
DEFINE_AG_RESV_EVENT
(
xfs_ag_resv_alloc_extent
);
DEFINE_AG_RESV_EVENT
(
xfs_ag_resv_free_extent
);
DEFINE_AG_RESV_EVENT
(
xfs_ag_resv_critical
);
DEFINE_AG_RESV_EVENT
(
xfs_ag_resv_needed
);
DEFINE_AG_ERROR_EVENT
(
xfs_ag_resv_free_error
);
DEFINE_AG_ERROR_EVENT
(
xfs_ag_resv_init_error
);
#endif
/* _TRACE_XFS_H */
#undef TRACE_INCLUDE_PATH
...
...
fs/xfs/xfs_trans.c
浏览文件 @
79ad5761
...
...
@@ -318,7 +318,6 @@ xfs_trans_mod_sb(
* in-core superblock's counter. This should only
* be applied to the on-disk superblock.
*/
ASSERT
(
delta
<
0
);
tp
->
t_res_fdblocks_delta
+=
delta
;
if
(
xfs_sb_version_haslazysbcount
(
&
mp
->
m_sb
))
flags
&=
~
XFS_TRANS_SB_DIRTY
;
...
...
fs/xfs/xfs_trans_extfree.c
浏览文件 @
79ad5761
...
...
@@ -79,7 +79,8 @@ xfs_trans_free_extent(
trace_xfs_bmap_free_deferred
(
tp
->
t_mountp
,
agno
,
0
,
agbno
,
ext_len
);
error
=
xfs_free_extent
(
tp
,
start_block
,
ext_len
,
oinfo
);
error
=
xfs_free_extent
(
tp
,
start_block
,
ext_len
,
oinfo
,
XFS_AG_RESV_NONE
);
/*
* Mark the transaction dirty, even on error. This ensures the
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录