xfs_mount.c 69.8 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
2
3
 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
 * All Rights Reserved.
Linus Torvalds's avatar
Linus Torvalds committed
4
 *
5
6
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
Linus Torvalds's avatar
Linus Torvalds committed
7
8
 * published by the Free Software Foundation.
 *
9
10
11
12
 * This program is distributed in the hope that it would be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
Linus Torvalds's avatar
Linus Torvalds committed
13
 *
14
15
16
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write the Free Software Foundation,
 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Linus Torvalds's avatar
Linus Torvalds committed
17
18
 */
#include "xfs.h"
19
#include "xfs_fs.h"
Linus Torvalds's avatar
Linus Torvalds committed
20
#include "xfs_types.h"
21
#include "xfs_bit.h"
Linus Torvalds's avatar
Linus Torvalds committed
22
#include "xfs_log.h"
23
#include "xfs_inum.h"
Linus Torvalds's avatar
Linus Torvalds committed
24
#include "xfs_trans.h"
25
#include "xfs_trans_priv.h"
Linus Torvalds's avatar
Linus Torvalds committed
26
27
28
29
30
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
31
#include "xfs_alloc_btree.h"
Linus Torvalds's avatar
Linus Torvalds committed
32
33
34
#include "xfs_ialloc_btree.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
35
36
#include "xfs_btree.h"
#include "xfs_ialloc.h"
Linus Torvalds's avatar
Linus Torvalds committed
37
38
39
40
41
42
#include "xfs_alloc.h"
#include "xfs_rtalloc.h"
#include "xfs_bmap.h"
#include "xfs_error.h"
#include "xfs_quota.h"
#include "xfs_fsops.h"
43
#include "xfs_utils.h"
Christoph Hellwig's avatar
Christoph Hellwig committed
44
#include "xfs_trace.h"
45
#include "xfs_icache.h"
46
47
#include "xfs_cksum.h"
#include "xfs_buf_item.h"
Christoph Hellwig's avatar
Christoph Hellwig committed
48

Linus Torvalds's avatar
Linus Torvalds committed
49

50
#ifdef HAVE_PERCPU_SB
51
STATIC void	xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t,
52
53
54
						int);
STATIC void	xfs_icsb_balance_counter_locked(xfs_mount_t *, xfs_sb_field_t,
						int);
55
STATIC void	xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t);
56
57
#else

58
59
#define xfs_icsb_balance_counter(mp, a, b)		do { } while (0)
#define xfs_icsb_balance_counter_locked(mp, a, b)	do { } while (0)
60
61
#endif

62
static const struct {
63
64
65
66
	short offset;
	short type;	/* 0 = integer
			 * 1 = binary / string (no translation)
			 */
Linus Torvalds's avatar
Linus Torvalds committed
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
} xfs_sb_info[] = {
    { offsetof(xfs_sb_t, sb_magicnum),   0 },
    { offsetof(xfs_sb_t, sb_blocksize),  0 },
    { offsetof(xfs_sb_t, sb_dblocks),    0 },
    { offsetof(xfs_sb_t, sb_rblocks),    0 },
    { offsetof(xfs_sb_t, sb_rextents),   0 },
    { offsetof(xfs_sb_t, sb_uuid),       1 },
    { offsetof(xfs_sb_t, sb_logstart),   0 },
    { offsetof(xfs_sb_t, sb_rootino),    0 },
    { offsetof(xfs_sb_t, sb_rbmino),     0 },
    { offsetof(xfs_sb_t, sb_rsumino),    0 },
    { offsetof(xfs_sb_t, sb_rextsize),   0 },
    { offsetof(xfs_sb_t, sb_agblocks),   0 },
    { offsetof(xfs_sb_t, sb_agcount),    0 },
    { offsetof(xfs_sb_t, sb_rbmblocks),  0 },
    { offsetof(xfs_sb_t, sb_logblocks),  0 },
    { offsetof(xfs_sb_t, sb_versionnum), 0 },
    { offsetof(xfs_sb_t, sb_sectsize),   0 },
    { offsetof(xfs_sb_t, sb_inodesize),  0 },
    { offsetof(xfs_sb_t, sb_inopblock),  0 },
    { offsetof(xfs_sb_t, sb_fname[0]),   1 },
    { offsetof(xfs_sb_t, sb_blocklog),   0 },
    { offsetof(xfs_sb_t, sb_sectlog),    0 },
    { offsetof(xfs_sb_t, sb_inodelog),   0 },
    { offsetof(xfs_sb_t, sb_inopblog),   0 },
    { offsetof(xfs_sb_t, sb_agblklog),   0 },
    { offsetof(xfs_sb_t, sb_rextslog),   0 },
    { offsetof(xfs_sb_t, sb_inprogress), 0 },
    { offsetof(xfs_sb_t, sb_imax_pct),   0 },
    { offsetof(xfs_sb_t, sb_icount),     0 },
    { offsetof(xfs_sb_t, sb_ifree),      0 },
    { offsetof(xfs_sb_t, sb_fdblocks),   0 },
    { offsetof(xfs_sb_t, sb_frextents),  0 },
    { offsetof(xfs_sb_t, sb_uquotino),   0 },
    { offsetof(xfs_sb_t, sb_gquotino),   0 },
    { offsetof(xfs_sb_t, sb_qflags),     0 },
    { offsetof(xfs_sb_t, sb_flags),      0 },
    { offsetof(xfs_sb_t, sb_shared_vn),  0 },
    { offsetof(xfs_sb_t, sb_inoalignmt), 0 },
    { offsetof(xfs_sb_t, sb_unit),	 0 },
    { offsetof(xfs_sb_t, sb_width),	 0 },
    { offsetof(xfs_sb_t, sb_dirblklog),	 0 },
    { offsetof(xfs_sb_t, sb_logsectlog), 0 },
    { offsetof(xfs_sb_t, sb_logsectsize),0 },
    { offsetof(xfs_sb_t, sb_logsunit),	 0 },
    { offsetof(xfs_sb_t, sb_features2),	 0 },
113
    { offsetof(xfs_sb_t, sb_bad_features2), 0 },
114
115
116
    { offsetof(xfs_sb_t, sb_features_compat), 0 },
    { offsetof(xfs_sb_t, sb_features_ro_compat), 0 },
    { offsetof(xfs_sb_t, sb_features_incompat), 0 },
117
    { offsetof(xfs_sb_t, sb_features_log_incompat), 0 },
118
    { offsetof(xfs_sb_t, sb_crc),	 0 },
119
    { offsetof(xfs_sb_t, sb_pad),	 0 },
120
121
    { offsetof(xfs_sb_t, sb_pquotino),	 0 },
    { offsetof(xfs_sb_t, sb_lsn),	 0 },
Linus Torvalds's avatar
Linus Torvalds committed
122
123
124
    { sizeof(xfs_sb_t),			 0 }
};

Christoph Hellwig's avatar
Christoph Hellwig committed
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
static DEFINE_MUTEX(xfs_uuid_table_mutex);
static int xfs_uuid_table_size;
static uuid_t *xfs_uuid_table;

/*
 * See if the UUID is unique among mounted XFS filesystems.
 * Mount fails if UUID is nil or a FS with the same UUID is already mounted.
 */
