xfs_fsops.c 16.2 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2 3
 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
 * All Rights Reserved.
L
Linus Torvalds 已提交
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
L
Linus Torvalds 已提交
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.
L
Linus Torvalds 已提交
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
L
Linus Torvalds 已提交
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"
L
Linus Torvalds 已提交
24 25
#include "xfs_sb.h"
#include "xfs_mount.h"
26
#include "xfs_defer.h"
27
#include "xfs_trans.h"
L
Linus Torvalds 已提交
28
#include "xfs_error.h"
29 30
#include "xfs_btree.h"
#include "xfs_alloc_btree.h"
L
Linus Torvalds 已提交
31
#include "xfs_alloc.h"
32
#include "xfs_rmap_btree.h"
L
Linus Torvalds 已提交
33 34 35 36
#include "xfs_ialloc.h"
#include "xfs_fsops.h"
#include "xfs_trans_space.h"
#include "xfs_rtalloc.h"
C
Christoph Hellwig 已提交
37
#include "xfs_trace.h"
38
#include "xfs_log.h"
39
#include "xfs_rmap.h"
D
Dave Chinner 已提交
40
#include "xfs_ag.h"
41
#include "xfs_ag_resv.h"
L
Linus Torvalds 已提交
42 43

/*
D
Dave Chinner 已提交
44
 * growfs operations
L
Linus Torvalds 已提交
45 46 47 48 49 50 51 52 53
 */
static int
xfs_growfs_data_private(
	xfs_mount_t		*mp,		/* mount point for filesystem */
	xfs_growfs_data_t	*in)		/* growfs data input struct */
{
	xfs_agf_t		*agf;
	xfs_agi_t		*agi;
	xfs_buf_t		*bp;
54
	int			error;
L
Linus Torvalds 已提交
55 56 57 58 59 60
	xfs_agnumber_t		nagcount;
	xfs_agnumber_t		nagimax = 0;
	xfs_rfsblock_t		nb, nb_mod;
	xfs_rfsblock_t		new;
	xfs_agnumber_t		oagcount;
	xfs_trans_t		*tp;
61
	LIST_HEAD		(buffer_list);
62
	struct aghdr_init_data	id = {};
L
Linus Torvalds 已提交
63 64

	nb = in->newblocks;
65
	if (nb < mp->m_sb.sb_dblocks)
D
Dave Chinner 已提交
66
		return -EINVAL;
67 68
	if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb)))
		return error;
69
	error = xfs_buf_read_uncached(mp->m_ddev_targp,
70
				XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
71 72
				XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
	if (error)
73
		return error;
L
Linus Torvalds 已提交
74 75 76 77 78 79 80
	xfs_buf_relse(bp);

	new = nb;	/* use new as a temporary here */
	nb_mod = do_div(new, mp->m_sb.sb_agblocks);
	nagcount = new + (nb_mod != 0);
	if (nb_mod && nb_mod < XFS_MIN_AG_BLOCKS) {
		nagcount--;
81
		nb = (xfs_rfsblock_t)nagcount * mp->m_sb.sb_agblocks;
L
Linus Torvalds 已提交
82
		if (nb < mp->m_sb.sb_dblocks)
D
Dave Chinner 已提交
83
			return -EINVAL;
L
Linus Torvalds 已提交
84 85 86
	}
	new = nb - mp->m_sb.sb_dblocks;
	oagcount = mp->m_sb.sb_agcount;
87

88 89 90 91 92
	/* allocate the new per-ag structures */
	if (nagcount > oagcount) {
		error = xfs_initialize_perag(mp, nagcount, &nagimax);
		if (error)
			return error;
L
Linus Torvalds 已提交
93
	}
94

95 96 97
	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata,
			XFS_GROWFS_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp);
	if (error)
L
Linus Torvalds 已提交
98 99
		return error;

