]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/xfs_mount.c
Userspace support for lazy superblock counters
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_mount.c
CommitLineData
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 */
26void
27xfs_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
92static 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 */
155void
b391b7cd
NS
156xfs_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 */
222void
223xfs_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
255xfs_agnumber_t
256xfs_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 */
325STATIC int
326xfs_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}