diff options
author | Jie Liu <jeff.liu@oracle.com> | 2013-08-12 06:50:02 -0400 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2013-08-12 18:49:38 -0400 |
commit | 5a96a94547fe345467c2ab2ec51cb3fade355bd9 (patch) | |
tree | 938de207a0021f622782fd28a6c1c39fbe3a5d5f /fs/xfs/xfs_log_rlimit.c | |
parent | e773fc934fcbe2536dc625c2bd76234b9b9a60b6 (diff) |
xfs: Add xfs_log_rlimit.c
Add source files for xfs_log_rlimit.c The new file is used for log
size calculations and validation shared with userspace.
[dchinner: xfs_log_calc_max_attrsetm_res() does not modify the
tr_attrsetm reservation, just calculates the maximum. ]
[dchinner: rework loop in xfs_log_get_max_trans_res() ]
Signed-off-by: Jie Liu <jeff.liu@oracle.com>
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_log_rlimit.c')
-rw-r--r-- | fs/xfs/xfs_log_rlimit.c | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/fs/xfs/xfs_log_rlimit.c b/fs/xfs/xfs_log_rlimit.c new file mode 100644 index 000000000000..6b17ef4a061b --- /dev/null +++ b/fs/xfs/xfs_log_rlimit.c | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 Jie Liu. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it would be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write the Free Software Foundation, | ||
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
17 | */ | ||
18 | #include "xfs.h" | ||
19 | #include "xfs_fs.h" | ||
20 | #include "xfs_log.h" | ||
21 | #include "xfs_trans.h" | ||
22 | #include "xfs_ag.h" | ||
23 | #include "xfs_sb.h" | ||
24 | #include "xfs_mount.h" | ||
25 | #include "xfs_trans_space.h" | ||
26 | #include "xfs_bmap_btree.h" | ||
27 | #include "xfs_inode.h" | ||
28 | #include "xfs_da_btree.h" | ||
29 | #include "xfs_attr_leaf.h" | ||
30 | |||
31 | /* | ||
32 | * Calculate the maximum length in bytes that would be required for a local | ||
33 | * attribute value as large attributes out of line are not logged. | ||
34 | */ | ||
35 | STATIC int | ||
36 | xfs_log_calc_max_attrsetm_res( | ||
37 | struct xfs_mount *mp) | ||
38 | { | ||
39 | int size; | ||
40 | int nblks; | ||
41 | |||
42 | size = xfs_attr_leaf_entsize_local_max(mp->m_sb.sb_blocksize) - | ||
43 | MAXNAMELEN - 1; | ||
44 | nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); | ||
45 | nblks += XFS_B_TO_FSB(mp, size); | ||
46 | nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK); | ||
47 | |||
48 | return M_RES(mp)->tr_attrsetm.tr_logres + | ||
49 | M_RES(mp)->tr_attrsetrt.tr_logres * nblks; | ||
50 | } | ||
51 | |||
52 | /* | ||
53 | * Iterate over the log space reservation table to figure out and return | ||
54 | * the maximum one in terms of the pre-calculated values which were done | ||
55 | * at mount time. | ||
56 | */ | ||
57 | STATIC void | ||
58 | xfs_log_get_max_trans_res( | ||
59 | struct xfs_mount *mp, | ||
60 | struct xfs_trans_res *max_resp) | ||
61 | { | ||
62 | struct xfs_trans_res *resp; | ||
63 | struct xfs_trans_res *end_resp; | ||
64 | int log_space = 0; | ||
65 | int attr_space; | ||
66 | |||
67 | attr_space = xfs_log_calc_max_attrsetm_res(mp); | ||
68 | |||
69 | resp = (struct xfs_trans_res *)M_RES(mp); | ||
70 | end_resp = (struct xfs_trans_res *)(M_RES(mp) + 1); | ||
71 | for (; resp < end_resp; resp++) { | ||
72 | int tmp = resp->tr_logcount > 1 ? | ||
73 | resp->tr_logres * resp->tr_logcount : | ||
74 | resp->tr_logres; | ||
75 | if (log_space < tmp) { | ||
76 | log_space = tmp; | ||
77 | *max_resp = *resp; /* struct copy */ | ||
78 | } | ||
79 | } | ||
80 | |||
81 | if (attr_space > log_space) { | ||
82 | *max_resp = M_RES(mp)->tr_attrsetm; /* struct copy */ | ||
83 | max_resp->tr_logres = attr_space; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * Calculate the minimum valid log size for the given superblock configuration. | ||
89 | * Used to calculate the minimum log size at mkfs time, and to determine if | ||
90 | * the log is large enough or not at mount time. Returns the minimum size in | ||
91 | * filesystem block size units. | ||
92 | */ | ||
93 | int | ||
94 | xfs_log_calc_minimum_size( | ||
95 | struct xfs_mount *mp) | ||
96 | { | ||
97 | struct xfs_trans_res tres = {0}; | ||
98 | int max_logres; | ||
99 | int min_logblks = 0; | ||
100 | int lsunit = 0; | ||
101 | |||
102 | xfs_log_get_max_trans_res(mp, &tres); | ||
103 | |||
104 | max_logres = xfs_log_calc_unit_res(mp, tres.tr_logres); | ||
105 | if (tres.tr_logcount > 1) | ||
106 | max_logres *= tres.tr_logcount; | ||
107 | |||
108 | if (xfs_sb_version_haslogv2(&mp->m_sb) && mp->m_sb.sb_logsunit > 1) | ||
109 | lsunit = BTOBB(mp->m_sb.sb_logsunit); | ||
110 | |||
111 | /* | ||
112 | * Two factors should be taken into account for calculating the minimum | ||
113 | * log space. | ||
114 | * 1) The fundamental limitation is that no single transaction can be | ||
115 | * larger than half size of the log. | ||
116 | * | ||
117 | * From mkfs.xfs, this is considered by the XFS_MIN_LOG_FACTOR | ||
118 | * define, which is set to 3. That means we can definitely fit | ||
119 | * maximally sized 2 transactions in the log. We'll use this same | ||
120 | * value here. | ||
121 | * | ||
122 | * 2) If the lsunit option is specified, a transaction requires 2 LSU | ||
123 | * for the reservation because there are two log writes that can | ||
124 | * require padding - the transaction data and the commit record which | ||
125 | * are written separately and both can require padding to the LSU. | ||
126 | * Consider that we can have an active CIL reservation holding 2*LSU, | ||
127 | * but the CIL is not over a push threshold, in this case, if we | ||
128 | * don't have enough log space for at one new transaction, which | ||
129 | * includes another 2*LSU in the reservation, we will run into dead | ||
130 | * loop situation in log space grant procedure. i.e. | ||
131 | * xlog_grant_head_wait(). | ||
132 | * | ||
133 | * Hence the log size needs to be able to contain two maximally sized | ||
134 | * and padded transactions, which is (2 * (2 * LSU + maxlres)). | ||
135 | * | ||
136 | * Also, the log size should be a multiple of the log stripe unit, round | ||
137 | * it up to lsunit boundary if lsunit is specified. | ||
138 | */ | ||
139 | if (lsunit) | ||
140 | min_logblks = roundup(BTOBB(max_logres), lsunit) + 2 * lsunit; | ||
141 | else | ||
142 | min_logblks = BTOBB(max_logres) + 2 * BBSIZE; | ||
143 | min_logblks *= XFS_MIN_LOG_FACTOR; | ||
144 | return XFS_BB_TO_FSB(mp, min_logblks); | ||
145 | } | ||