]>
Commit | Line | Data |
---|---|---|
2bd0ea18 | 1 | /* |
f1b058f9 | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
da23017d | 3 | * All Rights Reserved. |
2bd0ea18 | 4 | * |
da23017d NS |
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 | |
2bd0ea18 NS |
7 | * published by the Free Software Foundation. |
8 | * | |
da23017d NS |
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. | |
2bd0ea18 | 13 | * |
da23017d NS |
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 | |
2bd0ea18 NS |
17 | */ |
18 | ||
19 | #include <xfs.h> | |
20 | ||
21 | /* | |
22 | * Mount initialization code establishing various mount | |
23 | * fields from the superblock associated with the given | |
24 | * mount structure. | |
25 | */ | |
26 | void | |
27 | xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp) | |
28 | { | |
29 | int i; | |
30 | ||
31 | mp->m_agfrotor = mp->m_agirotor = 0; | |
321717ae | 32 | spinlock_init(&mp->m_agirotor_lock, "m_agirotor_lock"); |
34317449 | 33 | mp->m_maxagi = mp->m_sb.sb_agcount; |
2bd0ea18 NS |
34 | mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG; |
35 | mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT; | |
9440d84d | 36 | mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT; |
2bd0ea18 NS |
37 | mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1; |
38 | mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog; | |
39 | mp->m_litino = sbp->sb_inodesize - | |
40 | ((uint)sizeof(xfs_dinode_core_t) + (uint)sizeof(xfs_agino_t)); | |
41 | mp->m_blockmask = sbp->sb_blocksize - 1; | |
42 | mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG; | |
43 | mp->m_blockwmask = mp->m_blockwsize - 1; | |
a562a63b | 44 | INIT_LIST_HEAD(&mp->m_del_inodes); |
73bf5988 | 45 | |
2bd0ea18 NS |
46 | /* |
47 | * Setup for attributes, in case they get created. | |
48 | * This value is for inodes getting attributes for the first time, | |
49 | * the per-inode value is for old attribute values. | |
50 | */ | |
51 | ASSERT(sbp->sb_inodesize >= 256 && sbp->sb_inodesize <= 2048); | |
52 | switch (sbp->sb_inodesize) { | |
53 | case 256: | |
ca86e759 NS |
54 | mp->m_attroffset = XFS_LITINO(mp) - |
55 | XFS_BMDR_SPACE_CALC(MINABTPTRS); | |
2bd0ea18 NS |
56 | break; |
57 | case 512: | |
58 | case 1024: | |
59 | case 2048: | |
ca86e759 | 60 | mp->m_attroffset = XFS_BMDR_SPACE_CALC(6 * MINABTPTRS); |
2bd0ea18 NS |
61 | break; |
62 | default: | |
63 | ASSERT(0); | |
64 | } | |
65 | ASSERT(mp->m_attroffset < XFS_LITINO(mp)); | |
66 | ||
67 | for (i = 0; i < 2; i++) { | |
68 | mp->m_alloc_mxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, | |
69 | xfs_alloc, i == 0); | |
70 | mp->m_alloc_mnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, | |
71 | xfs_alloc, i == 0); | |
72 | } | |
73 | for (i = 0; i < 2; i++) { | |
74 | mp->m_bmap_dmxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, | |
75 | xfs_bmbt, i == 0); | |
76 | mp->m_bmap_dmnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, | |
77 | xfs_bmbt, i == 0); | |
78 | } | |
79 | for (i = 0; i < 2; i++) { | |
80 | mp->m_inobt_mxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, | |
81 | xfs_inobt, i == 0); | |
82 | mp->m_inobt_mnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, | |
83 | xfs_inobt, i == 0); | |
84 | } | |
85 | ||
86 | mp->m_bsize = XFS_FSB_TO_BB(mp, 1); | |
7dcc1612 NS |
87 | mp->m_ialloc_inos = (int)MAX((__uint16_t)XFS_INODES_PER_CHUNK, |
88 | sbp->sb_inopblock); | |
2bd0ea18 NS |
89 | mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog; |
90 | } | |
91 | ||
92 | static struct { | |
93 | short offset; | |
5000d01d SL |
94 | short type; /* 0 = integer |
95 | * 1 = binary / string (no translation) | |
96 | */ | |
2bd0ea18 | 97 | } xfs_sb_info[] = { |
5000d01d SL |
98 | { offsetof(xfs_sb_t, sb_magicnum), 0 }, |
99 | { offsetof(xfs_sb_t, sb_blocksize), 0 }, | |
100 | { offsetof(xfs_sb_t, sb_dblocks), 0 }, | |
101 | { offsetof(xfs_sb_t, sb_rblocks), 0 }, | |
102 | { offsetof(xfs_sb_t, sb_rextents), 0 }, | |
103 | { offsetof(xfs_sb_t, sb_uuid), 1 }, | |
104 | { offsetof(xfs_sb_t, sb_logstart), 0 }, | |
105 | { offsetof(xfs_sb_t, sb_rootino), 0 }, | |
106 | { offsetof(xfs_sb_t, sb_rbmino), 0 }, | |
107 | { offsetof(xfs_sb_t, sb_rsumino), 0 }, | |
108 | { offsetof(xfs_sb_t, sb_rextsize), 0 }, | |
109 | { offsetof(xfs_sb_t, sb_agblocks), 0 }, | |
110 | { offsetof(xfs_sb_t, sb_agcount), 0 }, | |
111 | { offsetof(xfs_sb_t, sb_rbmblocks), 0 }, | |
112 | { offsetof(xfs_sb_t, sb_logblocks), 0 }, | |
2bd0ea18 | 113 | { offsetof(xfs_sb_t, sb_versionnum), 0 }, |
5000d01d SL |
114 | { offsetof(xfs_sb_t, sb_sectsize), 0 }, |
115 | { offsetof(xfs_sb_t, sb_inodesize), 0 }, | |
116 | { offsetof(xfs_sb_t, sb_inopblock), 0 }, | |
117 | { offsetof(xfs_sb_t, sb_fname[0]), 1 }, | |
118 | { offsetof(xfs_sb_t, sb_blocklog), 0 }, | |
119 | { offsetof(xfs_sb_t, sb_sectlog), 0 }, | |
120 | { offsetof(xfs_sb_t, sb_inodelog), 0 }, | |
121 | { offsetof(xfs_sb_t, sb_inopblog), 0 }, | |
122 | { offsetof(xfs_sb_t, sb_agblklog), 0 }, | |
123 | { offsetof(xfs_sb_t, sb_rextslog), 0 }, | |
2bd0ea18 | 124 | { offsetof(xfs_sb_t, sb_inprogress), 0 }, |
5000d01d SL |
125 | { offsetof(xfs_sb_t, sb_imax_pct), 0 }, |
126 | { offsetof(xfs_sb_t, sb_icount), 0 }, | |
127 | { offsetof(xfs_sb_t, sb_ifree), 0 }, | |
128 | { offsetof(xfs_sb_t, sb_fdblocks), 0 }, | |
129 | { offsetof(xfs_sb_t, sb_frextents), 0 }, | |
130 | { offsetof(xfs_sb_t, sb_uquotino), 0 }, | |
131 | { offsetof(xfs_sb_t, sb_gquotino), 0 }, | |
132 | { offsetof(xfs_sb_t, sb_qflags), 0 }, | |
133 | { offsetof(xfs_sb_t, sb_flags), 0 }, | |
134 | { offsetof(xfs_sb_t, sb_shared_vn), 0 }, | |
2bd0ea18 | 135 | { offsetof(xfs_sb_t, sb_inoalignmt), 0 }, |
5000d01d SL |
136 | { offsetof(xfs_sb_t, sb_unit), 0 }, |
137 | { offsetof(xfs_sb_t, sb_width), 0 }, | |
138 | { offsetof(xfs_sb_t, sb_dirblklog), 0 }, | |
9440d84d NS |
139 | { offsetof(xfs_sb_t, sb_logsectlog), 0 }, |
140 | { offsetof(xfs_sb_t, sb_logsectsize),0 }, | |
5000d01d | 141 | { offsetof(xfs_sb_t, sb_logsunit), 0 }, |
2999b9c1 | 142 | { offsetof(xfs_sb_t, sb_features2), 0 }, |
5000d01d | 143 | { sizeof(xfs_sb_t), 0 } |
2bd0ea18 NS |
144 | }; |
145 | ||
146 | /* | |
147 | * xfs_xlatesb | |
5000d01d SL |
148 | * data - on disk version of sb |
149 | * sb - a superblock | |
150 | * dir - conversion direction: <0 - convert sb to buf | |
151 | * >0 - convert buf to sb | |
152 | * arch - architecture to read/write from/to buf | |
153 | * fields - which fields to copy (bitmask) | |
2bd0ea18 NS |
154 | */ |
155 | void | |
b391b7cd NS |
156 | xfs_xlatesb( |
157 | void *data, | |
158 | xfs_sb_t *sb, | |
159 | int dir, | |
b391b7cd | 160 | __int64_t fields) |
2bd0ea18 | 161 | { |
b391b7cd NS |
162 | xfs_caddr_t buf_ptr; |
163 | xfs_caddr_t mem_ptr; | |
164 | xfs_sb_field_t f; | |
165 | int first; | |
166 | int size; | |
5000d01d | 167 | |
b391b7cd NS |
168 | ASSERT(dir); |
169 | ASSERT(fields); | |
2bd0ea18 | 170 | |
b391b7cd NS |
171 | if (!fields) |
172 | return; | |
5000d01d | 173 | |
b391b7cd NS |
174 | buf_ptr = (xfs_caddr_t)data; |
175 | mem_ptr = (xfs_caddr_t)sb; | |
5000d01d | 176 | |
b391b7cd NS |
177 | while (fields) { |
178 | f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields); | |
179 | first = xfs_sb_info[f].offset; | |
180 | size = xfs_sb_info[f + 1].offset - first; | |
2bd0ea18 | 181 | |
b391b7cd | 182 | ASSERT(xfs_sb_info[f].type == 0 || xfs_sb_info[f].type == 1); |
5000d01d | 183 | |
46eca962 | 184 | if (size == 1 || xfs_sb_info[f].type == 1) { |
b391b7cd | 185 | if (dir > 0) { |
32181a02 | 186 | memcpy(mem_ptr + first, buf_ptr + first, size); |
b391b7cd | 187 | } else { |
32181a02 | 188 | memcpy(buf_ptr + first, mem_ptr + first, size); |
b391b7cd NS |
189 | } |
190 | } else { | |
191 | switch (size) { | |
192 | case 2: | |
193 | INT_XLATE(*(__uint16_t*)(buf_ptr+first), | |
194 | *(__uint16_t*)(mem_ptr+first), | |
46eca962 | 195 | dir, ARCH_CONVERT); |
b391b7cd NS |
196 | break; |
197 | case 4: | |
198 | INT_XLATE(*(__uint32_t*)(buf_ptr+first), | |
199 | *(__uint32_t*)(mem_ptr+first), | |
46eca962 | 200 | dir, ARCH_CONVERT); |
b391b7cd NS |
201 | break; |
202 | case 8: | |
203 | INT_XLATE(*(__uint64_t*)(buf_ptr+first), | |
46eca962 | 204 | *(__uint64_t*)(mem_ptr+first), dir, ARCH_CONVERT); |
b391b7cd NS |
205 | break; |
206 | default: | |
207 | ASSERT(0); | |
208 | } | |
209 | } | |
210 | ||
211 | fields &= ~(1LL << f); | |
212 | } | |
2bd0ea18 | 213 | } |
a33a9e62 | 214 | |
f1b058f9 NS |
215 | /* |
216 | * xfs_mod_sb() can be used to copy arbitrary changes to the | |
217 | * in-core superblock into the superblock buffer to be logged. | |
218 | * It does not provide the higher level of locking that is | |
219 | * needed to protect the in-core superblock from concurrent | |
220 | * access. | |
221 | */ | |
222 | void | |
223 | xfs_mod_sb(xfs_trans_t *tp, __int64_t fields) | |
224 | { | |
225 | xfs_buf_t *bp; | |
226 | int first; | |
227 | int last; | |
228 | xfs_mount_t *mp; | |
229 | xfs_sb_t *sbp; | |
230 | xfs_sb_field_t f; | |
231 | ||
232 | ASSERT(fields); | |
233 | if (!fields) | |
234 | return; | |
235 | mp = tp->t_mountp; | |
236 | bp = xfs_trans_getsb(tp, mp, 0); | |
237 | sbp = XFS_BUF_TO_SBP(bp); | |
238 | first = sizeof(xfs_sb_t); | |
239 | last = 0; | |
240 | ||
241 | /* translate/copy */ | |
242 | xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), -1, fields); | |
243 | ||
244 | /* find modified range */ | |
245 | f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields); | |
246 | ASSERT((1LL << f) & XFS_SB_MOD_BITS); | |
247 | first = xfs_sb_info[f].offset; | |
248 | f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields); | |
249 | ASSERT((1LL << f) & XFS_SB_MOD_BITS); | |
250 | last = xfs_sb_info[f + 1].offset - 1; | |
251 | ||
252 | xfs_trans_log_buf(tp, bp, first, last); | |
253 | } | |
254 | ||
062998e3 NS |
255 | xfs_agnumber_t |
256 | xfs_initialize_perag(xfs_mount_t *mp, xfs_agnumber_t agcount) | |
a33a9e62 | 257 | { |
062998e3 | 258 | xfs_agnumber_t index, max_metadata; |
a33a9e62 NS |
259 | xfs_perag_t *pag; |
260 | xfs_agino_t agino; | |
261 | xfs_ino_t ino; | |
262 | xfs_sb_t *sbp = &mp->m_sb; | |
263 | xfs_ino_t max_inum = XFS_MAXINUMBER_32; | |
264 | ||
265 | /* Check to see if the filesystem can overflow 32 bit inodes */ | |
266 | agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); | |
267 | ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); | |
268 | ||
269 | /* Clear the mount flag if no inode can overflow 32 bits | |
2b288ccf | 270 | * on this filesystem, or if specifically requested.. |
a33a9e62 | 271 | */ |
2b288ccf NS |
272 | if ((mp->m_flags & XFS_MOUNT_32BITINOOPT) && ino > max_inum) { |
273 | mp->m_flags |= XFS_MOUNT_32BITINODES; | |
274 | } else { | |
a33a9e62 NS |
275 | mp->m_flags &= ~XFS_MOUNT_32BITINODES; |
276 | } | |
277 | ||
278 | /* If we can overflow then setup the ag headers accordingly */ | |
279 | if (mp->m_flags & XFS_MOUNT_32BITINODES) { | |
280 | /* Calculate how much should be reserved for inodes to | |
281 | * meet the max inode percentage. | |
282 | */ | |
283 | if (mp->m_maxicount) { | |
284 | __uint64_t icount; | |
285 | ||
286 | icount = sbp->sb_dblocks * sbp->sb_imax_pct; | |
287 | do_div(icount, 100); | |
288 | icount += sbp->sb_agblocks - 1; | |
f9c48a87 | 289 | do_div(icount, sbp->sb_agblocks); |
a33a9e62 NS |
290 | max_metadata = icount; |
291 | } else { | |
292 | max_metadata = agcount; | |
293 | } | |
294 | for (index = 0; index < agcount; index++) { | |
295 | ino = XFS_AGINO_TO_INO(mp, index, agino); | |
296 | if (ino > max_inum) { | |
297 | index++; | |
298 | break; | |
299 | } | |
300 | ||
301 | /* This ag is prefered for inodes */ | |
302 | pag = &mp->m_perag[index]; | |
303 | pag->pagi_inodeok = 1; | |
304 | if (index < max_metadata) | |
305 | pag->pagf_metadata = 1; | |
306 | } | |
307 | } else { | |
308 | /* Setup default behavior for smaller filesystems */ | |
309 | for (index = 0; index < agcount; index++) { | |
310 | pag = &mp->m_perag[index]; | |
311 | pag->pagi_inodeok = 1; | |
312 | } | |
313 | } | |
062998e3 | 314 | return index; |
a33a9e62 | 315 | } |
cdded3d8 DC |
316 | |
317 | /* | |
318 | * xfs_initialize_perag_data | |
319 | * | |
320 | * Read in each per-ag structure so we can count up the number of | |
321 | * allocated inodes, free inodes and used filesystem blocks as this | |
322 | * information is no longer persistent in the superblock. Once we have | |
323 | * this information, write it into the in-core superblock structure. | |
324 | */ | |
325 | STATIC int | |
326 | xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount) | |
327 | { | |
328 | xfs_agnumber_t index; | |
329 | xfs_perag_t *pag; | |
330 | xfs_sb_t *sbp = &mp->m_sb; | |
331 | __uint64_t ifree = 0; | |
332 | __uint64_t ialloc = 0; | |
333 | __uint64_t bfree = 0; | |
334 | __uint64_t bfreelst = 0; | |
335 | __uint64_t btree = 0; | |
336 | int error; | |
337 | int s; | |
338 | ||
339 | for (index = 0; index < agcount; index++) { | |
340 | /* | |
341 | * read the agf, then the agi. This gets us | |
342 | * all the information we need and populates the | |
343 | * per-ag structures for us. | |
344 | */ | |
345 | error = xfs_alloc_pagf_init(mp, NULL, index, 0); | |
346 | if (error) | |
347 | return error; | |
348 | ||
349 | error = xfs_ialloc_pagi_init(mp, NULL, index); | |
350 | if (error) | |
351 | return error; | |
352 | pag = &mp->m_perag[index]; | |
353 | ifree += pag->pagi_freecount; | |
354 | ialloc += pag->pagi_count; | |
355 | bfree += pag->pagf_freeblks; | |
356 | bfreelst += pag->pagf_flcount; | |
357 | btree += pag->pagf_btreeblks; | |
358 | } | |
359 | /* | |
360 | * Overwrite incore superblock counters with just-read data | |
361 | */ | |
362 | s = XFS_SB_LOCK(mp); | |
363 | sbp->sb_ifree = ifree; | |
364 | sbp->sb_icount = ialloc; | |
365 | sbp->sb_fdblocks = bfree + bfreelst + btree; | |
366 | XFS_SB_UNLOCK(mp, s); | |
367 | return 0; | |
368 | } |