100
	/*
101 102 103 104 105 106 107 108 109 110
	 * Write new AG headers to disk. Non-transactional, but need to be
	 * written and completed prior to the growfs transaction being logged.
	 * To do this, we use a delayed write buffer list and wait for
	 * submission and IO completion of the list as a whole. This allows the
	 * IO subsystem to merge all the AG headers in a single AG into a single
	 * IO and hide most of the latency of the IO from us.
	 *
	 * This also means that if we get an error whilst building the buffer
	 * list to write, we can cancel the entire list without having written
	 * anything.
111
	 */
112 113 114 115 116 117 118 119
	INIT_LIST_HEAD(&id.buffer_list);
	for (id.agno = nagcount - 1;
	     id.agno >= oagcount;
	     id.agno--, new -= id.agsize) {

		if (id.agno == nagcount - 1)
			id.agsize = nb -
				(id.agno * (xfs_rfsblock_t)mp->m_sb.sb_agblocks);
L
Linus Torvalds 已提交
120
		else
121
			id.agsize = mp->m_sb.sb_agblocks;
122

D
Dave Chinner 已提交
123
		error = xfs_ag_init_headers(mp, &id);
124
		if (error) {
125
			xfs_buf_delwri_cancel(&id.buffer_list);
126
			goto out_trans_cancel;
127
		}
L
Linus Torvalds 已提交
128
	}
129
	error = xfs_buf_delwri_submit(&id.buffer_list);
130
	if (error)
131
		goto out_trans_cancel;
132

133
	xfs_trans_agblocks_delta(tp, id.nfree);
134

L
Linus Torvalds 已提交
135 136 137 138
	/*
	 * There are new blocks in the old last a.g.
	 */
	if (new) {
139 140
		struct xfs_owner_info	oinfo;

L
Linus Torvalds 已提交
141 142 143
		/*
		 * Change the agi length.
		 */
144
		error = xfs_ialloc_read_agi(mp, tp, id.agno, &bp);
145 146 147
		if (error)
			goto out_trans_cancel;

L
Linus Torvalds 已提交
148 149
		ASSERT(bp);
		agi = XFS_BUF_TO_AGI(bp);
150
		be32_add_cpu(&agi->agi_length, new);
L
Linus Torvalds 已提交
151
		ASSERT(nagcount == oagcount ||
152
		       be32_to_cpu(agi->agi_length) == mp->m_sb.sb_agblocks);
L
Linus Torvalds 已提交
153
		xfs_ialloc_log_agi(tp, bp, XFS_AGI_LENGTH);
154

L
Linus Torvalds 已提交
155 156 157
		/*
		 * Change agf length.
		 */
158
		error = xfs_alloc_read_agf(mp, tp, id.agno, 0, &bp);
159 160 161
		if (error)
			goto out_trans_cancel;

L
Linus Torvalds 已提交
162 163
		ASSERT(bp);
		agf = XFS_BUF_TO_AGF(bp);
164
		be32_add_cpu(&agf->agf_length, new);
165 166
		ASSERT(be32_to_cpu(agf->agf_length) ==
		       be32_to_cpu(agi->agi_length));
C
Christoph Hellwig 已提交
167

168
		xfs_alloc_log_agf(tp, bp, XFS_AGF_LENGTH);
169

L
Linus Torvalds 已提交
170 171
		/*
		 * Free the new space.
172 173 174
		 *
		 * XFS_RMAP_OWN_NULL is used here to tell the rmap btree that
		 * this doesn't actually exist in the rmap btree.
L
Linus Torvalds 已提交
175
		 */
176
		xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_NULL);
177
		error = xfs_rmap_free(tp, bp, id.agno,
178 179 180
				be32_to_cpu(agf->agf_length) - new,
				new, &oinfo);
		if (error)
181
			goto out_trans_cancel;
182
		error = xfs_free_extent(tp,
183
				XFS_AGB_TO_FSB(mp, id.agno,
184
					be32_to_cpu(agf->agf_length) - new),
185
				new, &oinfo, XFS_AG_RESV_NONE);
186
		if (error)
187
			goto out_trans_cancel;
L
Linus Torvalds 已提交
188
	}