STATIC int
xfs_uuid_mount(
	struct xfs_mount	*mp)
{
	uuid_t			*uuid = &mp->m_sb.sb_uuid;
	int			hole, i;

	if (mp->m_flags & XFS_MOUNT_NOUUID)
		return 0;

	if (uuid_is_nil(uuid)) {
144
		xfs_warn(mp, "Filesystem has nil UUID - can't mount");
Christoph Hellwig's avatar
Christoph Hellwig committed
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
		return XFS_ERROR(EINVAL);
	}

	mutex_lock(&xfs_uuid_table_mutex);
	for (i = 0, hole = -1; i < xfs_uuid_table_size; i++) {
		if (uuid_is_nil(&xfs_uuid_table[i])) {
			hole = i;
			continue;
		}
		if (uuid_equal(uuid, &xfs_uuid_table[i]))
			goto out_duplicate;
	}

	if (hole < 0) {
		xfs_uuid_table = kmem_realloc(xfs_uuid_table,
			(xfs_uuid_table_size + 1) * sizeof(*xfs_uuid_table),
			xfs_uuid_table_size  * sizeof(*xfs_uuid_table),
			KM_SLEEP);
		hole = xfs_uuid_table_size++;
	}
	xfs_uuid_table[hole] = *uuid;
	mutex_unlock(&xfs_uuid_table_mutex);

	return 0;

 out_duplicate:
	mutex_unlock(&xfs_uuid_table_mutex);
172
	xfs_warn(mp, "Filesystem has duplicate UUID %pU - can't mount", uuid);
Christoph Hellwig's avatar
Christoph Hellwig committed
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
	return XFS_ERROR(EINVAL);
}

STATIC void
xfs_uuid_unmount(
	struct xfs_mount	*mp)
{
	uuid_t			*uuid = &mp->m_sb.sb_uuid;
	int			i;

	if (mp->m_flags & XFS_MOUNT_NOUUID)
		return;

	mutex_lock(&xfs_uuid_table_mutex);
	for (i = 0; i < xfs_uuid_table_size; i++) {
		if (uuid_is_nil(&xfs_uuid_table[i]))
			continue;
		if (!uuid_equal(uuid, &xfs_uuid_table[i]))
			continue;
		memset(&xfs_uuid_table[i], 0, sizeof(uuid_t));
		break;
	}
	ASSERT(i < xfs_uuid_table_size);
	mutex_unlock(&xfs_uuid_table_mutex);
}


200
201
/*
 * Reference counting access wrappers to the perag structures.
Dave Chinner's avatar
Dave Chinner committed
202
203
 * Because we never free per-ag structures, the only thing we
 * have to protect against changes is the tree structure itself.
204
205
206
207
208
209
210
 */
struct xfs_perag *
xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno)
{
	struct xfs_perag	*pag;
	int			ref = 0;

Dave Chinner's avatar
Dave Chinner committed
211
	rcu_read_lock();
212
213
214
215
216
	pag = radix_tree_lookup(&mp->m_perag_tree, agno);
	if (pag) {
		ASSERT(atomic_read(&pag->pag_ref) >= 0);
		ref = atomic_inc_return(&pag->pag_ref);
	}
Dave Chinner's avatar
Dave Chinner committed
217
	rcu_read_unlock();
218
219
220
221
	trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
	return pag;
}

222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
/*
 * search from @first to find the next perag with the given tag set.
 */
struct xfs_perag *
xfs_perag_get_tag(
	struct xfs_mount	*mp,
	xfs_agnumber_t		first,
	int			tag)
{
	struct xfs_perag	*pag;
	int			found;
	int			ref;

	rcu_read_lock();
	found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
					(void **)&pag, first, 1, tag);
	if (found <= 0) {
		rcu_read_unlock();
		return NULL;
	}
	ref = atomic_inc_return(&pag->pag_ref);
	rcu_read_unlock();
	trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_);
	return pag;
}

248
249
250
251
252
253
254
255
256
257
void
xfs_perag_put(struct xfs_perag *pag)
{
	int	ref;

	ASSERT(atomic_read(&pag->pag_ref) > 0);
	ref = atomic_dec_return(&pag->pag_ref);
	trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
}

Dave Chinner's avatar
Dave Chinner committed
258
259
260
261
262
263
264
265
266
267
STATIC void
__xfs_free_perag(
	struct rcu_head	*head)
{
	struct xfs_perag *pag = container_of(head, struct xfs_perag, rcu_head);

	ASSERT(atomic_read(&pag->pag_ref) == 0);
	kmem_free(pag);
}

Linus Torvalds's avatar
Linus Torvalds committed
268
/*
Dave Chinner's avatar
Dave Chinner committed
269
 * Free up the per-ag resources associated with the mount structure.
Linus Torvalds's avatar
Linus Torvalds committed
270
 */
Christoph Hellwig's avatar
Christoph Hellwig committed
271
STATIC void
272
xfs_free_perag(
273
	xfs_mount_t	*mp)
Linus Torvalds's avatar
Linus Torvalds committed
274
{
275
276
277
278
279
280
281
	xfs_agnumber_t	agno;
	struct xfs_perag *pag;

	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
		spin_lock(&mp->m_perag_lock);
		pag = radix_tree_delete(&mp->m_perag_tree, agno);
		spin_unlock(&mp->m_perag_lock);
Dave Chinner's avatar
Dave Chinner committed
282
		ASSERT(pag);
283
		ASSERT(atomic_read(&pag->pag_ref) == 0);
Dave Chinner's avatar
Dave Chinner committed
284
		call_rcu(&pag->rcu_head, __xfs_free_perag);
Linus Torvalds's avatar
Linus Torvalds committed
285
286
287
	}
}

288
289
290
291
292
293
294
295
296
297
298
299
300
301
/*
 * Check size of device based on the (data/realtime) block count.
 * Note: this check is used by the growfs code as well as mount.
 */
