diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_log_rlimit.c')
-rw-r--r-- | fs/xfs/libxfs/xfs_log_rlimit.c | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/fs/xfs/libxfs/xfs_log_rlimit.c b/fs/xfs/libxfs/xfs_log_rlimit.c new file mode 100644 index 000000000000..ee7e0e80246b --- /dev/null +++ b/fs/xfs/libxfs/xfs_log_rlimit.c | |||
@@ -0,0 +1,150 @@ | |||
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_shared.h" | ||
21 | #include "xfs_format.h" | ||
22 | #include "xfs_log_format.h" | ||
23 | #include "xfs_trans_resv.h" | ||
24 | #include "xfs_ag.h" | ||
25 | #include "xfs_sb.h" | ||
26 | #include "xfs_mount.h" | ||
27 | #include "xfs_da_format.h" | ||
28 | #include "xfs_trans_space.h" | ||
29 | #include "xfs_inode.h" | ||
30 | #include "xfs_da_btree.h" | ||
31 | #include "xfs_attr_leaf.h" | ||
32 | #include "xfs_bmap_btree.h" | ||
33 | |||
34 | /* | ||
35 | * Calculate the maximum length in bytes that would be required for a local | ||
36 | * attribute value as large attributes out of line are not logged. | ||
37 | */ | ||
38 | STATIC int | ||
39 | xfs_log_calc_max_attrsetm_res( | ||
40 | struct xfs_mount *mp) | ||
41 | { | ||
42 | int size; | ||
43 | int nblks; | ||
44 | |||
45 | size = xfs_attr_leaf_entsize_local_max(mp->m_attr_geo->blksize) - | ||
46 | MAXNAMELEN - 1; | ||
47 | nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); | ||
48 | nblks += XFS_B_TO_FSB(mp, size); | ||
49 | nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK); | ||
50 | |||
51 | return M_RES(mp)->tr_attrsetm.tr_logres + | ||
52 | M_RES(mp)->tr_attrsetrt.tr_logres * nblks; | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | * Iterate over the log space reservation table to figure out and return | ||
57 | * the maximum one in terms of the pre-calculated values which were done | ||
58 | * at mount time. | ||
59 | */ | ||
60 | STATIC void | ||
61 | xfs_log_get_max_trans_res( | ||
62 | struct xfs_mount *mp, | ||
63 | struct xfs_trans_res *max_resp) | ||
64 | { | ||
65 | struct xfs_trans_res *resp; | ||
66 | struct xfs_trans_res *end_resp; | ||
67 | int log_space = 0; | ||
68 | int attr_space; | ||
69 | |||
70 | attr_space = xfs_log_calc_max_attrsetm_res(mp); | ||
71 | |||
72 | resp = (struct xfs_trans_res *)M_RES(mp); | ||
73 | end_resp = (struct xfs_trans_res *)(M_RES(mp) + 1); | ||
74 | for (; resp < end_resp; resp++) { | ||
75 | int tmp = resp->tr_logcount > 1 ? | ||
76 | resp->tr_logres * resp->tr_logcount : | ||
77 | resp->tr_logres; | ||
78 | if (log_space < tmp) { | ||
79 | log_space = tmp; | ||
80 | *max_resp = *resp; /* struct copy */ | ||
81 | } | ||
82 | } | ||
83 | |||
84 | if (attr_space > log_space) { | ||
85 | *max_resp = M_RES(mp)->tr_attrsetm; /* struct copy */ | ||
86 | max_resp->tr_logres = attr_space; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Calculate the minimum valid log size for the given superblock configuration. | ||
92 | * Used to calculate the minimum log size at mkfs time, and to determine if | ||
93 | * the log is large enough or not at mount time. Returns the minimum size in | ||
94 | * filesystem block size units. | ||
95 | */ | ||
96 | int | ||
97 | xfs_log_calc_minimum_size( | ||
98 | struct xfs_mount *mp) | ||
99 | { | ||
100 | struct xfs_trans_res tres = {0}; | ||
101 | int max_logres; | ||
102 | int min_logblks = 0; | ||
103 | int lsunit = 0; | ||
104 | |||
105 | xfs_log_get_max_trans_res(mp, &tres); | ||
106 | |||
107 | max_logres = xfs_log_calc_unit_res(mp, tres.tr_logres); | ||
108 | if (tres.tr_logcount > 1) | ||
109 | max_logres *= tres.tr_logcount; | ||
110 | |||
111 | if (xfs_sb_version_haslogv2(&mp->m_sb) && mp->m_sb.sb_logsunit > 1) | ||
112 | lsunit = BTOBB(mp->m_sb.sb_logsunit); | ||
113 | |||
114 | /* | ||
115 | * Two factors should be taken into account for calculating the minimum | ||
116 | * log space. | ||
117 | * 1) The fundamental limitation is that no single transaction can be | ||
118 | * larger than half size of the log. | ||
119 | * | ||
120 | * From mkfs.xfs, this is considered by the XFS_MIN_LOG_FACTOR | ||
121 | * define, which is set to 3. That means we can definitely fit | ||
122 | * maximally sized 2 transactions in the log. We'll use this same | ||
123 | * value here. | ||
124 | * | ||
125 | * 2) If the lsunit option is specified, a transaction requires 2 LSU | ||
126 | * for the reservation because there are two log writes that can | ||
127 | * require padding - the transaction data and the commit record which | ||
128 | * are written separately and both can require padding to the LSU. | ||
129 | * Consider that we can have an active CIL reservation holding 2*LSU, | ||
130 | * but the CIL is not over a push threshold, in this case, if we | ||
131 | * don't have enough log space for at one new transaction, which | ||
132 | * includes another 2*LSU in the reservation, we will run into dead | ||
133 | * loop situation in log space grant procedure. i.e. | ||
134 | * xlog_grant_head_wait(). | ||
135 | * | ||
136 | * Hence the log size needs to be able to contain two maximally sized | ||
137 | * and padded transactions, which is (2 * (2 * LSU + maxlres)). | ||
138 | * | ||
139 | * Also, the log size should be a multiple of the log stripe unit, round | ||
140 | * it up to lsunit boundary if lsunit is specified. | ||
141 | */ | ||
142 | if (lsunit) { | ||
143 | min_logblks = roundup_64(BTOBB(max_logres), lsunit) + | ||
144 | 2 * lsunit; | ||
145 | } else | ||
146 | min_logblks = BTOBB(max_logres) + 2 * BBSIZE; | ||
147 | min_logblks *= XFS_MIN_LOG_FACTOR; | ||
148 | |||
149 | return XFS_BB_TO_FSB(mp, min_logblks); | ||
150 | } | ||