189 190 191 192 193 194

	/*
	 * Update changed superblock fields transactionally. These are not
	 * seen by the rest of the world until the transaction commit applies
	 * them atomically to the superblock.
	 */
L
Linus Torvalds 已提交
195 196 197 198 199
	if (nagcount > oagcount)
		xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount);
	if (nb > mp->m_sb.sb_dblocks)
		xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS,
				 nb - mp->m_sb.sb_dblocks);
200 201
	if (id.nfree)
		xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, id.nfree);
202
	xfs_trans_set_sync(tp);
203
	error = xfs_trans_commit(tp);
204
	if (error)
L
Linus Torvalds 已提交
205
		return error;
206

L
Linus Torvalds 已提交
207 208 209
	/* New allocation groups fully initialized, so update mount struct */
	if (nagimax)
		mp->m_maxagi = nagimax;
210
	xfs_set_low_space_thresholds(mp);
211
	mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
212

213 214 215 216 217 218 219
	/*
	 * If we expanded the last AG, free the per-AG reservation
	 * so we can reinitialize it with the new size.
	 */
	if (new) {
		struct xfs_perag	*pag;

220
		pag = xfs_perag_get(mp, id.agno);
221 222 223
		error = xfs_ag_resv_free(pag);
		xfs_perag_put(pag);
		if (error)
224
			return error;
225 226
	}

227 228 229 230 231
	/*
	 * Reserve AG metadata blocks. ENOSPC here does not mean there was a
	 * growfs failure, just that there still isn't space for new user data
	 * after the grow has been run.
	 */
232
	error = xfs_fs_reserve_ag_blocks(mp);
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
	if (error == -ENOSPC)
		error = 0;
	return error;

out_trans_cancel:
	xfs_trans_cancel(tp);
	return error;
}

static int
xfs_growfs_log_private(
	xfs_mount_t		*mp,	/* mount point for filesystem */
	xfs_growfs_log_t	*in)	/* growfs log input struct */
{
	xfs_extlen_t		nb;

	nb = in->newblocks;
	if (nb < XFS_MIN_LOG_BLOCKS || nb < XFS_B_TO_FSB(mp, XFS_MIN_LOG_BYTES))
		return -EINVAL;
	if (nb == mp->m_sb.sb_logblocks &&
	    in->isint == (mp->m_sb.sb_logstart != 0))
		return -EINVAL;
	/*
	 * Moving the log is hard, need new interfaces to sync
	 * the log first, hold off all activity while moving it.
	 * Can have shorter or longer log in the same space,
	 * or transform internal to external log or vice versa.
	 */
	return -ENOSYS;
}

static int
xfs_growfs_imaxpct(
	struct xfs_mount	*mp,
	__u32			imaxpct)
{
	struct xfs_trans	*tp;
	int			dpct;
	int			error;

	if (imaxpct > 100)
		return -EINVAL;

	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata,
			XFS_GROWFS_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp);
	if (error)
		return error;

	dpct = imaxpct - mp->m_sb.sb_imax_pct;
	xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct);
	xfs_trans_set_sync(tp);
	return xfs_trans_commit(tp);
}

L
Linus Torvalds 已提交
287 288 289 290 291 292 293
/*
 * protected versions of growfs function acquire and release locks on the mount
 * point - exported through ioctls: XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG,
 * XFS_IOC_FSGROWFSRT
 */
int
xfs_growfs_data(
294 295
	struct xfs_mount	*mp,
	struct xfs_growfs_data	*in)