int
xfs_sb_validate_fsb_count(
	xfs_sb_t	*sbp,
	__uint64_t	nblocks)
{
	ASSERT(PAGE_SHIFT >= sbp->sb_blocklog);
	ASSERT(sbp->sb_blocklog >= BBSHIFT);

#if XFS_BIG_BLKNOS     /* Limited by ULONG_MAX of page cache index */
	if (nblocks >> (PAGE_CACHE_SHIFT - sbp->sb_blocklog) > ULONG_MAX)
302
		return EFBIG;
303
304
#else                  /* Limited by UINT_MAX of sectors */
	if (nblocks << (sbp->sb_blocklog - BBSHIFT) > UINT_MAX)
305
		return EFBIG;
306
307
308
#endif
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
309
310
311
312
313
314
315

/*
 * Check the validity of the SB found.
 */
STATIC int
xfs_mount_validate_sb(
	xfs_mount_t	*mp,
316
	xfs_sb_t	*sbp,
317
318
	bool		check_inprogress,
	bool		check_version)
Linus Torvalds's avatar
Linus Torvalds committed
319
{
320

Linus Torvalds's avatar
Linus Torvalds committed
321
322
323
324
325
326
327
328
	/*
	 * If the log device and data device have the
	 * same device number, the log is internal.
	 * Consequently, the sb_logstart should be non-zero.  If
	 * we have a zero sb_logstart in this case, we may be trying to mount
	 * a volume filesystem in a non-volume manner.
	 */
	if (sbp->sb_magicnum != XFS_SB_MAGIC) {
329
		xfs_warn(mp, "bad magic number");
Linus Torvalds's avatar
Linus Torvalds committed
330
331
332
		return XFS_ERROR(EWRONGFS);
	}

333

334
	if (!xfs_sb_good_version(sbp)) {
335
		xfs_warn(mp, "bad version");
Linus Torvalds's avatar
Linus Torvalds committed
336
337
338
		return XFS_ERROR(EWRONGFS);
	}

339
	/*
340
	 * Version 5 superblock feature mask validation. Reject combinations the
341
342
	 * kernel cannot support up front before checking anything else. For
	 * write validation, we don't need to check feature masks.
343
	 */
344
	if (check_version && XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) {
345
		xfs_alert(mp,
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
"Version 5 superblock detected. This kernel has EXPERIMENTAL support enabled!\n"
"Use of these features in this kernel is at your own risk!");

		if (xfs_sb_has_compat_feature(sbp,
					XFS_SB_FEAT_COMPAT_UNKNOWN)) {
			xfs_warn(mp,
"Superblock has unknown compatible features (0x%x) enabled.\n"
"Using a more recent kernel is recommended.",
				(sbp->sb_features_compat &
						XFS_SB_FEAT_COMPAT_UNKNOWN));
		}

		if (xfs_sb_has_ro_compat_feature(sbp,
					XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) {
			xfs_alert(mp,
"Superblock has unknown read-only compatible features (0x%x) enabled.",
				(sbp->sb_features_ro_compat &
						XFS_SB_FEAT_RO_COMPAT_UNKNOWN));
			if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
				xfs_warn(mp,
"Attempted to mount read-only compatible filesystem read-write.\n"
"Filesystem can only be safely mounted read only.");
				return XFS_ERROR(EINVAL);
			}
		}
		if (xfs_sb_has_incompat_feature(sbp,
					XFS_SB_FEAT_INCOMPAT_UNKNOWN)) {
			xfs_warn(mp,
"Superblock has unknown incompatible features (0x%x) enabled.\n"
"Filesystem can not be safely mounted by this kernel.",
				(sbp->sb_features_incompat &
						XFS_SB_FEAT_INCOMPAT_UNKNOWN));
			return XFS_ERROR(EINVAL);
		}
380
381
	}

Linus Torvalds's avatar
Linus Torvalds committed
382
383
	if (unlikely(
	    sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) {
384
		xfs_warn(mp,
385
386
		"filesystem is marked as having an external log; "
		"specify logdev on the mount command line.");
387
		return XFS_ERROR(EINVAL);
Linus Torvalds's avatar
Linus Torvalds committed
388
389
390
391
	}

	if (unlikely(
	    sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) {
392
		xfs_warn(mp,
393
394
		"filesystem is marked as having an internal log; "
		"do not specify logdev on the mount command line.");
395
		return XFS_ERROR(EINVAL);
Linus Torvalds's avatar
Linus Torvalds committed
396
397
398
	}

	/*
399
	 * More sanity checking.  Most of these were stolen directly from
Linus Torvalds's avatar
Linus Torvalds committed
400
401
402
403
404
405
406
407
	 * xfs_repair.
	 */
	if (unlikely(
	    sbp->sb_agcount <= 0					||
	    sbp->sb_sectsize < XFS_MIN_SECTORSIZE			||
	    sbp->sb_sectsize > XFS_MAX_SECTORSIZE			||
	    sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG			||
	    sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG			||
408
	    sbp->sb_sectsize != (1 << sbp->sb_sectlog)			||
Linus Torvalds's avatar
Linus Torvalds committed
409
410
411
412
	    sbp->sb_blocksize < XFS_MIN_BLOCKSIZE			||
	    sbp->sb_blocksize > XFS_MAX_BLOCKSIZE			||
	    sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG			||
	    sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG			||
413
	    sbp->sb_blocksize != (1 << sbp->sb_blocklog)		||
Linus Torvalds's avatar
Linus Torvalds committed
414
415
	    sbp->sb_inodesize < XFS_DINODE_MIN_SIZE			||
	    sbp->sb_inodesize > XFS_DINODE_MAX_SIZE			||
416
417
	    sbp->sb_inodelog < XFS_DINODE_MIN_LOG			||
	    sbp->sb_inodelog > XFS_DINODE_MAX_LOG			||
418
	    sbp->sb_inodesize != (1 << sbp->sb_inodelog)		||
419
	    (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog)	||
Linus Torvalds's avatar
Linus Torvalds committed
420
421
	    (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE)	||
	    (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE)	||
422
423
424
425
	    (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */)	||
	    sbp->sb_dblocks == 0					||
	    sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp)			||
	    sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))) {
426
		XFS_CORRUPTION_ERROR("SB sanity check failed",
427
				XFS_ERRLEVEL_LOW, mp, sbp);
Linus Torvalds's avatar
Linus Torvalds committed
428
429
430
		return XFS_ERROR(EFSCORRUPTED);
	}

431
432
433
434
	/*
	 * Until this is fixed only page-sized or smaller data blocks work.
	 */
	if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) {
435
		xfs_warn(mp,
436
437
438
		"File system with blocksize %d bytes. "
		"Only pagesize (%ld) or less will currently work.",
				sbp->sb_blocksize, PAGE_SIZE);
439
440
441
		return XFS_ERROR(ENOSYS);
	}

Christoph Hellwig's avatar
Christoph Hellwig committed
442
443
444
445
446
447
448
449
450
451
	/*
	 * Currently only very few inode sizes are supported.
	 */
	switch (sbp->sb_inodesize) {
	case 256:
	case 512:
	case 1024:
	case 2048:
		break;
	default:
452
		xfs_warn(mp, "inode size of %d bytes not supported",
453
				sbp->sb_inodesize);
Christoph Hellwig's avatar
Christoph Hellwig committed
454
455
456
		return XFS_ERROR(ENOSYS);
	}

457
458
	if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) ||
	    xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) {
459
		xfs_warn(mp,
460
		"file system too large to be mounted on this system.");
461
		return XFS_ERROR(EFBIG);
Linus Torvalds's avatar
Linus Torvalds committed
462
463
	}

464
465
	if (check_inprogress && sbp->sb_inprogress) {
		xfs_warn(mp, "Offline file system operation in progress!");
Linus Torvalds's avatar
Linus Torvalds committed
466
467
468
		return XFS_ERROR(EFSCORRUPTED);
	}

469
470
471
	/*
	 * Version 1 directory format has never worked on Linux.
	 */
472
	if (unlikely(!xfs_sb_version_hasdirv2(sbp))) {
473
		xfs_warn(mp, "file system using version 1 directory format");
474
475
476
		return XFS_ERROR(ENOSYS);
	}

Linus Torvalds's avatar
Linus Torvalds committed
477
478
479
	return 0;
}

480
int
481
482
xfs_initialize_perag(
	xfs_mount_t	*mp,
483
484
	xfs_agnumber_t	agcount,
	xfs_agnumber_t	*maxagi)
