1/*
2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18#include "xfs.h"
19#include "xfs_fs.h"
20#include "xfs_shared.h"
21#include "xfs_format.h"
22#include "xfs_log_format.h"
23#include "xfs_trans_resv.h"
24#include "xfs_sb.h"
25#include "xfs_mount.h"
26#include "xfs_da_format.h"
27#include "xfs_da_btree.h"
28#include "xfs_inode.h"
29#include "xfs_trans.h"
30#include "xfs_inode_item.h"
31#include "xfs_error.h"
32#include "xfs_btree.h"
33#include "xfs_alloc_btree.h"
34#include "xfs_alloc.h"
35#include "xfs_ialloc.h"
36#include "xfs_fsops.h"
37#include "xfs_itable.h"
38#include "xfs_trans_space.h"
39#include "xfs_rtalloc.h"
40#include "xfs_trace.h"
41#include "xfs_log.h"
42#include "xfs_filestream.h"
43
44/*
45 * File system operations
46 */
47
48int
49xfs_fs_geometry(
50	xfs_mount_t		*mp,
51	xfs_fsop_geom_t		*geo,
52	int			new_version)
53{
54
55	memset(geo, 0, sizeof(*geo));
56
57	geo->blocksize = mp->m_sb.sb_blocksize;
58	geo->rtextsize = mp->m_sb.sb_rextsize;
59	geo->agblocks = mp->m_sb.sb_agblocks;
60	geo->agcount = mp->m_sb.sb_agcount;
61	geo->logblocks = mp->m_sb.sb_logblocks;
62	geo->sectsize = mp->m_sb.sb_sectsize;
63	geo->inodesize = mp->m_sb.sb_inodesize;
64	geo->imaxpct = mp->m_sb.sb_imax_pct;
65	geo->datablocks = mp->m_sb.sb_dblocks;
66	geo->rtblocks = mp->m_sb.sb_rblocks;
67	geo->rtextents = mp->m_sb.sb_rextents;
68	geo->logstart = mp->m_sb.sb_logstart;
69	ASSERT(sizeof(geo->uuid)==sizeof(mp->m_sb.sb_uuid));
70	memcpy(geo->uuid, &mp->m_sb.sb_uuid, sizeof(mp->m_sb.sb_uuid));
71	if (new_version >= 2) {
72		geo->sunit = mp->m_sb.sb_unit;
73		geo->swidth = mp->m_sb.sb_width;
74	}
75	if (new_version >= 3) {
76		geo->version = XFS_FSOP_GEOM_VERSION;
77		geo->flags = XFS_FSOP_GEOM_FLAGS_NLINK |
78			     XFS_FSOP_GEOM_FLAGS_DIRV2 |
79			(xfs_sb_version_hasattr(&mp->m_sb) ?
80				XFS_FSOP_GEOM_FLAGS_ATTR : 0) |
81			(xfs_sb_version_hasquota(&mp->m_sb) ?
82				XFS_FSOP_GEOM_FLAGS_QUOTA : 0) |
83			(xfs_sb_version_hasalign(&mp->m_sb) ?
84				XFS_FSOP_GEOM_FLAGS_IALIGN : 0) |
85			(xfs_sb_version_hasdalign(&mp->m_sb) ?
86				XFS_FSOP_GEOM_FLAGS_DALIGN : 0) |
87			(xfs_sb_version_hasextflgbit(&mp->m_sb) ?
88				XFS_FSOP_GEOM_FLAGS_EXTFLG : 0) |
89			(xfs_sb_version_hassector(&mp->m_sb) ?
90				XFS_FSOP_GEOM_FLAGS_SECTOR : 0) |
91			(xfs_sb_version_hasasciici(&mp->m_sb) ?
92				XFS_FSOP_GEOM_FLAGS_DIRV2CI : 0) |
93			(xfs_sb_version_haslazysbcount(&mp->m_sb) ?
94				XFS_FSOP_GEOM_FLAGS_LAZYSB : 0) |
95			(xfs_sb_version_hasattr2(&mp->m_sb) ?
96				XFS_FSOP_GEOM_FLAGS_ATTR2 : 0) |
97			(xfs_sb_version_hasprojid32bit(&mp->m_sb) ?
98				XFS_FSOP_GEOM_FLAGS_PROJID32 : 0) |
99			(xfs_sb_version_hascrc(&mp->m_sb) ?
100				XFS_FSOP_GEOM_FLAGS_V5SB : 0) |
101			(xfs_sb_version_hasftype(&mp->m_sb) ?
102				XFS_FSOP_GEOM_FLAGS_FTYPE : 0) |
103			(xfs_sb_version_hasfinobt(&mp->m_sb) ?
104				XFS_FSOP_GEOM_FLAGS_FINOBT : 0);
105		geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ?
106				mp->m_sb.sb_logsectsize : BBSIZE;
107		geo->rtsectsize = mp->m_sb.sb_blocksize;
108		geo->dirblocksize = mp->m_dir_geo->blksize;
109	}
110	if (new_version >= 4) {
111		geo->flags |=
112			(xfs_sb_version_haslogv2(&mp->m_sb) ?
113				XFS_FSOP_GEOM_FLAGS_LOGV2 : 0);
114		geo->logsunit = mp->m_sb.sb_logsunit;
115	}
116	return 0;
117}
118
119static struct xfs_buf *
120xfs_growfs_get_hdr_buf(
121	struct xfs_mount	*mp,
122	xfs_daddr_t		blkno,
123	size_t			numblks,
124	int			flags,
125	const struct xfs_buf_ops *ops)
126{
127	struct xfs_buf		*bp;
128
129	bp = xfs_buf_get_uncached(mp->m_ddev_targp, numblks, flags);
130	if (!bp)
131		return NULL;
132
133	xfs_buf_zero(bp, 0, BBTOB(bp->b_length));
134	bp->b_bn = blkno;
135	bp->b_maps[0].bm_bn = blkno;
136	bp->b_ops = ops;
137
138	return bp;
139}
140
141static int
142xfs_growfs_data_private(
143	xfs_mount_t		*mp,		/* mount point for filesystem */
144	xfs_growfs_data_t	*in)		/* growfs data input struct */
145{
146	xfs_agf_t		*agf;
147	struct xfs_agfl		*agfl;
148	xfs_agi_t		*agi;
149	xfs_agnumber_t		agno;
150	xfs_extlen_t		agsize;
151	xfs_extlen_t		tmpsize;
152	xfs_alloc_rec_t		*arec;
153	xfs_buf_t		*bp;
154	int			bucket;
155	int			dpct;
156	int			error, saved_error = 0;
157	xfs_agnumber_t		nagcount;
158	xfs_agnumber_t		nagimax = 0;
159	xfs_rfsblock_t		nb, nb_mod;
160	xfs_rfsblock_t		new;
161	xfs_rfsblock_t		nfree;
162	xfs_agnumber_t		oagcount;
163	int			pct;
164	xfs_trans_t		*tp;
165
166	nb = in->newblocks;
167	pct = in->imaxpct;
168	if (nb < mp->m_sb.sb_dblocks || pct < 0 || pct > 100)
169		return -EINVAL;
170	if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb)))
171		return error;
172	dpct = pct - mp->m_sb.sb_imax_pct;
173	error = xfs_buf_read_uncached(mp->m_ddev_targp,
174				XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
175				XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
176	if (error)
177		return error;
178	xfs_buf_relse(bp);
179
180	new = nb;	/* use new as a temporary here */
181	nb_mod = do_div(new, mp->m_sb.sb_agblocks);
182	nagcount = new + (nb_mod != 0);
183	if (nb_mod && nb_mod < XFS_MIN_AG_BLOCKS) {
184		nagcount--;
185		nb = (xfs_rfsblock_t)nagcount * mp->m_sb.sb_agblocks;
186		if (nb < mp->m_sb.sb_dblocks)
187			return -EINVAL;
188	}
189	new = nb - mp->m_sb.sb_dblocks;
190	oagcount = mp->m_sb.sb_agcount;
191
192	/* allocate the new per-ag structures */
193	if (nagcount > oagcount) {
194		error = xfs_initialize_perag(mp, nagcount, &nagimax);
195		if (error)
196			return error;
197	}
198
199	tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS);
200	tp->t_flags |= XFS_TRANS_RESERVE;
201	error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growdata,
202				  XFS_GROWFS_SPACE_RES(mp), 0);
203	if (error) {
204		xfs_trans_cancel(tp, 0);
205		return error;
206	}
207
208	/*
209	 * Write new AG headers to disk. Non-transactional, but written
210	 * synchronously so they are completed prior to the growfs transaction
211	 * being logged.
212	 */
213	nfree = 0;
214	for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) {
215		__be32	*agfl_bno;
216
217		/*
218		 * AG freespace header block
219		 */
220		bp = xfs_growfs_get_hdr_buf(mp,
221				XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
222				XFS_FSS_TO_BB(mp, 1), 0,
223				&xfs_agf_buf_ops);
224		if (!bp) {
225			error = -ENOMEM;
226			goto error0;
227		}
228
229		agf = XFS_BUF_TO_AGF(bp);
230		agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC);
231		agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION);
232		agf->agf_seqno = cpu_to_be32(agno);
233		if (agno == nagcount - 1)
234			agsize =
235				nb -
236				(agno * (xfs_rfsblock_t)mp->m_sb.sb_agblocks);
237		else
238			agsize = mp->m_sb.sb_agblocks;
239		agf->agf_length = cpu_to_be32(agsize);
240		agf->agf_roots[XFS_BTNUM_BNOi] = cpu_to_be32(XFS_BNO_BLOCK(mp));
241		agf->agf_roots[XFS_BTNUM_CNTi] = cpu_to_be32(XFS_CNT_BLOCK(mp));
242		agf->agf_levels[XFS_BTNUM_BNOi] = cpu_to_be32(1);
243		agf->agf_levels[XFS_BTNUM_CNTi] = cpu_to_be32(1);
244		agf->agf_flfirst = cpu_to_be32(1);
245		agf->agf_fllast = 0;
246		agf->agf_flcount = 0;
247		tmpsize = agsize - XFS_PREALLOC_BLOCKS(mp);
248		agf->agf_freeblks = cpu_to_be32(tmpsize);
249		agf->agf_longest = cpu_to_be32(tmpsize);
250		if (xfs_sb_version_hascrc(&mp->m_sb))
251			uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_uuid);
252
253		error = xfs_bwrite(bp);
254		xfs_buf_relse(bp);
255		if (error)
256			goto error0;
257
258		/*
259		 * AG freelist header block
260		 */
261		bp = xfs_growfs_get_hdr_buf(mp,
262				XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),
263				XFS_FSS_TO_BB(mp, 1), 0,
264				&xfs_agfl_buf_ops);
265		if (!bp) {
266			error = -ENOMEM;
267			goto error0;
268		}
269
270		agfl = XFS_BUF_TO_AGFL(bp);
271		if (xfs_sb_version_hascrc(&mp->m_sb)) {
272			agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
273			agfl->agfl_seqno = cpu_to_be32(agno);
274			uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_uuid);
275		}
276
277		agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, bp);
278		for (bucket = 0; bucket < XFS_AGFL_SIZE(mp); bucket++)
279			agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK);
280
281		error = xfs_bwrite(bp);
282		xfs_buf_relse(bp);
283		if (error)
284			goto error0;
285
286		/*
287		 * AG inode header block
288		 */
289		bp = xfs_growfs_get_hdr_buf(mp,
290				XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
291				XFS_FSS_TO_BB(mp, 1), 0,
292				&xfs_agi_buf_ops);
293		if (!bp) {
294			error = -ENOMEM;
295			goto error0;
296		}
297
298		agi = XFS_BUF_TO_AGI(bp);
299		agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC);
300		agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION);
301		agi->agi_seqno = cpu_to_be32(agno);
302		agi->agi_length = cpu_to_be32(agsize);
303		agi->agi_count = 0;
304		agi->agi_root = cpu_to_be32(XFS_IBT_BLOCK(mp));
305		agi->agi_level = cpu_to_be32(1);
306		agi->agi_freecount = 0;
307		agi->agi_newino = cpu_to_be32(NULLAGINO);
308		agi->agi_dirino = cpu_to_be32(NULLAGINO);
309		if (xfs_sb_version_hascrc(&mp->m_sb))
310			uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
311		if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
312			agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp));
313			agi->agi_free_level = cpu_to_be32(1);
314		}
315		for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
316			agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
317
318		error = xfs_bwrite(bp);
319		xfs_buf_relse(bp);
320		if (error)
321			goto error0;
322
323		/*
324		 * BNO btree root block
325		 */
326		bp = xfs_growfs_get_hdr_buf(mp,
327				XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)),
328				BTOBB(mp->m_sb.sb_blocksize), 0,
329				&xfs_allocbt_buf_ops);
330
331		if (!bp) {
332			error = -ENOMEM;
333			goto error0;
334		}
335
336		if (xfs_sb_version_hascrc(&mp->m_sb))
337			xfs_btree_init_block(mp, bp, XFS_ABTB_CRC_MAGIC, 0, 1,
338						agno, XFS_BTREE_CRC_BLOCKS);
339		else
340			xfs_btree_init_block(mp, bp, XFS_ABTB_MAGIC, 0, 1,
341						agno, 0);
342
343		arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1);
344		arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
345		arec->ar_blockcount = cpu_to_be32(
346			agsize - be32_to_cpu(arec->ar_startblock));
347
348		error = xfs_bwrite(bp);
349		xfs_buf_relse(bp);
350		if (error)
351			goto error0;
352
353		/*
354		 * CNT btree root block
355		 */
356		bp = xfs_growfs_get_hdr_buf(mp,
357				XFS_AGB_TO_DADDR(mp, agno, XFS_CNT_BLOCK(mp)),
358				BTOBB(mp->m_sb.sb_blocksize), 0,
359				&xfs_allocbt_buf_ops);
360		if (!bp) {
361			error = -ENOMEM;
362			goto error0;
363		}
364
365		if (xfs_sb_version_hascrc(&mp->m_sb))
366			xfs_btree_init_block(mp, bp, XFS_ABTC_CRC_MAGIC, 0, 1,
367						agno, XFS_BTREE_CRC_BLOCKS);
368		else
369			xfs_btree_init_block(mp, bp, XFS_ABTC_MAGIC, 0, 1,
370						agno, 0);
371
372		arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1);
373		arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
374		arec->ar_blockcount = cpu_to_be32(
375			agsize - be32_to_cpu(arec->ar_startblock));
376		nfree += be32_to_cpu(arec->ar_blockcount);
377
378		error = xfs_bwrite(bp);
379		xfs_buf_relse(bp);
380		if (error)
381			goto error0;
382
383		/*
384		 * INO btree root block
385		 */
386		bp = xfs_growfs_get_hdr_buf(mp,
387				XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)),
388				BTOBB(mp->m_sb.sb_blocksize), 0,
389				&xfs_inobt_buf_ops);
390		if (!bp) {
391			error = -ENOMEM;
392			goto error0;
393		}
394
395		if (xfs_sb_version_hascrc(&mp->m_sb))
396			xfs_btree_init_block(mp, bp, XFS_IBT_CRC_MAGIC, 0, 0,
397						agno, XFS_BTREE_CRC_BLOCKS);
398		else
399			xfs_btree_init_block(mp, bp, XFS_IBT_MAGIC, 0, 0,
400						agno, 0);
401
402		error = xfs_bwrite(bp);
403		xfs_buf_relse(bp);
404		if (error)
405			goto error0;
406
407		/*
408		 * FINO btree root block
409		 */
410		if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
411			bp = xfs_growfs_get_hdr_buf(mp,
412				XFS_AGB_TO_DADDR(mp, agno, XFS_FIBT_BLOCK(mp)),
413				BTOBB(mp->m_sb.sb_blocksize), 0,
414				&xfs_inobt_buf_ops);
415			if (!bp) {
416				error = -ENOMEM;
417				goto error0;
418			}
419
420			if (xfs_sb_version_hascrc(&mp->m_sb))
421				xfs_btree_init_block(mp, bp, XFS_FIBT_CRC_MAGIC,
422						     0, 0, agno,
423						     XFS_BTREE_CRC_BLOCKS);
424			else
425				xfs_btree_init_block(mp, bp, XFS_FIBT_MAGIC, 0,
426						     0, agno, 0);
427
428			error = xfs_bwrite(bp);
429			xfs_buf_relse(bp);
430			if (error)
431				goto error0;
432		}
433
434	}
435	xfs_trans_agblocks_delta(tp, nfree);
436	/*
437	 * There are new blocks in the old last a.g.
438	 */
439	if (new) {
440		/*
441		 * Change the agi length.
442		 */
443		error = xfs_ialloc_read_agi(mp, tp, agno, &bp);
444		if (error) {
445			goto error0;
446		}
447		ASSERT(bp);
448		agi = XFS_BUF_TO_AGI(bp);
449		be32_add_cpu(&agi->agi_length, new);
450		ASSERT(nagcount == oagcount ||
451		       be32_to_cpu(agi->agi_length) == mp->m_sb.sb_agblocks);
452		xfs_ialloc_log_agi(tp, bp, XFS_AGI_LENGTH);
453		/*
454		 * Change agf length.
455		 */
456		error = xfs_alloc_read_agf(mp, tp, agno, 0, &bp);
457		if (error) {
458			goto error0;
459		}
460		ASSERT(bp);
461		agf = XFS_BUF_TO_AGF(bp);
462		be32_add_cpu(&agf->agf_length, new);
463		ASSERT(be32_to_cpu(agf->agf_length) ==
464		       be32_to_cpu(agi->agi_length));
465
466		xfs_alloc_log_agf(tp, bp, XFS_AGF_LENGTH);
467		/*
468		 * Free the new space.
469		 */
470		error = xfs_free_extent(tp, XFS_AGB_TO_FSB(mp, agno,
471			be32_to_cpu(agf->agf_length) - new), new);
472		if (error) {
473			goto error0;
474		}
475	}
476
477	/*
478	 * Update changed superblock fields transactionally. These are not
479	 * seen by the rest of the world until the transaction commit applies
480	 * them atomically to the superblock.
481	 */
482	if (nagcount > oagcount)
483		xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount);
484	if (nb > mp->m_sb.sb_dblocks)
485		xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS,
486				 nb - mp->m_sb.sb_dblocks);
487	if (nfree)
488		xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, nfree);
489	if (dpct)
490		xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct);
491	xfs_trans_set_sync(tp);
492	error = xfs_trans_commit(tp, 0);
493	if (error)
494		return error;
495
496	/* New allocation groups fully initialized, so update mount struct */
497	if (nagimax)
498		mp->m_maxagi = nagimax;
499	if (mp->m_sb.sb_imax_pct) {
500		__uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct;
501		do_div(icount, 100);
502		mp->m_maxicount = icount << mp->m_sb.sb_inopblog;
503	} else
504		mp->m_maxicount = 0;
505	xfs_set_low_space_thresholds(mp);
506
507	/* update secondary superblocks. */
508	for (agno = 1; agno < nagcount; agno++) {
509		error = 0;
510		/*
511		 * new secondary superblocks need to be zeroed, not read from
512		 * disk as the contents of the new area we are growing into is
513		 * completely unknown.
514		 */
515		if (agno < oagcount) {
516			error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
517				  XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
518				  XFS_FSS_TO_BB(mp, 1), 0, &bp,
519				  &xfs_sb_buf_ops);
520		} else {
521			bp = xfs_trans_get_buf(NULL, mp->m_ddev_targp,
522				  XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
523				  XFS_FSS_TO_BB(mp, 1), 0);
524			if (bp) {
525				bp->b_ops = &xfs_sb_buf_ops;
526				xfs_buf_zero(bp, 0, BBTOB(bp->b_length));
527			} else
528				error = -ENOMEM;
529		}
530
531		/*
532		 * If we get an error reading or writing alternate superblocks,
533		 * continue.  xfs_repair chooses the "best" superblock based
534		 * on most matches; if we break early, we'll leave more
535		 * superblocks un-updated than updated, and xfs_repair may
536		 * pick them over the properly-updated primary.
537		 */
538		if (error) {
539			xfs_warn(mp,
540		"error %d reading secondary superblock for ag %d",
541				error, agno);
542			saved_error = error;
543			continue;
544		}
545		xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb);
546
547		error = xfs_bwrite(bp);
548		xfs_buf_relse(bp);
549		if (error) {
550			xfs_warn(mp,
551		"write error %d updating secondary superblock for ag %d",
552				error, agno);
553			saved_error = error;
554			continue;
555		}
556	}
557	return saved_error ? saved_error : error;
558
559 error0:
560	xfs_trans_cancel(tp, XFS_TRANS_ABORT);
561	return error;
562}
563
564static int
565xfs_growfs_log_private(
566	xfs_mount_t		*mp,	/* mount point for filesystem */
567	xfs_growfs_log_t	*in)	/* growfs log input struct */
568{
569	xfs_extlen_t		nb;
570
571	nb = in->newblocks;
572	if (nb < XFS_MIN_LOG_BLOCKS || nb < XFS_B_TO_FSB(mp, XFS_MIN_LOG_BYTES))
573		return -EINVAL;
574	if (nb == mp->m_sb.sb_logblocks &&
575	    in->isint == (mp->m_sb.sb_logstart != 0))
576		return -EINVAL;
577	/*
578	 * Moving the log is hard, need new interfaces to sync
579	 * the log first, hold off all activity while moving it.
580	 * Can have shorter or longer log in the same space,
581	 * or transform internal to external log or vice versa.
582	 */
583	return -ENOSYS;
584}
585
586/*
587 * protected versions of growfs function acquire and release locks on the mount
588 * point - exported through ioctls: XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG,
589 * XFS_IOC_FSGROWFSRT
590 */
591
592
593int
594xfs_growfs_data(
595	xfs_mount_t		*mp,
596	xfs_growfs_data_t	*in)
597{
598	int error;
599
600	if (!capable(CAP_SYS_ADMIN))
601		return -EPERM;
602	if (!mutex_trylock(&mp->m_growlock))
603		return -EWOULDBLOCK;
604	error = xfs_growfs_data_private(mp, in);
605	/*
606	 * Increment the generation unconditionally, the error could be from
607	 * updating the secondary superblocks, in which case the new size
608	 * is live already.
609	 */
610	mp->m_generation++;
611	mutex_unlock(&mp->m_growlock);
612	return error;
613}
614
615int
616xfs_growfs_log(
617	xfs_mount_t		*mp,
618	xfs_growfs_log_t	*in)
619{
620	int error;
621
622	if (!capable(CAP_SYS_ADMIN))
623		return -EPERM;
624	if (!mutex_trylock(&mp->m_growlock))
625		return -EWOULDBLOCK;
626	error = xfs_growfs_log_private(mp, in);
627	mutex_unlock(&mp->m_growlock);
628	return error;
629}
630
631/*
632 * exported through ioctl XFS_IOC_FSCOUNTS
633 */
634
635int
636xfs_fs_counts(
637	xfs_mount_t		*mp,
638	xfs_fsop_counts_t	*cnt)
639{
640	cnt->allocino = percpu_counter_read_positive(&mp->m_icount);
641	cnt->freeino = percpu_counter_read_positive(&mp->m_ifree);
642	cnt->freedata = percpu_counter_read_positive(&mp->m_fdblocks) -
643							XFS_ALLOC_SET_ASIDE(mp);
644
645	spin_lock(&mp->m_sb_lock);
646	cnt->freertx = mp->m_sb.sb_frextents;
647	spin_unlock(&mp->m_sb_lock);
648	return 0;
649}
650
651/*
652 * exported through ioctl XFS_IOC_SET_RESBLKS & XFS_IOC_GET_RESBLKS
653 *
654 * xfs_reserve_blocks is called to set m_resblks
655 * in the in-core mount table. The number of unused reserved blocks
656 * is kept in m_resblks_avail.
657 *
658 * Reserve the requested number of blocks if available. Otherwise return
659 * as many as possible to satisfy the request. The actual number
660 * reserved are returned in outval
661 *
662 * A null inval pointer indicates that only the current reserved blocks
663 * available  should  be returned no settings are changed.
664 */
665
666int
667xfs_reserve_blocks(
668	xfs_mount_t             *mp,
669	__uint64_t              *inval,
670	xfs_fsop_resblks_t      *outval)
671{
672	__int64_t		lcounter, delta, fdblks_delta;
673	__uint64_t		request;
674
675	/* If inval is null, report current values and return */
676	if (inval == (__uint64_t *)NULL) {
677		if (!outval)
678			return -EINVAL;
679		outval->resblks = mp->m_resblks;
680		outval->resblks_avail = mp->m_resblks_avail;
681		return 0;
682	}
683
684	request = *inval;
685
686	/*
687	 * With per-cpu counters, this becomes an interesting
688	 * problem. we needto work out if we are freeing or allocation
689	 * blocks first, then we can do the modification as necessary.
690	 *
691	 * We do this under the m_sb_lock so that if we are near
692	 * ENOSPC, we will hold out any changes while we work out
693	 * what to do. This means that the amount of free space can
694	 * change while we do this, so we need to retry if we end up
695	 * trying to reserve more space than is available.
696	 */
697retry:
698	spin_lock(&mp->m_sb_lock);
699
700	/*
701	 * If our previous reservation was larger than the current value,
702	 * then move any unused blocks back to the free pool.
703	 */
704	fdblks_delta = 0;
705	if (mp->m_resblks > request) {
706		lcounter = mp->m_resblks_avail - request;
707		if (lcounter  > 0) {		/* release unused blocks */
708			fdblks_delta = lcounter;
709			mp->m_resblks_avail -= lcounter;
710		}
711		mp->m_resblks = request;
712	} else {
713		__int64_t	free;
714
715		free = percpu_counter_sum(&mp->m_fdblocks) -
716							XFS_ALLOC_SET_ASIDE(mp);
717		if (!free)
718			goto out; /* ENOSPC and fdblks_delta = 0 */
719
720		delta = request - mp->m_resblks;
721		lcounter = free - delta;
722		if (lcounter < 0) {
723			/* We can't satisfy the request, just get what we can */
724			mp->m_resblks += free;
725			mp->m_resblks_avail += free;
726			fdblks_delta = -free;
727		} else {
728			fdblks_delta = -delta;
729			mp->m_resblks = request;
730			mp->m_resblks_avail += delta;
731		}
732	}
733out:
734	if (outval) {
735		outval->resblks = mp->m_resblks;
736		outval->resblks_avail = mp->m_resblks_avail;
737	}
738	spin_unlock(&mp->m_sb_lock);
739
740	if (fdblks_delta) {
741		/*
742		 * If we are putting blocks back here, m_resblks_avail is
743		 * already at its max so this will put it in the free pool.
744		 *
745		 * If we need space, we'll either succeed in getting it
746		 * from the free block count or we'll get an enospc. If
747		 * we get a ENOSPC, it means things changed while we were
748		 * calculating fdblks_delta and so we should try again to
749		 * see if there is anything left to reserve.
750		 *
751		 * Don't set the reserved flag here - we don't want to reserve
752		 * the extra reserve blocks from the reserve.....
753		 */
754		int error;
755		error = xfs_mod_fdblocks(mp, fdblks_delta, 0);
756		if (error == -ENOSPC)
757			goto retry;
758	}
759	return 0;
760}
761
762int
763xfs_fs_goingdown(
764	xfs_mount_t	*mp,
765	__uint32_t	inflags)
766{
767	switch (inflags) {
768	case XFS_FSOP_GOING_FLAGS_DEFAULT: {
769		struct super_block *sb = freeze_bdev(mp->m_super->s_bdev);
770
771		if (sb && !IS_ERR(sb)) {
772			xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
773			thaw_bdev(sb->s_bdev, sb);
774		}
775
776		break;
777	}
778	case XFS_FSOP_GOING_FLAGS_LOGFLUSH:
779		xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
780		break;
781	case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH:
782		xfs_force_shutdown(mp,
783				SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR);
784		break;
785	default:
786		return -EINVAL;
787	}
788
789	return 0;
790}
791
792/*
793 * Force a shutdown of the filesystem instantly while keeping the filesystem
794 * consistent. We don't do an unmount here; just shutdown the shop, make sure
795 * that absolutely nothing persistent happens to this filesystem after this
796 * point.
797 */
798void
799xfs_do_force_shutdown(
800	xfs_mount_t	*mp,
801	int		flags,
802	char		*fname,
803	int		lnnum)
804{
805	int		logerror;
806
807	logerror = flags & SHUTDOWN_LOG_IO_ERROR;
808
809	if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
810		xfs_notice(mp,
811	"%s(0x%x) called from line %d of file %s.  Return address = 0x%p",
812			__func__, flags, lnnum, fname, __return_address);
813	}
814	/*
815	 * No need to duplicate efforts.
816	 */
817	if (XFS_FORCED_SHUTDOWN(mp) && !logerror)
818		return;
819
820	/*
821	 * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't
822	 * queue up anybody new on the log reservations, and wakes up
823	 * everybody who's sleeping on log reservations to tell them
824	 * the bad news.
825	 */
826	if (xfs_log_force_umount(mp, logerror))
827		return;
828
829	if (flags & SHUTDOWN_CORRUPT_INCORE) {
830		xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT,
831    "Corruption of in-memory data detected.  Shutting down filesystem");
832		if (XFS_ERRLEVEL_HIGH <= xfs_error_level)
833			xfs_stack_trace();
834	} else if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
835		if (logerror) {
836			xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR,
837		"Log I/O Error Detected.  Shutting down filesystem");
838		} else if (flags & SHUTDOWN_DEVICE_REQ) {
839			xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
840		"All device paths lost.  Shutting down filesystem");
841		} else if (!(flags & SHUTDOWN_REMOTE_REQ)) {
842			xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
843		"I/O Error Detected. Shutting down filesystem");
844		}
845	}
846	if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
847		xfs_alert(mp,
848	"Please umount the filesystem and rectify the problem(s)");
849	}
850}
851