L
Linus Torvalds 已提交
296
{
297
	int			error = 0;
298 299

	if (!capable(CAP_SYS_ADMIN))
D
Dave Chinner 已提交
300
		return -EPERM;
301
	if (!mutex_trylock(&mp->m_growlock))
D
Dave Chinner 已提交
302
		return -EWOULDBLOCK;
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324

	/* update imaxpct separately to the physical grow of the filesystem */
	if (in->imaxpct != mp->m_sb.sb_imax_pct) {
		error = xfs_growfs_imaxpct(mp, in->imaxpct);
		if (error)
			goto out_error;
	}

	if (in->newblocks != mp->m_sb.sb_dblocks) {
		error = xfs_growfs_data_private(mp, in);
		if (error)
			goto out_error;
	}

	/* Post growfs calculations needed to reflect new state in operations */
	if (mp->m_sb.sb_imax_pct) {
		uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct;
		do_div(icount, 100);
		mp->m_maxicount = icount << mp->m_sb.sb_inopblog;
	} else
		mp->m_maxicount = 0;

325
	/* Update secondary superblocks now the physical grow has completed */
D
Dave Chinner 已提交
326
	error = xfs_update_secondary_sbs(mp);
327

328
out_error:
329 330 331 332 333 334
	/*
	 * Increment the generation unconditionally, the error could be from
	 * updating the secondary superblocks, in which case the new size
	 * is live already.
	 */
	mp->m_generation++;
335
	mutex_unlock(&mp->m_growlock);
L
Linus Torvalds 已提交
336 337 338 339 340 341 342 343 344
	return error;
}

int
xfs_growfs_log(
	xfs_mount_t		*mp,
	xfs_growfs_log_t	*in)
{
	int error;
345 346

	if (!capable(CAP_SYS_ADMIN))
D
Dave Chinner 已提交
347
		return -EPERM;
348
	if (!mutex_trylock(&mp->m_growlock))
D
Dave Chinner 已提交
349
		return -EWOULDBLOCK;
L
Linus Torvalds 已提交
350
	error = xfs_growfs_log_private(mp, in);
351
	mutex_unlock(&mp->m_growlock);
L
Linus Torvalds 已提交
352 353 354 355 356 357 358 359 360 361 362 363
	return error;
}

/*
 * exported through ioctl XFS_IOC_FSCOUNTS
 */

int
xfs_fs_counts(
	xfs_mount_t		*mp,
	xfs_fsop_counts_t	*cnt)
{
364
	cnt->allocino = percpu_counter_read_positive(&mp->m_icount);
365
	cnt->freeino = percpu_counter_read_positive(&mp->m_ifree);
366
	cnt->freedata = percpu_counter_read_positive(&mp->m_fdblocks) -
367
						mp->m_alloc_set_aside;
368

E
Eric Sandeen 已提交
369
	spin_lock(&mp->m_sb_lock);
L
Linus Torvalds 已提交
370
	cnt->freertx = mp->m_sb.sb_frextents;
E
Eric Sandeen 已提交
371
	spin_unlock(&mp->m_sb_lock);
L
Linus Torvalds 已提交
372 373 374 375 376 377 378 379
	return 0;
}

/*
 * exported through ioctl XFS_IOC_SET_RESBLKS & XFS_IOC_GET_RESBLKS
 *
 * xfs_reserve_blocks is called to set m_resblks
 * in the in-core mount table. The number of unused reserved blocks
380
 * is kept in m_resblks_avail.
L
Linus Torvalds 已提交
381 382 383 384 385 386 387 388 389 390 391 392
 *
 * Reserve the requested number of blocks if available. Otherwise return
 * as many as possible to satisfy the request. The actual number
 * reserved are returned in outval
 *
 * A null inval pointer indicates that only the current reserved blocks
 * available  should  be returned no settings are changed.
 */