Linus Torvalds's avatar
Linus Torvalds committed
485
{
486
	xfs_agnumber_t	index;
487
	xfs_agnumber_t	first_initialised = 0;
Linus Torvalds's avatar
Linus Torvalds committed
488
489
490
491
	xfs_perag_t	*pag;
	xfs_agino_t	agino;
	xfs_ino_t	ino;
	xfs_sb_t	*sbp = &mp->m_sb;
492
	int		error = -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
493

494
495
496
497
498
499
500
501
502
503
504
	/*
	 * Walk the current per-ag tree so we don't try to initialise AGs
	 * that already exist (growfs case). Allocate and insert all the
	 * AGs we don't find ready for initialisation.
	 */
	for (index = 0; index < agcount; index++) {
		pag = xfs_perag_get(mp, index);
		if (pag) {
			xfs_perag_put(pag);
			continue;
		}
505
506
		if (!first_initialised)
			first_initialised = index;
507

508
509
		pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL);
		if (!pag)
510
			goto out_unwind;
511
512
		pag->pag_agno = index;
		pag->pag_mount = mp;
513
		spin_lock_init(&pag->pag_ici_lock);
514
		mutex_init(&pag->pag_ici_reclaim_lock);
515
		INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
516
517
		spin_lock_init(&pag->pag_buf_lock);
		pag->pag_buf_tree = RB_ROOT;
518

519
		if (radix_tree_preload(GFP_NOFS))
520
			goto out_unwind;
521

522
523
524
525
		spin_lock(&mp->m_perag_lock);
		if (radix_tree_insert(&mp->m_perag_tree, index, pag)) {
			BUG();
			spin_unlock(&mp->m_perag_lock);
526
527
528
			radix_tree_preload_end();
			error = -EEXIST;
			goto out_unwind;
529
530
531
532
533
		}
		spin_unlock(&mp->m_perag_lock);
		radix_tree_preload_end();
	}

534
535
536
	/*
	 * If we mount with the inode64 option, or no inode overflows
	 * the legacy 32-bit address space clear the inode32 option.
Linus Torvalds's avatar
Linus Torvalds committed
537
	 */
538
539
540
541
	agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0);
	ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino);

	if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > XFS_MAXINUMBER_32)
Linus Torvalds's avatar
Linus Torvalds committed
542
		mp->m_flags |= XFS_MOUNT_32BITINODES;
543
	else
Linus Torvalds's avatar
Linus Torvalds committed
544
545
		mp->m_flags &= ~XFS_MOUNT_32BITINODES;

546
547
548
549
	if (mp->m_flags & XFS_MOUNT_32BITINODES)
		index = xfs_set_inode32(mp);
	else
		index = xfs_set_inode64(mp);
550

551
552
553
	if (maxagi)
		*maxagi = index;
	return 0;
554
555
556
557
558
559
560
561

out_unwind:
	kmem_free(pag);
	for (; index > first_initialised; index--) {
		pag = radix_tree_delete(&mp->m_perag_tree, index);
		kmem_free(pag);
	}
	return error;
Linus Torvalds's avatar
Linus Torvalds committed
562
563
}

564
565
void
xfs_sb_from_disk(
566
	struct xfs_sb	*to,
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
	xfs_dsb_t	*from)
{
	to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
	to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
	to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
	to->sb_rblocks = be64_to_cpu(from->sb_rblocks);
	to->sb_rextents = be64_to_cpu(from->sb_rextents);
	memcpy(&to->sb_uuid, &from->sb_uuid, sizeof(to->sb_uuid));
	to->sb_logstart = be64_to_cpu(from->sb_logstart);
	to->sb_rootino = be64_to_cpu(from->sb_rootino);
	to->sb_rbmino = be64_to_cpu(from->sb_rbmino);
	to->sb_rsumino = be64_to_cpu(from->sb_rsumino);
	to->sb_rextsize = be32_to_cpu(from->sb_rextsize);
	to->sb_agblocks = be32_to_cpu(from->sb_agblocks);
	to->sb_agcount = be32_to_cpu(from->sb_agcount);
	to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks);
	to->sb_logblocks = be32_to_cpu(from->sb_logblocks);
	to->sb_versionnum = be16_to_cpu(from->sb_versionnum);
	to->sb_sectsize = be16_to_cpu(from->sb_sectsize);
	to->sb_inodesize = be16_to_cpu(from->sb_inodesize);
	to->sb_inopblock = be16_to_cpu(from->sb_inopblock);
	memcpy(&to->sb_fname, &from->sb_fname, sizeof(to->sb_fname));
	to->sb_blocklog = from->sb_blocklog;
	to->sb_sectlog = from->sb_sectlog;
	to->sb_inodelog = from->sb_inodelog;
	to->sb_inopblog = from->sb_inopblog;
	to->sb_agblklog = from->sb_agblklog;
	to->sb_rextslog = from->sb_rextslog;
	to->sb_inprogress = from->sb_inprogress;
	to->sb_imax_pct = from->sb_imax_pct;
	to->sb_icount = be64_to_cpu(from->sb_icount);
	to->sb_ifree = be64_to_cpu(from->sb_ifree);
	to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks);
	to->sb_frextents = be64_to_cpu(from->sb_frextents);
	to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
	to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
	to->sb_qflags = be16_to_cpu(from->sb_qflags);
	to->sb_flags = from->sb_flags;
	to->sb_shared_vn = from->sb_shared_vn;
	to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt);
	to->sb_unit = be32_to_cpu(from->sb_unit);
	to->sb_width = be32_to_cpu(from->sb_width);
	to->sb_dirblklog = from->sb_dirblklog;
	to->sb_logsectlog = from->sb_logsectlog;
	to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize);
	to->sb_logsunit = be32_to_cpu(from->sb_logsunit);
	to->sb_features2 = be32_to_cpu(from->sb_features2);
614
	to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2);
615
616
617
	to->sb_features_compat = be32_to_cpu(from->sb_features_compat);
	to->sb_features_ro_compat = be32_to_cpu(from->sb_features_ro_compat);
	to->sb_features_incompat = be32_to_cpu(from->sb_features_incompat);
618
619
620
	to->sb_features_log_incompat =
				be32_to_cpu(from->sb_features_log_incompat);
	to->sb_pad = 0;
621
622
	to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
	to->sb_lsn = be64_to_cpu(from->sb_lsn);
623
624
}

Linus Torvalds's avatar
Linus Torvalds committed
625
/*
626
 * Copy in core superblock to ondisk one.
Linus Torvalds's avatar
Linus Torvalds committed
627
 *
628
 * The fields argument is mask of superblock fields to copy.
Linus Torvalds's avatar
Linus Torvalds committed
629
630
 */
