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 | |
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>
-rw-r--r-- | fs/xfs/Makefile | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_log_format.h | 7 | ||||
-rw-r--r-- | fs/xfs/xfs_log_rlimit.c | 145 |
3 files changed, 152 insertions, 1 deletions
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index d6ccf5742d18..0719e4db93f2 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile | |||
@@ -79,6 +79,7 @@ xfs-y += xfs_alloc.o \ | |||
79 | xfs_inode_fork.o \ | 79 | xfs_inode_fork.o \ |
80 | xfs_inode_buf.o \ | 80 | xfs_inode_buf.o \ |
81 | xfs_log_recover.o \ | 81 | xfs_log_recover.o \ |
82 | xfs_log_rlimit.o \ | ||
82 | xfs_sb.o \ | 83 | xfs_sb.o \ |
83 | xfs_symlink_remote.o \ | 84 | xfs_symlink_remote.o \ |
84 | xfs_trans_resv.o | 85 | xfs_trans_resv.o |
diff --git a/fs/xfs/xfs_log_format.h b/fs/xfs/xfs_log_format.h index cc08f597593c..a49ab2c1e7aa 100644 --- a/fs/xfs/xfs_log_format.h +++ b/fs/xfs/xfs_log_format.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #define __XFS_LOG_FORMAT_H__ | 19 | #define __XFS_LOG_FORMAT_H__ |
20 | 20 | ||
21 | struct xfs_mount; | 21 | struct xfs_mount; |
22 | struct xfs_trans_res; | ||
22 | 23 | ||
23 | /* | 24 | /* |
24 | * On-disk Log Format definitions. | 25 | * On-disk Log Format definitions. |
@@ -51,6 +52,9 @@ typedef __uint32_t xlog_tid_t; | |||
51 | 52 | ||
52 | #define XLOG_HEADER_SIZE 512 | 53 | #define XLOG_HEADER_SIZE 512 |
53 | 54 | ||
55 | /* Minimum number of transactions that must fit in the log (defined by mkfs) */ | ||
56 | #define XFS_MIN_LOG_FACTOR 3 | ||
57 | |||
54 | #define XLOG_REC_SHIFT(log) \ | 58 | #define XLOG_REC_SHIFT(log) \ |
55 | BTOBB(1 << (xfs_sb_version_haslogv2(&log->l_mp->m_sb) ? \ | 59 | BTOBB(1 << (xfs_sb_version_haslogv2(&log->l_mp->m_sb) ? \ |
56 | XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT)) | 60 | XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT)) |
@@ -135,7 +139,6 @@ typedef struct xlog_op_header { | |||
135 | __u16 oh_res2; /* 32 bit align : 2 b */ | 139 | __u16 oh_res2; /* 32 bit align : 2 b */ |
136 | } xlog_op_header_t; | 140 | } xlog_op_header_t; |
137 | 141 | ||
138 | |||
139 | /* valid values for h_fmt */ | 142 | /* valid values for h_fmt */ |
140 | #define XLOG_FMT_UNKNOWN 0 | 143 | #define XLOG_FMT_UNKNOWN 0 |
141 | #define XLOG_FMT_LINUX_LE 1 | 144 | #define XLOG_FMT_LINUX_LE 1 |
@@ -837,5 +840,7 @@ struct xfs_icreate_log { | |||
837 | }; | 840 | }; |
838 | 841 | ||
839 | int xfs_log_calc_unit_res(struct xfs_mount *mp, int unit_bytes); | 842 | int xfs_log_calc_unit_res(struct xfs_mount *mp, int unit_bytes); |
843 | int xfs_log_calc_minimum_size(struct xfs_mount *); | ||
844 | |||
840 | 845 | ||
841 | #endif /* __XFS_LOG_FORMAT_H__ */ | 846 | #endif /* __XFS_LOG_FORMAT_H__ */ |
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 | } | ||