int
xfs_reserve_blocks(
	xfs_mount_t             *mp,
393
	uint64_t              *inval,
L
Linus Torvalds 已提交
394 395
	xfs_fsop_resblks_t      *outval)
{
396 397 398 399
	int64_t			lcounter, delta;
	int64_t			fdblks_delta = 0;
	uint64_t		request;
	int64_t			free;
400
	int			error = 0;
L
Linus Torvalds 已提交
401 402

	/* If inval is null, report current values and return */
403
	if (inval == (uint64_t *)NULL) {
404
		if (!outval)
D
Dave Chinner 已提交
405
			return -EINVAL;
L
Linus Torvalds 已提交
406 407
		outval->resblks = mp->m_resblks;
		outval->resblks_avail = mp->m_resblks_avail;
408
		return 0;
L
Linus Torvalds 已提交
409 410 411
	}

	request = *inval;
412 413

	/*
414 415 416
	 * With per-cpu counters, this becomes an interesting problem. we need
	 * to work out if we are freeing or allocation blocks first, then we can
	 * do the modification as necessary.
417
	 *
418 419 420 421
	 * We do this under the m_sb_lock so that if we are near ENOSPC, we will
	 * hold out any changes while we work out what to do. This means that
	 * the amount of free space can change while we do this, so we need to
	 * retry if we end up trying to reserve more space than is available.
422
	 */
E
Eric Sandeen 已提交
423
	spin_lock(&mp->m_sb_lock);
L
Linus Torvalds 已提交
424 425 426

	/*
	 * If our previous reservation was larger than the current value,
427 428 429
	 * then move any unused blocks back to the free pool. Modify the resblks
	 * counters directly since we shouldn't have any problems unreserving
	 * space.
L
Linus Torvalds 已提交
430 431 432 433
	 */
	if (mp->m_resblks > request) {
		lcounter = mp->m_resblks_avail - request;
		if (lcounter  > 0) {		/* release unused blocks */
434
			fdblks_delta = lcounter;
L
Linus Torvalds 已提交
435 436 437
			mp->m_resblks_avail -= lcounter;
		}
		mp->m_resblks = request;
438 439 440 441 442 443 444 445
		if (fdblks_delta) {
			spin_unlock(&mp->m_sb_lock);
			error = xfs_mod_fdblocks(mp, fdblks_delta, 0);
			spin_lock(&mp->m_sb_lock);
		}

		goto out;
	}
446

447 448 449 450 451 452 453
	/*
	 * If the request is larger than the current reservation, reserve the
	 * blocks before we update the reserve counters. Sample m_fdblocks and
	 * perform a partial reservation if the request exceeds free space.
	 */
	error = -ENOSPC;
	do {
454
		free = percpu_counter_sum(&mp->m_fdblocks) -
455
						mp->m_alloc_set_aside;
456
		if (!free)
457
			break;
458

L
Linus Torvalds 已提交
459
		delta = request - mp->m_resblks;
460
		lcounter = free - delta;
461
		if (lcounter < 0)
L
Linus Torvalds 已提交
462
			/* We can't satisfy the request, just get what we can */
463 464 465
			fdblks_delta = free;
		else
			fdblks_delta = delta;
466 467

		/*
468 469 470 471 472
		 * We'll either succeed in getting space from the free block
		 * count or we'll get an ENOSPC. If we get a ENOSPC, it means
		 * things changed while we were calculating fdblks_delta and so
		 * we should try again to see if there is anything left to
		 * reserve.
473 474 475 476
		 *
		 * Don't set the reserved flag here - we don't want to reserve
		 * the extra reserve blocks from the reserve.....
		 */
477 478 479 480 481 482 483 484 485 486 487 488
		spin_unlock(&mp->m_sb_lock);
		error = xfs_mod_fdblocks(mp, -fdblks_delta, 0);
		spin_lock(&mp->m_sb_lock);
	} while (error == -ENOSPC);

	/*
	 * Update the reserve counters if blocks have been successfully
	 * allocated.
	 */
	if (!error && fdblks_delta) {
		mp->m_resblks += fdblks_delta;
		mp->m_resblks_avail += fdblks_delta;
489
	}
490 491 492 493 494 495 496 497 498

out:
	if (outval) {
		outval->resblks = mp->m_resblks;
		outval->resblks_avail = mp->m_resblks_avail;
	}

	spin_unlock(&mp->m_sb_lock);
	return error;
L
Linus Torvalds 已提交
499 500 501 502 503
}

int
xfs_fs_goingdown(
	xfs_mount_t	*mp,
504
	uint32_t	inflags)