void
631
632
633
xfs_sb_to_disk(
	xfs_dsb_t	*to,
	xfs_sb_t	*from,
Linus Torvalds's avatar
Linus Torvalds committed
634
635
	__int64_t	fields)
{
636
637
	xfs_caddr_t	to_ptr = (xfs_caddr_t)to;
	xfs_caddr_t	from_ptr = (xfs_caddr_t)from;
Linus Torvalds's avatar
Linus Torvalds committed
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
	xfs_sb_field_t	f;
	int		first;
	int		size;

	ASSERT(fields);
	if (!fields)
		return;

	while (fields) {
		f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
		first = xfs_sb_info[f].offset;
		size = xfs_sb_info[f + 1].offset - first;

		ASSERT(xfs_sb_info[f].type == 0 || xfs_sb_info[f].type == 1);

		if (size == 1 || xfs_sb_info[f].type == 1) {
654
			memcpy(to_ptr + first, from_ptr + first, size);
Linus Torvalds's avatar
Linus Torvalds committed
655
656
657
		} else {
			switch (size) {
			case 2:
658
659
				*(__be16 *)(to_ptr + first) =
					cpu_to_be16(*(__u16 *)(from_ptr + first));
Linus Torvalds's avatar
Linus Torvalds committed
660
661
				break;
			case 4:
662
663
				*(__be32 *)(to_ptr + first) =
					cpu_to_be32(*(__u32 *)(from_ptr + first));
Linus Torvalds's avatar
Linus Torvalds committed
664
665
				break;
			case 8:
666
667
				*(__be64 *)(to_ptr + first) =
					cpu_to_be64(*(__u64 *)(from_ptr + first));
Linus Torvalds's avatar
Linus Torvalds committed
668
669
670
671
672
673
674
675
676
677
				break;
			default:
				ASSERT(0);
			}
		}

		fields &= ~(1LL << f);
	}
}

678
static int
679
xfs_sb_verify(
680
681
	struct xfs_buf	*bp,
	bool		check_version)
682
683
684
685
686
687
688
689
690
691
{
	struct xfs_mount *mp = bp->b_target->bt_mount;
	struct xfs_sb	sb;

	xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp));

	/*
	 * Only check the in progress field for the primary superblock as
	 * mkfs.xfs doesn't clear it from secondary superblocks.
	 */
692
693
	return xfs_mount_validate_sb(mp, &sb, bp->b_bn == XFS_SB_DADDR,
				     check_version);
694
695
}

696
697
698
699
700
701
702
/*
 * If the superblock has the CRC feature bit set or the CRC field is non-null,
 * check that the CRC is valid.  We check the CRC field is non-null because a
 * single bit error could clear the feature bit and unused parts of the
 * superblock are supposed to be zero. Hence a non-null crc field indicates that
 * we've potentially lost a feature bit and we should check it anyway.
 */
703
static void
704
705
706
xfs_sb_read_verify(
	struct xfs_buf	*bp)
{
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
	struct xfs_mount *mp = bp->b_target->bt_mount;
	struct xfs_dsb	*dsb = XFS_BUF_TO_SBP(bp);
	int		error;

	/*
	 * open code the version check to avoid needing to convert the entire
	 * superblock from disk order just to check the version number
	 */
	if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC) &&
	    (((be16_to_cpu(dsb->sb_versionnum) & XFS_SB_VERSION_NUMBITS) ==
						XFS_SB_VERSION_5) ||
	     dsb->sb_crc != 0)) {

		if (!xfs_verify_cksum(bp->b_addr, be16_to_cpu(dsb->sb_sectsize),
				      offsetof(struct xfs_sb, sb_crc))) {
			error = EFSCORRUPTED;
			goto out_error;
		}
	}
726
	error = xfs_sb_verify(bp, true);
727
728
729
730
731
732

out_error:
	if (error) {
		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
		xfs_buf_ioerror(bp, error);
	}
733
734
735
736
737
738
739
740
}

/*
 * We may be probed for a filesystem match, so we may not want to emit
 * messages when the superblock buffer is not actually an XFS superblock.
 * If we find an XFS superblock, the run a normal, noisy mount because we are
 * really going to mount it and want to know about errors.
 */
741
static void
742
743
744
xfs_sb_quiet_read_verify(
	struct xfs_buf	*bp)
{
745
	struct xfs_dsb	*dsb = XFS_BUF_TO_SBP(bp);
746
747


748
	if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC)) {
749
750
751
752
753
		/* XFS filesystem, verify noisily! */
		xfs_sb_read_verify(bp);
		return;
	}
	/* quietly fail */
754
	xfs_buf_ioerror(bp, EWRONGFS);
755
756
}

757
758
static void
xfs_sb_write_verify(
759
	struct xfs_buf		*bp)
760
{
761
762
763
764
	struct xfs_mount	*mp = bp->b_target->bt_mount;
	struct xfs_buf_log_item	*bip = bp->b_fspriv;
	int			error;

765
	error = xfs_sb_verify(bp, false);
766
767
768
769
770
771
772
773
774
775
776
777
778
779
	if (error) {
		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
		xfs_buf_ioerror(bp, error);
		return;
	}

	if (!xfs_sb_version_hascrc(&mp->m_sb))
		return;

	if (bip)
		XFS_BUF_TO_SBP(bp)->sb_lsn = cpu_to_be64(bip->bli_item.li_lsn);

	xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
			 offsetof(struct xfs_sb, sb_crc));
780
781
782
783
784
785
786
787
788
789
790
791
}

const struct xfs_buf_ops xfs_sb_buf_ops = {
	.verify_read = xfs_sb_read_verify,
	.verify_write = xfs_sb_write_verify,
};

static const struct xfs_buf_ops xfs_sb_quiet_buf_ops = {
	.verify_read = xfs_sb_quiet_read_verify,
	.verify_write = xfs_sb_write_verify,
};

Linus Torvalds's avatar
Linus Torvalds committed
792
793
794
795
796
797
/*
 * xfs_readsb
 *
 * Does the initial read of the superblock.
 */
int
798
xfs_readsb(xfs_mount_t *mp, int flags)
Linus Torvalds's avatar
Linus Torvalds committed
799
800
{
	unsigned int	sector_size;
801
802
	struct xfs_buf	*bp;
	struct xfs_sb	*sbp = &mp->m_sb;
Linus Torvalds's avatar
Linus Torvalds committed
803
	int		error;
804
	int		loud = !(flags & XFS_MFSI_QUIET);
Linus Torvalds's avatar
Linus Torvalds committed
805
806
807
808
809
810
811
812
813
814

	ASSERT(mp->m_sb_bp == NULL);
	ASSERT(mp->m_ddev_targp != NULL);

	/*
	 * Allocate a (locked) buffer to hold the superblock.
	 * This will be kept around at all times to optimize
	 * access to the superblock.
	 */
	sector_size = xfs_getsize_buftarg(mp->m_ddev_targp);
815
816

reread:
817
	bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR,
818
				   BTOBB(sector_size), 0,
819
820
				   loud ? &xfs_sb_buf_ops
				        : &xfs_sb_quiet_buf_ops);
821
	if (!bp) {
822
823
		if (loud)
			xfs_warn(mp, "SB buffer read failed");
824
		return EIO;
Linus Torvalds's avatar
Linus Torvalds committed
825
	}
826
827
828
	if (bp->b_error) {
		error = bp->b_error;
		if (loud)
829
			xfs_warn(mp, "SB validate failed with error %d.", error);
830
831
		goto release_buf;
	}
Linus Torvalds's avatar
Linus Torvalds committed
832
833
834
835

	/*
	 * Initialize the mount structure from the superblock.
	 */
836
	xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp));
Linus Torvalds's avatar
Linus Torvalds committed
837
838
839
840

	/*
	 * We must be able to do sector-sized and sector-aligned IO.
	 */
841
	if (sector_size > sbp->sb_sectsize) {
842
843
		if (loud)
			xfs_warn(mp, "device supports %u byte sectors (not %u)",
844
				sector_size, sbp->sb_sectsize);
Linus Torvalds's avatar
Linus Torvalds committed
845
		error = ENOSYS;
846
		goto release_buf;
Linus Torvalds's avatar
Linus Torvalds committed
847
848
849
850
851
852
	}

	/*
	 * If device sector size is smaller than the superblock size,
	 * re-read the superblock so the buffer is correctly sized.
	 */
853
	if (sector_size < sbp->sb_sectsize) {
Linus Torvalds's avatar
Linus Torvalds committed
854
		xfs_buf_relse(bp);
855
		sector_size = sbp->sb_sectsize;
856
		goto reread;
Linus Torvalds's avatar
Linus Torvalds committed
857
858
	}

859
860
	/* Initialize per-cpu counters */
	xfs_icsb_reinit_counters(mp);
861

862
863
864
	/* no need to be quiet anymore, so reset the buf ops */
	bp->b_ops = &xfs_sb_buf_ops;

Linus Torvalds's avatar
Linus Torvalds committed
865
	mp->m_sb_bp = bp;
866
	xfs_buf_unlock(bp);
Linus Torvalds's avatar
Linus Torvalds committed
867
868
	return 0;

869
870
release_buf:
	xfs_buf_relse(bp);
Linus Torvalds's avatar
Linus Torvalds committed
871
872
873
874
875
876
877
878
879
880
881
	return error;
}


/*
 * xfs_mount_common
 *
 * Mount initialization code establishing various mount
 * fields from the superblock associated with the given
 * mount structure
 */
882
STATIC void
Linus Torvalds's avatar
Linus Torvalds committed
883
884
885
xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp)
{
	mp->m_agfrotor = mp->m_agirotor = 0;
Eric Sandeen's avatar
Eric Sandeen committed
886
	spin_lock_init(&mp->m_agirotor_lock);
Linus Torvalds's avatar
Linus Torvalds committed
887
888
889
890
891
892
893
894
895
896
	mp->m_maxagi = mp->m_sb.sb_agcount;
	mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG;
	mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;
	mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;
	mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1;
	mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog;
	mp->m_blockmask = sbp->sb_blocksize - 1;
	mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG;
	mp->m_blockwmask = mp->m_blockwsize - 1;

897
898
899
900
901
902
903
904
905
906
907
908
909
910
	mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1);
	mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0);
	mp->m_alloc_mnr[0] = mp->m_alloc_mxr[0] / 2;
	mp->m_alloc_mnr[1] = mp->m_alloc_mxr[1] / 2;

	mp->m_inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 1);
	mp->m_inobt_mxr[1] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 0);
	mp->m_inobt_mnr[0] = mp->m_inobt_mxr[0] / 2;
	mp->m_inobt_mnr[1] = mp->m_inobt_mxr[1] / 2;

	mp->m_bmap_dmxr[0] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 1);
	mp->m_bmap_dmxr[1] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 0);
	mp->m_bmap_dmnr[0] = mp->m_bmap_dmxr[0] / 2;
	mp->m_bmap_dmnr[1] = mp->m_bmap_dmxr[1] / 2;
Linus Torvalds's avatar
Linus Torvalds committed
911
912
913
914
915
916

	mp->m_bsize = XFS_FSB_TO_BB(mp, 1);
	mp->m_ialloc_inos = (int)MAX((__uint16_t)XFS_INODES_PER_CHUNK,
					sbp->sb_inopblock);
	mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog;
}
David Chinner's avatar
David Chinner committed
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941

/*
 * xfs_initialize_perag_data
 *
 * Read in each per-ag structure so we can count up the number of
 * allocated inodes, free inodes and used filesystem blocks as this
 * information is no longer persistent in the superblock. Once we have
 * this information, write it into the in-core superblock structure.
 */