L
Linus Torvalds 已提交
505 506 507
{
	switch (inflags) {
	case XFS_FSOP_GOING_FLAGS_DEFAULT: {
C
Christoph Hellwig 已提交
508
		struct super_block *sb = freeze_bdev(mp->m_super->s_bdev);
L
Linus Torvalds 已提交
509

510
		if (sb && !IS_ERR(sb)) {
511
			xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
L
Linus Torvalds 已提交
512 513
			thaw_bdev(sb->s_bdev, sb);
		}
514

L
Linus Torvalds 已提交
515 516 517
		break;
	}
	case XFS_FSOP_GOING_FLAGS_LOGFLUSH:
518
		xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
L
Linus Torvalds 已提交
519 520
		break;
	case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH:
521 522
		xfs_force_shutdown(mp,
				SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR);
L
Linus Torvalds 已提交
523 524
		break;
	default:
D
Dave Chinner 已提交
525
		return -EINVAL;
L
Linus Torvalds 已提交
526 527 528 529
	}

	return 0;
}
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549

/*
 * Force a shutdown of the filesystem instantly while keeping the filesystem
 * consistent. We don't do an unmount here; just shutdown the shop, make sure
 * that absolutely nothing persistent happens to this filesystem after this
 * point.
 */
void
xfs_do_force_shutdown(
	xfs_mount_t	*mp,
	int		flags,
	char		*fname,
	int		lnnum)
{
	int		logerror;

	logerror = flags & SHUTDOWN_LOG_IO_ERROR;

	if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
		xfs_notice(mp,
550
	"%s(0x%x) called from line %d of file %s.  Return address = "PTR_FMT,
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
			__func__, flags, lnnum, fname, __return_address);
	}
	/*
	 * No need to duplicate efforts.
	 */
	if (XFS_FORCED_SHUTDOWN(mp) && !logerror)
		return;

	/*
	 * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't
	 * queue up anybody new on the log reservations, and wakes up
	 * everybody who's sleeping on log reservations to tell them
	 * the bad news.
	 */
	if (xfs_log_force_umount(mp, logerror))
		return;

	if (flags & SHUTDOWN_CORRUPT_INCORE) {
		xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT,
    "Corruption of in-memory data detected.  Shutting down filesystem");
		if (XFS_ERRLEVEL_HIGH <= xfs_error_level)
			xfs_stack_trace();
	} else if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
		if (logerror) {
			xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR,
		"Log I/O Error Detected.  Shutting down filesystem");
		} else if (flags & SHUTDOWN_DEVICE_REQ) {
			xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
		"All device paths lost.  Shutting down filesystem");
		} else if (!(flags & SHUTDOWN_REMOTE_REQ)) {
			xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
		"I/O Error Detected. Shutting down filesystem");
		}
	}
	if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
		xfs_alert(mp,
	"Please umount the filesystem and rectify the problem(s)");
	}
}
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645

/*
 * Reserve free space for per-AG metadata.
 */
int
xfs_fs_reserve_ag_blocks(
	struct xfs_mount	*mp)
{
	xfs_agnumber_t		agno;
	struct xfs_perag	*pag;
	int			error = 0;
	int			err2;

	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
		pag = xfs_perag_get(mp, agno);
		err2 = xfs_ag_resv_init(pag);
		xfs_perag_put(pag);
		if (err2 && !error)
			error = err2;
	}

	if (error && error != -ENOSPC) {
		xfs_warn(mp,
	"Error %d reserving per-AG metadata reserve pool.", error);
		xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
	}

	return error;
}

/*
 * Free space reserved for per-AG metadata.
 */
int
xfs_fs_unreserve_ag_blocks(
	struct xfs_mount	*mp)
{
	xfs_agnumber_t		agno;
	struct xfs_perag	*pag;
	int			error = 0;
	int			err2;

	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
		pag = xfs_perag_get(mp, agno);
		err2 = xfs_ag_resv_free(pag);
		xfs_perag_put(pag);
		if (err2 && !error)
			error = err2;
	}

	if (error)
		xfs_warn(mp,
	"Error %d freeing per-AG metadata reserve pool.", error);

	return error;
}