STATIC int
xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount)
{
	xfs_agnumber_t	index;
	xfs_perag_t	*pag;
	xfs_sb_t	*sbp = &mp->m_sb;
	uint64_t	ifree = 0;
	uint64_t	ialloc = 0;
	uint64_t	bfree = 0;
	uint64_t	bfreelst = 0;
	uint64_t	btree = 0;
	int		error;

	for (index = 0; index < agcount; index++) {
		/*
		 * read the agf, then the agi. This gets us
Malcolm Parsons's avatar
Malcolm Parsons committed
942
		 * all the information we need and populates the
David Chinner's avatar
David Chinner committed
943
944
945
946
947
948
949
950
951
		 * per-ag structures for us.
		 */
		error = xfs_alloc_pagf_init(mp, NULL, index, 0);
		if (error)
			return error;

		error = xfs_ialloc_pagi_init(mp, NULL, index);
		if (error)
			return error;
952
		pag = xfs_perag_get(mp, index);
David Chinner's avatar
David Chinner committed
953
954
955
956
957
		ifree += pag->pagi_freecount;
		ialloc += pag->pagi_count;
		bfree += pag->pagf_freeblks;
		bfreelst += pag->pagf_flcount;
		btree += pag->pagf_btreeblks;
958
		xfs_perag_put(pag);
David Chinner's avatar
David Chinner committed
959
960
961
962
	}
	/*
	 * Overwrite incore superblock counters with just-read data
	 */
Eric Sandeen's avatar
Eric Sandeen committed
963
	spin_lock(&mp->m_sb_lock);
David Chinner's avatar
David Chinner committed
964
965
966
	sbp->sb_ifree = ifree;
	sbp->sb_icount = ialloc;
	sbp->sb_fdblocks = bfree + bfreelst + btree;
Eric Sandeen's avatar
Eric Sandeen committed
967
	spin_unlock(&mp->m_sb_lock);
David Chinner's avatar
David Chinner committed
968
969
970
971
972
973
974

	/* Fixup the per-cpu counters as well. */
	xfs_icsb_reinit_counters(mp);

	return 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
975
/*
Eric Sandeen's avatar
Eric Sandeen committed
976
 * Update alignment values based on mount options and sb values
Linus Torvalds's avatar
Linus Torvalds committed
977
 */
Eric Sandeen's avatar
Eric Sandeen committed
978
STATIC int
979
xfs_update_alignment(xfs_mount_t *mp)
Linus Torvalds's avatar
Linus Torvalds committed
980
981
982
{
	xfs_sb_t	*sbp = &(mp->m_sb);

Christoph Hellwig's avatar
Christoph Hellwig committed
983
	if (mp->m_dalign) {
Linus Torvalds's avatar
Linus Torvalds committed
984
985
986
987
988
989
990
		/*
		 * If stripe unit and stripe width are not multiples
		 * of the fs blocksize turn off alignment.
		 */
		if ((BBTOB(mp->m_dalign) & mp->m_blockmask) ||
		    (BBTOB(mp->m_swidth) & mp->m_blockmask)) {
			if (mp->m_flags & XFS_MOUNT_RETERR) {
991
992
				xfs_warn(mp, "alignment check failed: "
					 "(sunit/swidth vs. blocksize)");
Eric Sandeen's avatar
Eric Sandeen committed
993
				return XFS_ERROR(EINVAL);
Linus Torvalds's avatar
Linus Torvalds committed
994
995
996
997
998
999
1000
1001
1002
			}
			mp->m_dalign = mp->m_swidth = 0;
		} else {
			/*
			 * Convert the stripe unit and width to FSBs.
			 */
			mp->m_dalign = XFS_BB_TO_FSBT(mp, mp->m_dalign);
			if (mp->m_dalign && (sbp->sb_agblocks % mp->m_dalign)) {
				if (mp->m_flags & XFS_MOUNT_RETERR) {
1003
1004
					xfs_warn(mp, "alignment check failed: "
						 "(sunit/swidth vs. ag size)");
Eric Sandeen's avatar
Eric Sandeen committed
1005
					return XFS_ERROR(EINVAL);
Linus Torvalds's avatar
Linus Torvalds committed
1006
				}
1007
1008
1009
				xfs_warn(mp,
		"stripe alignment turned off: sunit(%d)/swidth(%d) "
		"incompatible with agsize(%d)",
Linus Torvalds's avatar
Linus Torvalds committed
1010
1011
1012
1013
1014
1015
1016
1017
1018
					mp->m_dalign, mp->m_swidth,
					sbp->sb_agblocks);

				mp->m_dalign = 0;
				mp->m_swidth = 0;
			} else if (mp->m_dalign) {
				mp->m_swidth = XFS_BB_TO_FSBT(mp, mp->m_swidth);
			} else {
				if (mp->m_flags & XFS_MOUNT_RETERR) {
1019
1020
					xfs_warn(mp, "alignment check failed: "
						"sunit(%d) less than bsize(%d)",
1021
						mp->m_dalign,
Linus Torvalds's avatar
Linus Torvalds committed
1022
						mp->m_blockmask +1);
Eric Sandeen's avatar
Eric Sandeen committed
1023
					return XFS_ERROR(EINVAL);
Linus Torvalds's avatar
Linus Torvalds committed
1024
1025
1026
1027
1028
1029
1030
1031
1032
				}
				mp->m_swidth = 0;
			}
		}

		/*
		 * Update superblock with new values
		 * and log changes
		 */
1033
		if (xfs_sb_version_hasdalign(sbp)) {
Linus Torvalds's avatar
Linus Torvalds committed
1034
1035
			if (sbp->sb_unit != mp->m_dalign) {
				sbp->sb_unit = mp->m_dalign;
1036
				mp->m_update_flags |= XFS_SB_UNIT;
Linus Torvalds's avatar
Linus Torvalds committed
1037
1038
1039
			}
			if (sbp->sb_width != mp->m_swidth) {
				sbp->sb_width = mp->m_swidth;
1040
				mp->m_update_flags |= XFS_SB_WIDTH;
Linus Torvalds's avatar
Linus Torvalds committed
1041
1042
1043
			}
		}
	} else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN &&
1044
		    xfs_sb_version_hasdalign(&mp->m_sb)) {
Linus Torvalds's avatar
Linus Torvalds committed
1045
1046
1047
1048
			mp->m_dalign = sbp->sb_unit;
			mp->m_swidth = sbp->sb_width;
	}

Eric Sandeen's avatar
Eric Sandeen committed
1049
1050
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
1051

Eric Sandeen's avatar
Eric Sandeen committed
1052
1053
1054
1055
1056
1057
1058
1059
/*
 * Set the maximum inode count for this filesystem
 */
STATIC void
xfs_set_maxicount(xfs_mount_t *mp)
{
	xfs_sb_t	*sbp = &(mp->m_sb);
	__uint64_t	icount;
Linus Torvalds's avatar
Linus Torvalds committed
1060

Eric Sandeen's avatar
Eric Sandeen committed
1061
1062
1063
1064
	if (sbp->sb_imax_pct) {
		/*
		 * Make sure the maximum inode count is a multiple
		 * of the units we allocate inodes in.
Linus Torvalds's avatar
Linus Torvalds committed
1065
1066
1067
1068
1069
1070
		 */
		icount = sbp->sb_dblocks * sbp->sb_imax_pct;
		do_div(icount, 100);
		do_div(icount, mp->m_ialloc_blks);
		mp->m_maxicount = (icount * mp->m_ialloc_blks)  <<
				   sbp->sb_inopblog;
Eric Sandeen's avatar
Eric Sandeen committed
1071
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
1072
1073
		mp->m_maxicount = 0;
	}
Eric Sandeen's avatar
Eric Sandeen committed
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
}

/*
 * Set the default minimum read and write sizes unless
 * already specified in a mount option.
 * We use smaller I/O sizes when the file system
 * is being used for NFS service (wsync mount option).
 */
STATIC void
xfs_set_rw_sizes(xfs_mount_t *mp)
{
	xfs_sb_t	*sbp = &(mp->m_sb);
	int		readio_log, writeio_log;
Linus Torvalds's avatar
Linus Torvalds committed
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112

	if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)) {
		if (mp->m_flags & XFS_MOUNT_WSYNC) {
			readio_log = XFS_WSYNC_READIO_LOG;
			writeio_log = XFS_WSYNC_WRITEIO_LOG;
		} else {
			readio_log = XFS_READIO_LOG_LARGE;
			writeio_log = XFS_WRITEIO_LOG_LARGE;
		}
	} else {
		readio_log = mp->m_readio_log;
		writeio_log = mp->m_writeio_log;
	}

	if (sbp->sb_blocklog > readio_log) {
		mp->m_readio_log = sbp->sb_blocklog;
	} else {
		mp->m_readio_log = readio_log;
	}
	mp->m_readio_blocks = 1 << (mp->m_readio_log - sbp->sb_blocklog);
	if (sbp->sb_blocklog > writeio_log) {
		mp->m_writeio_log = sbp->sb_blocklog;
	} else {
		mp->m_writeio_log = writeio_log;
	}
	mp->m_writeio_blocks = 1 << (mp->m_writeio_log - sbp->sb_blocklog);
Eric Sandeen's avatar
Eric Sandeen committed
1113
}
Linus Torvalds's avatar
Linus Torvalds committed
1114

1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
/*
 * precalculate the low space thresholds for dynamic speculative preallocation.
 */
void
xfs_set_low_space_thresholds(
	struct xfs_mount	*mp)
{
	int i;

	for (i = 0; i < XFS_LOWSP_MAX; i++) {
		__uint64_t space = mp->m_sb.sb_dblocks;

		do_div(space, 100);
		mp->m_low_space[i] = space * (i + 1);
	}
}


Eric Sandeen's avatar
Eric Sandeen committed
1133
1134
1135
1136
1137
1138
/*
 * Set whether we're using inode alignment.
 */
STATIC void
xfs_set_inoalignment(xfs_mount_t *mp)
{
1139
	if (xfs_sb_version_hasalign(&mp->m_sb) &&
Linus Torvalds's avatar
Linus Torvalds committed
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
	    mp->m_sb.sb_inoalignmt >=
	    XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size))
		mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1;
	else
		mp->m_inoalign_mask = 0;
	/*
	 * If we are using stripe alignment, check whether
	 * the stripe unit is a multiple of the inode alignment
	 */
	if (mp->m_dalign && mp->m_inoalign_mask &&
	    !(mp->m_dalign & mp->m_inoalign_mask))
		mp->m_sinoalign = mp->m_dalign;
	else
		mp->m_sinoalign = 0;
Eric Sandeen's avatar
Eric Sandeen committed
1154
1155
1156
1157
1158
1159
}

/*
 * Check that the data (and log if separate) are an ok size.
 */
STATIC int
Christoph Hellwig's avatar
Christoph Hellwig committed
1160
xfs_check_sizes(xfs_mount_t *mp)
Eric Sandeen's avatar
Eric Sandeen committed
1161
1162
1163
1164
{
	xfs_buf_t	*bp;
	xfs_daddr_t	d;

Linus Torvalds's avatar
Linus Torvalds committed
1165
1166
	d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
	if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) {
1167
		xfs_warn(mp, "filesystem size mismatch detected");
1168
		return XFS_ERROR(EFBIG);
Linus Torvalds's avatar
Linus Torvalds committed
1169
	}
1170
	bp = xfs_buf_read_uncached(mp->m_ddev_targp,
1171
					d - XFS_FSS_TO_BB(mp, 1),
1172
					XFS_FSS_TO_BB(mp, 1), 0, NULL);
1173
	if (!bp) {
1174
		xfs_warn(mp, "last sector read failed");
1175
		return EIO;
Linus Torvalds's avatar
Linus Torvalds committed
1176
	}
1177
	xfs_buf_relse(bp);
Linus Torvalds's avatar
Linus Torvalds committed
1178

Christoph Hellwig's avatar
Christoph Hellwig committed
1179
	if (mp->m_logdev_targp != mp->m_ddev_targp) {
Linus Torvalds's avatar
Linus Torvalds committed
1180
1181
		d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
		if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) {
1182
			xfs_warn(mp, "log size mismatch detected");
1183
			return XFS_ERROR(EFBIG);
Linus Torvalds's avatar
Linus Torvalds committed
1184
		}
1185
		bp = xfs_buf_read_uncached(mp->m_logdev_targp,
1186
					d - XFS_FSB_TO_BB(mp, 1),
1187
					XFS_FSB_TO_BB(mp, 1), 0, NULL);
1188
		if (!bp) {
1189
			xfs_warn(mp, "log device read failed");
1190
			return EIO;
Eric Sandeen's avatar
Eric Sandeen committed
1191
		}
1192
		xfs_buf_relse(bp);
Eric Sandeen's avatar
Eric Sandeen committed
1193
1194
1195
1196
	}
	return 0;
}

Christoph Hellwig's avatar
Christoph Hellwig committed
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
/*
 * Clear the quotaflags in memory and in the superblock.
 */
int
xfs_mount_reset_sbqflags(
	struct xfs_mount	*mp)
{
	int			error;
	struct xfs_trans	*tp;

	mp->m_qflags = 0;

	/*
	 * It is OK to look at sb_qflags here in mount path,
	 * without m_sb_lock.
	 */
	if (mp->m_sb.sb_qflags == 0)
		return 0;
	spin_lock(&mp->m_sb_lock);
	mp->m_sb.sb_qflags = 0;
	spin_unlock(&mp->m_sb_lock);

	/*
	 * If the fs is readonly, let the incore superblock run
	 * with quotas off but don't flush the update out to disk
	 */
	if (mp->m_flags & XFS_MOUNT_RDONLY)
		return 0;

	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
1227
1228
	error = xfs_trans_reserve(tp, 0, XFS_QM_SBCHANGE_LOG_RES(mp),
				  0, 0, XFS_DEFAULT_LOG_COUNT);
Christoph Hellwig's avatar
Christoph Hellwig committed
1229
1230
	if (error) {
		xfs_trans_cancel(tp, 0);
1231
		xfs_alert(mp, "%s: Superblock update failed!", __func__);
Christoph Hellwig's avatar
Christoph Hellwig committed
1232
1233
1234
1235
1236
1237
1238
		return error;
	}

	xfs_mod_sb(tp, XFS_SB_QFLAGS);
	return xfs_trans_commit(tp, 0);
}

1239
1240
1241
1242
1243
1244
__uint64_t
xfs_default_resblks(xfs_mount_t *mp)
{
	__uint64_t resblks;

	/*
1245
1246
1247
1248
1249
	 * We default to 5% or 8192 fsbs of space reserved, whichever is
	 * smaller.  This is intended to cover concurrent allocation
	 * transactions when we initially hit enospc. These each require a 4
	 * block reservation. Hence by default we cover roughly 2000 concurrent
	 * allocation reservations.
1250
1251
1252
	 */
	resblks = mp->m_sb.sb_dblocks;
	do_div(resblks, 20);
1253
	resblks = min_t(__uint64_t, resblks, 8192);
1254
1255
1256
	return resblks;
}

Eric Sandeen's avatar
Eric Sandeen committed
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
/*
 * This function does the following on an initial mount of a file system:
 *	- reads the superblock from disk and init the mount struct
 *	- if we're a 32-bit kernel, do a size check on the superblock
 *		so we don't mount terabyte filesystems
 *	- init mount struct realtime fields
 *	- allocate inode hash table for fs
 *	- init directory manager
 *	- perform recovery and init the log manager
 */
int
xfs_mountfs(
Christoph Hellwig's avatar
Christoph Hellwig committed
1269
	xfs_mount_t	*mp)
Eric Sandeen's avatar
Eric Sandeen committed
1270
1271
1272
1273
{
	xfs_sb_t	*sbp = &(mp->m_sb);
	xfs_inode_t	*rip;
	__uint64_t	resblks;
Christoph Hellwig's avatar
Christoph Hellwig committed
1274
1275
	uint		quotamount = 0;
	uint		quotaflags = 0;
Eric Sandeen's avatar
Eric Sandeen committed
1276
1277
1278
1279
	int		error = 0;

	xfs_mount_common(mp, sbp);

1280
	/*
1281
1282
1283
1284
1285
	 * Check for a mismatched features2 values.  Older kernels
	 * read & wrote into the wrong sb offset for sb_features2
	 * on some platforms due to xfs_sb_t not being 64bit size aligned
	 * when sb_features2 was added, which made older superblock
	 * reading/writing routines swap it as a 64-bit value.
1286
	 *
1287
1288
1289
1290
1291
1292
1293
1294
	 * For backwards compatibility, we make both slots equal.
	 *
	 * If we detect a mismatched field, we OR the set bits into the
	 * existing features2 field in case it has already been modified; we
	 * don't want to lose any features.  We then update the bad location
	 * with the ORed value so that older kernels will see any features2
	 * flags, and mark the two fields as needing updates once the
	 * transaction subsystem is online.
1295
	 */
1296
	if (xfs_sb_has_mismatched_features2(sbp)) {
1297
		xfs_warn(mp, "correcting sb_features alignment problem");
1298
		sbp->sb_features2 |= sbp->sb_bad_features2;
1299
		sbp->sb_bad_features2 = sbp->sb_features2;
1300
		mp->m_update_flags |= XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2;
1301
1302
1303
1304
1305

		/*
		 * Re-check for ATTR2 in case it was found in bad_features2
		 * slot.
		 */
1306
1307
		if (xfs_sb_version_hasattr2(&mp->m_sb) &&
		   !(mp->m_flags & XFS_MOUNT_NOATTR2))
1308
			mp->m_flags |= XFS_MOUNT_ATTR2;