1 |
1275 |
phoenix |
/*
|
2 |
|
|
* Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
|
3 |
|
|
*
|
4 |
|
|
* This program is free software; you can redistribute it and/or modify it
|
5 |
|
|
* under the terms of version 2 of the GNU General Public License as
|
6 |
|
|
* published by the Free Software Foundation.
|
7 |
|
|
*
|
8 |
|
|
* This program is distributed in the hope that it would be useful, but
|
9 |
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
10 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
11 |
|
|
*
|
12 |
|
|
* Further, this software is distributed without any warranty that it is
|
13 |
|
|
* free of the rightful claim of any third person regarding infringement
|
14 |
|
|
* or the like. Any license provided herein, whether implied or
|
15 |
|
|
* otherwise, applies only to this software file. Patent licenses, if
|
16 |
|
|
* any, provided herein do not apply to combinations of this program with
|
17 |
|
|
* other software, or any other product whatsoever.
|
18 |
|
|
*
|
19 |
|
|
* You should have received a copy of the GNU General Public License along
|
20 |
|
|
* with this program; if not, write the Free Software Foundation, Inc., 59
|
21 |
|
|
* Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
22 |
|
|
*
|
23 |
|
|
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
|
24 |
|
|
* Mountain View, CA 94043, or:
|
25 |
|
|
*
|
26 |
|
|
* http://www.sgi.com
|
27 |
|
|
*
|
28 |
|
|
* For further information regarding this notice, see:
|
29 |
|
|
*
|
30 |
|
|
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
|
31 |
|
|
*/
|
32 |
|
|
|
33 |
|
|
#include "xfs.h"
|
34 |
|
|
#include "xfs_macros.h"
|
35 |
|
|
#include "xfs_types.h"
|
36 |
|
|
#include "xfs_inum.h"
|
37 |
|
|
#include "xfs_log.h"
|
38 |
|
|
#include "xfs_trans.h"
|
39 |
|
|
#include "xfs_sb.h"
|
40 |
|
|
#include "xfs_dir.h"
|
41 |
|
|
#include "xfs_dmapi.h"
|
42 |
|
|
#include "xfs_mount.h"
|
43 |
|
|
#include "xfs_ag.h"
|
44 |
|
|
#include "xfs_alloc_btree.h"
|
45 |
|
|
#include "xfs_bmap_btree.h"
|
46 |
|
|
#include "xfs_ialloc_btree.h"
|
47 |
|
|
#include "xfs_btree.h"
|
48 |
|
|
#include "xfs_error.h"
|
49 |
|
|
#include "xfs_alloc.h"
|
50 |
|
|
#include "xfs_ialloc.h"
|
51 |
|
|
#include "xfs_fsops.h"
|
52 |
|
|
#include "xfs_itable.h"
|
53 |
|
|
#include "xfs_rw.h"
|
54 |
|
|
#include "xfs_refcache.h"
|
55 |
|
|
#include "xfs_trans_space.h"
|
56 |
|
|
#include "xfs_rtalloc.h"
|
57 |
|
|
#include "xfs_dir2.h"
|
58 |
|
|
#include "xfs_attr_sf.h"
|
59 |
|
|
#include "xfs_dir_sf.h"
|
60 |
|
|
#include "xfs_dir2_sf.h"
|
61 |
|
|
#include "xfs_dinode.h"
|
62 |
|
|
#include "xfs_inode.h"
|
63 |
|
|
#include "xfs_inode_item.h"
|
64 |
|
|
|
65 |
|
|
/*
|
66 |
|
|
* File system operations
|
67 |
|
|
*/
|
68 |
|
|
|
69 |
|
|
int
|
70 |
|
|
xfs_fs_geometry(
|
71 |
|
|
xfs_mount_t *mp,
|
72 |
|
|
xfs_fsop_geom_t *geo,
|
73 |
|
|
int new_version)
|
74 |
|
|
{
|
75 |
|
|
geo->blocksize = mp->m_sb.sb_blocksize;
|
76 |
|
|
geo->rtextsize = mp->m_sb.sb_rextsize;
|
77 |
|
|
geo->agblocks = mp->m_sb.sb_agblocks;
|
78 |
|
|
geo->agcount = mp->m_sb.sb_agcount;
|
79 |
|
|
geo->logblocks = mp->m_sb.sb_logblocks;
|
80 |
|
|
geo->sectsize = mp->m_sb.sb_sectsize;
|
81 |
|
|
geo->inodesize = mp->m_sb.sb_inodesize;
|
82 |
|
|
geo->imaxpct = mp->m_sb.sb_imax_pct;
|
83 |
|
|
geo->datablocks = mp->m_sb.sb_dblocks;
|
84 |
|
|
geo->rtblocks = mp->m_sb.sb_rblocks;
|
85 |
|
|
geo->rtextents = mp->m_sb.sb_rextents;
|
86 |
|
|
geo->logstart = mp->m_sb.sb_logstart;
|
87 |
|
|
ASSERT(sizeof(geo->uuid)==sizeof(mp->m_sb.sb_uuid));
|
88 |
|
|
memcpy(geo->uuid, &mp->m_sb.sb_uuid, sizeof(mp->m_sb.sb_uuid));
|
89 |
|
|
if (new_version >= 2) {
|
90 |
|
|
geo->sunit = mp->m_sb.sb_unit;
|
91 |
|
|
geo->swidth = mp->m_sb.sb_width;
|
92 |
|
|
}
|
93 |
|
|
if (new_version >= 3) {
|
94 |
|
|
geo->version = XFS_FSOP_GEOM_VERSION;
|
95 |
|
|
geo->flags =
|
96 |
|
|
(XFS_SB_VERSION_HASATTR(&mp->m_sb) ?
|
97 |
|
|
XFS_FSOP_GEOM_FLAGS_ATTR : 0) |
|
98 |
|
|
(XFS_SB_VERSION_HASNLINK(&mp->m_sb) ?
|
99 |
|
|
XFS_FSOP_GEOM_FLAGS_NLINK : 0) |
|
100 |
|
|
(XFS_SB_VERSION_HASQUOTA(&mp->m_sb) ?
|
101 |
|
|
XFS_FSOP_GEOM_FLAGS_QUOTA : 0) |
|
102 |
|
|
(XFS_SB_VERSION_HASALIGN(&mp->m_sb) ?
|
103 |
|
|
XFS_FSOP_GEOM_FLAGS_IALIGN : 0) |
|
104 |
|
|
(XFS_SB_VERSION_HASDALIGN(&mp->m_sb) ?
|
105 |
|
|
XFS_FSOP_GEOM_FLAGS_DALIGN : 0) |
|
106 |
|
|
(XFS_SB_VERSION_HASSHARED(&mp->m_sb) ?
|
107 |
|
|
XFS_FSOP_GEOM_FLAGS_SHARED : 0) |
|
108 |
|
|
(XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb) ?
|
109 |
|
|
XFS_FSOP_GEOM_FLAGS_EXTFLG : 0) |
|
110 |
|
|
(XFS_SB_VERSION_HASDIRV2(&mp->m_sb) ?
|
111 |
|
|
XFS_FSOP_GEOM_FLAGS_DIRV2 : 0) |
|
112 |
|
|
(XFS_SB_VERSION_HASSECTOR(&mp->m_sb) ?
|
113 |
|
|
XFS_FSOP_GEOM_FLAGS_SECTOR : 0);
|
114 |
|
|
geo->logsectsize = XFS_SB_VERSION_HASSECTOR(&mp->m_sb) ?
|
115 |
|
|
mp->m_sb.sb_logsectsize : BBSIZE;
|
116 |
|
|
geo->rtsectsize = mp->m_sb.sb_blocksize;
|
117 |
|
|
geo->dirblocksize = mp->m_dirblksize;
|
118 |
|
|
}
|
119 |
|
|
if (new_version >= 4) {
|
120 |
|
|
geo->flags |=
|
121 |
|
|
(XFS_SB_VERSION_HASLOGV2(&mp->m_sb) ?
|
122 |
|
|
XFS_FSOP_GEOM_FLAGS_LOGV2 : 0);
|
123 |
|
|
geo->logsunit = mp->m_sb.sb_logsunit;
|
124 |
|
|
}
|
125 |
|
|
return 0;
|
126 |
|
|
}
|
127 |
|
|
|
128 |
|
|
static int
|
129 |
|
|
xfs_growfs_data_private(
|
130 |
|
|
xfs_mount_t *mp, /* mount point for filesystem */
|
131 |
|
|
xfs_growfs_data_t *in) /* growfs data input struct */
|
132 |
|
|
{
|
133 |
|
|
xfs_agf_t *agf;
|
134 |
|
|
xfs_agi_t *agi;
|
135 |
|
|
xfs_agnumber_t agno;
|
136 |
|
|
xfs_extlen_t agsize;
|
137 |
|
|
xfs_extlen_t tmpsize;
|
138 |
|
|
xfs_alloc_rec_t *arec;
|
139 |
|
|
xfs_btree_sblock_t *block;
|
140 |
|
|
xfs_buf_t *bp;
|
141 |
|
|
int bucket;
|
142 |
|
|
int dpct;
|
143 |
|
|
int error;
|
144 |
|
|
xfs_agnumber_t nagcount;
|
145 |
|
|
xfs_rfsblock_t nb, nb_mod;
|
146 |
|
|
xfs_rfsblock_t new;
|
147 |
|
|
xfs_rfsblock_t nfree;
|
148 |
|
|
xfs_agnumber_t oagcount;
|
149 |
|
|
int pct;
|
150 |
|
|
xfs_sb_t *sbp;
|
151 |
|
|
xfs_trans_t *tp;
|
152 |
|
|
|
153 |
|
|
nb = in->newblocks;
|
154 |
|
|
pct = in->imaxpct;
|
155 |
|
|
if (nb < mp->m_sb.sb_dblocks || pct < 0 || pct > 100)
|
156 |
|
|
return XFS_ERROR(EINVAL);
|
157 |
|
|
dpct = pct - mp->m_sb.sb_imax_pct;
|
158 |
|
|
error = xfs_read_buf(mp, mp->m_ddev_targp,
|
159 |
|
|
XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
|
160 |
|
|
XFS_FSS_TO_BB(mp, 1), 0, &bp);
|
161 |
|
|
if (error)
|
162 |
|
|
return error;
|
163 |
|
|
ASSERT(bp);
|
164 |
|
|
xfs_buf_relse(bp);
|
165 |
|
|
|
166 |
|
|
new = nb; /* use new as a temporary here */
|
167 |
|
|
nb_mod = do_div(new, mp->m_sb.sb_agblocks);
|
168 |
|
|
nagcount = new + (nb_mod != 0);
|
169 |
|
|
if (nb_mod && nb_mod < XFS_MIN_AG_BLOCKS) {
|
170 |
|
|
nagcount--;
|
171 |
|
|
nb = nagcount * mp->m_sb.sb_agblocks;
|
172 |
|
|
if (nb < mp->m_sb.sb_dblocks)
|
173 |
|
|
return XFS_ERROR(EINVAL);
|
174 |
|
|
}
|
175 |
|
|
new = nb - mp->m_sb.sb_dblocks;
|
176 |
|
|
oagcount = mp->m_sb.sb_agcount;
|
177 |
|
|
if (nagcount > oagcount) {
|
178 |
|
|
down_write(&mp->m_peraglock);
|
179 |
|
|
mp->m_perag = kmem_realloc(mp->m_perag,
|
180 |
|
|
sizeof(xfs_perag_t) * nagcount,
|
181 |
|
|
sizeof(xfs_perag_t) * oagcount,
|
182 |
|
|
KM_SLEEP);
|
183 |
|
|
memset(&mp->m_perag[oagcount], 0,
|
184 |
|
|
(nagcount - oagcount) * sizeof(xfs_perag_t));
|
185 |
|
|
mp->m_flags |= XFS_MOUNT_32BITINODES;
|
186 |
|
|
xfs_initialize_perag(mp, nagcount);
|
187 |
|
|
up_write(&mp->m_peraglock);
|
188 |
|
|
}
|
189 |
|
|
tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS);
|
190 |
|
|
if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp),
|
191 |
|
|
XFS_GROWDATA_LOG_RES(mp), 0, 0, 0))) {
|
192 |
|
|
xfs_trans_cancel(tp, 0);
|
193 |
|
|
return error;
|
194 |
|
|
}
|
195 |
|
|
|
196 |
|
|
nfree = 0;
|
197 |
|
|
for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) {
|
198 |
|
|
/*
|
199 |
|
|
* AG freelist header block
|
200 |
|
|
*/
|
201 |
|
|
bp = xfs_buf_get(mp->m_ddev_targp,
|
202 |
|
|
XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
|
203 |
|
|
XFS_FSS_TO_BB(mp, 1), 0);
|
204 |
|
|
agf = XFS_BUF_TO_AGF(bp);
|
205 |
|
|
memset(agf, 0, mp->m_sb.sb_sectsize);
|
206 |
|
|
INT_SET(agf->agf_magicnum, ARCH_CONVERT, XFS_AGF_MAGIC);
|
207 |
|
|
INT_SET(agf->agf_versionnum, ARCH_CONVERT, XFS_AGF_VERSION);
|
208 |
|
|
INT_SET(agf->agf_seqno, ARCH_CONVERT, agno);
|
209 |
|
|
if (agno == nagcount - 1)
|
210 |
|
|
agsize =
|
211 |
|
|
nb -
|
212 |
|
|
(agno * (xfs_rfsblock_t)mp->m_sb.sb_agblocks);
|
213 |
|
|
else
|
214 |
|
|
agsize = mp->m_sb.sb_agblocks;
|
215 |
|
|
INT_SET(agf->agf_length, ARCH_CONVERT, agsize);
|
216 |
|
|
INT_SET(agf->agf_roots[XFS_BTNUM_BNOi], ARCH_CONVERT,
|
217 |
|
|
XFS_BNO_BLOCK(mp));
|
218 |
|
|
INT_SET(agf->agf_roots[XFS_BTNUM_CNTi], ARCH_CONVERT,
|
219 |
|
|
XFS_CNT_BLOCK(mp));
|
220 |
|
|
INT_SET(agf->agf_levels[XFS_BTNUM_BNOi], ARCH_CONVERT, 1);
|
221 |
|
|
INT_SET(agf->agf_levels[XFS_BTNUM_CNTi], ARCH_CONVERT, 1);
|
222 |
|
|
INT_ZERO(agf->agf_flfirst, ARCH_CONVERT);
|
223 |
|
|
INT_SET(agf->agf_fllast, ARCH_CONVERT, XFS_AGFL_SIZE(mp) - 1);
|
224 |
|
|
INT_ZERO(agf->agf_flcount, ARCH_CONVERT);
|
225 |
|
|
tmpsize = agsize - XFS_PREALLOC_BLOCKS(mp);
|
226 |
|
|
INT_SET(agf->agf_freeblks, ARCH_CONVERT, tmpsize);
|
227 |
|
|
INT_SET(agf->agf_longest, ARCH_CONVERT, tmpsize);
|
228 |
|
|
error = xfs_bwrite(mp, bp);
|
229 |
|
|
if (error) {
|
230 |
|
|
goto error0;
|
231 |
|
|
}
|
232 |
|
|
/*
|
233 |
|
|
* AG inode header block
|
234 |
|
|
*/
|
235 |
|
|
bp = xfs_buf_get(mp->m_ddev_targp,
|
236 |
|
|
XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
|
237 |
|
|
XFS_FSS_TO_BB(mp, 1), 0);
|
238 |
|
|
agi = XFS_BUF_TO_AGI(bp);
|
239 |
|
|
memset(agi, 0, mp->m_sb.sb_sectsize);
|
240 |
|
|
INT_SET(agi->agi_magicnum, ARCH_CONVERT, XFS_AGI_MAGIC);
|
241 |
|
|
INT_SET(agi->agi_versionnum, ARCH_CONVERT, XFS_AGI_VERSION);
|
242 |
|
|
INT_SET(agi->agi_seqno, ARCH_CONVERT, agno);
|
243 |
|
|
INT_SET(agi->agi_length, ARCH_CONVERT, agsize);
|
244 |
|
|
INT_ZERO(agi->agi_count, ARCH_CONVERT);
|
245 |
|
|
INT_SET(agi->agi_root, ARCH_CONVERT, XFS_IBT_BLOCK(mp));
|
246 |
|
|
INT_SET(agi->agi_level, ARCH_CONVERT, 1);
|
247 |
|
|
INT_ZERO(agi->agi_freecount, ARCH_CONVERT);
|
248 |
|
|
INT_SET(agi->agi_newino, ARCH_CONVERT, NULLAGINO);
|
249 |
|
|
INT_SET(agi->agi_dirino, ARCH_CONVERT, NULLAGINO);
|
250 |
|
|
for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
|
251 |
|
|
INT_SET(agi->agi_unlinked[bucket], ARCH_CONVERT,
|
252 |
|
|
NULLAGINO);
|
253 |
|
|
error = xfs_bwrite(mp, bp);
|
254 |
|
|
if (error) {
|
255 |
|
|
goto error0;
|
256 |
|
|
}
|
257 |
|
|
/*
|
258 |
|
|
* BNO btree root block
|
259 |
|
|
*/
|
260 |
|
|
bp = xfs_buf_get(mp->m_ddev_targp,
|
261 |
|
|
XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)),
|
262 |
|
|
BTOBB(mp->m_sb.sb_blocksize), 0);
|
263 |
|
|
block = XFS_BUF_TO_SBLOCK(bp);
|
264 |
|
|
memset(block, 0, mp->m_sb.sb_blocksize);
|
265 |
|
|
INT_SET(block->bb_magic, ARCH_CONVERT, XFS_ABTB_MAGIC);
|
266 |
|
|
INT_ZERO(block->bb_level, ARCH_CONVERT);
|
267 |
|
|
INT_SET(block->bb_numrecs, ARCH_CONVERT, 1);
|
268 |
|
|
INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK);
|
269 |
|
|
INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK);
|
270 |
|
|
arec = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc,
|
271 |
|
|
block, 1, mp->m_alloc_mxr[0]);
|
272 |
|
|
INT_SET(arec->ar_startblock, ARCH_CONVERT,
|
273 |
|
|
XFS_PREALLOC_BLOCKS(mp));
|
274 |
|
|
INT_SET(arec->ar_blockcount, ARCH_CONVERT,
|
275 |
|
|
agsize - INT_GET(arec->ar_startblock, ARCH_CONVERT));
|
276 |
|
|
error = xfs_bwrite(mp, bp);
|
277 |
|
|
if (error) {
|
278 |
|
|
goto error0;
|
279 |
|
|
}
|
280 |
|
|
/*
|
281 |
|
|
* CNT btree root block
|
282 |
|
|
*/
|
283 |
|
|
bp = xfs_buf_get(mp->m_ddev_targp,
|
284 |
|
|
XFS_AGB_TO_DADDR(mp, agno, XFS_CNT_BLOCK(mp)),
|
285 |
|
|
BTOBB(mp->m_sb.sb_blocksize), 0);
|
286 |
|
|
block = XFS_BUF_TO_SBLOCK(bp);
|
287 |
|
|
memset(block, 0, mp->m_sb.sb_blocksize);
|
288 |
|
|
INT_SET(block->bb_magic, ARCH_CONVERT, XFS_ABTC_MAGIC);
|
289 |
|
|
INT_ZERO(block->bb_level, ARCH_CONVERT);
|
290 |
|
|
INT_SET(block->bb_numrecs, ARCH_CONVERT, 1);
|
291 |
|
|
INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK);
|
292 |
|
|
INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK);
|
293 |
|
|
arec = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc,
|
294 |
|
|
block, 1, mp->m_alloc_mxr[0]);
|
295 |
|
|
INT_SET(arec->ar_startblock, ARCH_CONVERT,
|
296 |
|
|
XFS_PREALLOC_BLOCKS(mp));
|
297 |
|
|
INT_SET(arec->ar_blockcount, ARCH_CONVERT,
|
298 |
|
|
agsize - INT_GET(arec->ar_startblock, ARCH_CONVERT));
|
299 |
|
|
nfree += INT_GET(arec->ar_blockcount, ARCH_CONVERT);
|
300 |
|
|
error = xfs_bwrite(mp, bp);
|
301 |
|
|
if (error) {
|
302 |
|
|
goto error0;
|
303 |
|
|
}
|
304 |
|
|
/*
|
305 |
|
|
* INO btree root block
|
306 |
|
|
*/
|
307 |
|
|
bp = xfs_buf_get(mp->m_ddev_targp,
|
308 |
|
|
XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)),
|
309 |
|
|
BTOBB(mp->m_sb.sb_blocksize), 0);
|
310 |
|
|
block = XFS_BUF_TO_SBLOCK(bp);
|
311 |
|
|
memset(block, 0, mp->m_sb.sb_blocksize);
|
312 |
|
|
INT_SET(block->bb_magic, ARCH_CONVERT, XFS_IBT_MAGIC);
|
313 |
|
|
INT_ZERO(block->bb_level, ARCH_CONVERT);
|
314 |
|
|
INT_ZERO(block->bb_numrecs, ARCH_CONVERT);
|
315 |
|
|
INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK);
|
316 |
|
|
INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK);
|
317 |
|
|
error = xfs_bwrite(mp, bp);
|
318 |
|
|
if (error) {
|
319 |
|
|
goto error0;
|
320 |
|
|
}
|
321 |
|
|
}
|
322 |
|
|
xfs_trans_agblocks_delta(tp, nfree);
|
323 |
|
|
/*
|
324 |
|
|
* There are new blocks in the old last a.g.
|
325 |
|
|
*/
|
326 |
|
|
if (new) {
|
327 |
|
|
/*
|
328 |
|
|
* Change the agi length.
|
329 |
|
|
*/
|
330 |
|
|
error = xfs_ialloc_read_agi(mp, tp, agno, &bp);
|
331 |
|
|
if (error) {
|
332 |
|
|
goto error0;
|
333 |
|
|
}
|
334 |
|
|
ASSERT(bp);
|
335 |
|
|
agi = XFS_BUF_TO_AGI(bp);
|
336 |
|
|
INT_MOD(agi->agi_length, ARCH_CONVERT, new);
|
337 |
|
|
ASSERT(nagcount == oagcount ||
|
338 |
|
|
INT_GET(agi->agi_length, ARCH_CONVERT) ==
|
339 |
|
|
mp->m_sb.sb_agblocks);
|
340 |
|
|
xfs_ialloc_log_agi(tp, bp, XFS_AGI_LENGTH);
|
341 |
|
|
/*
|
342 |
|
|
* Change agf length.
|
343 |
|
|
*/
|
344 |
|
|
error = xfs_alloc_read_agf(mp, tp, agno, 0, &bp);
|
345 |
|
|
if (error) {
|
346 |
|
|
goto error0;
|
347 |
|
|
}
|
348 |
|
|
ASSERT(bp);
|
349 |
|
|
agf = XFS_BUF_TO_AGF(bp);
|
350 |
|
|
INT_MOD(agf->agf_length, ARCH_CONVERT, new);
|
351 |
|
|
ASSERT(INT_GET(agf->agf_length, ARCH_CONVERT) ==
|
352 |
|
|
INT_GET(agi->agi_length, ARCH_CONVERT));
|
353 |
|
|
/*
|
354 |
|
|
* Free the new space.
|
355 |
|
|
*/
|
356 |
|
|
error = xfs_free_extent(tp, XFS_AGB_TO_FSB(mp, agno,
|
357 |
|
|
INT_GET(agf->agf_length, ARCH_CONVERT) - new), new);
|
358 |
|
|
if (error) {
|
359 |
|
|
goto error0;
|
360 |
|
|
}
|
361 |
|
|
}
|
362 |
|
|
if (nagcount > oagcount)
|
363 |
|
|
xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount);
|
364 |
|
|
if (nb > mp->m_sb.sb_dblocks)
|
365 |
|
|
xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS,
|
366 |
|
|
nb - mp->m_sb.sb_dblocks);
|
367 |
|
|
if (nfree)
|
368 |
|
|
xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, nfree);
|
369 |
|
|
if (dpct)
|
370 |
|
|
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct);
|
371 |
|
|
error = xfs_trans_commit(tp, 0, NULL);
|
372 |
|
|
if (error) {
|
373 |
|
|
return error;
|
374 |
|
|
}
|
375 |
|
|
if (mp->m_sb.sb_imax_pct) {
|
376 |
|
|
__uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct;
|
377 |
|
|
do_div(icount, 100);
|
378 |
|
|
mp->m_maxicount = icount << mp->m_sb.sb_inopblog;
|
379 |
|
|
} else
|
380 |
|
|
mp->m_maxicount = 0;
|
381 |
|
|
for (agno = 1; agno < nagcount; agno++) {
|
382 |
|
|
error = xfs_read_buf(mp, mp->m_ddev_targp,
|
383 |
|
|
XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
|
384 |
|
|
XFS_FSS_TO_BB(mp, 1), 0, &bp);
|
385 |
|
|
if (error) {
|
386 |
|
|
xfs_fs_cmn_err(CE_WARN, mp,
|
387 |
|
|
"error %d reading secondary superblock for ag %d",
|
388 |
|
|
error, agno);
|
389 |
|
|
break;
|
390 |
|
|
}
|
391 |
|
|
sbp = XFS_BUF_TO_SBP(bp);
|
392 |
|
|
xfs_xlatesb(sbp, &mp->m_sb, -1, ARCH_CONVERT, XFS_SB_ALL_BITS);
|
393 |
|
|
/*
|
394 |
|
|
* If we get an error writing out the alternate superblocks,
|
395 |
|
|
* just issue a warning and continue. The real work is
|
396 |
|
|
* already done and committed.
|
397 |
|
|
*/
|
398 |
|
|
if (!(error = xfs_bwrite(mp, bp))) {
|
399 |
|
|
continue;
|
400 |
|
|
} else {
|
401 |
|
|
xfs_fs_cmn_err(CE_WARN, mp,
|
402 |
|
|
"write error %d updating secondary superblock for ag %d",
|
403 |
|
|
error, agno);
|
404 |
|
|
break; /* no point in continuing */
|
405 |
|
|
}
|
406 |
|
|
}
|
407 |
|
|
return 0;
|
408 |
|
|
|
409 |
|
|
error0:
|
410 |
|
|
xfs_trans_cancel(tp, XFS_TRANS_ABORT);
|
411 |
|
|
return error;
|
412 |
|
|
}
|
413 |
|
|
|
414 |
|
|
static int
|
415 |
|
|
xfs_growfs_log_private(
|
416 |
|
|
xfs_mount_t *mp, /* mount point for filesystem */
|
417 |
|
|
xfs_growfs_log_t *in) /* growfs log input struct */
|
418 |
|
|
{
|
419 |
|
|
xfs_extlen_t nb;
|
420 |
|
|
|
421 |
|
|
nb = in->newblocks;
|
422 |
|
|
if (nb < XFS_MIN_LOG_BLOCKS || nb < XFS_B_TO_FSB(mp, XFS_MIN_LOG_BYTES))
|
423 |
|
|
return XFS_ERROR(EINVAL);
|
424 |
|
|
if (nb == mp->m_sb.sb_logblocks &&
|
425 |
|
|
in->isint == (mp->m_sb.sb_logstart != 0))
|
426 |
|
|
return XFS_ERROR(EINVAL);
|
427 |
|
|
/*
|
428 |
|
|
* Moving the log is hard, need new interfaces to sync
|
429 |
|
|
* the log first, hold off all activity while moving it.
|
430 |
|
|
* Can have shorter or longer log in the same space,
|
431 |
|
|
* or transform internal to external log or vice versa.
|
432 |
|
|
*/
|
433 |
|
|
return XFS_ERROR(ENOSYS);
|
434 |
|
|
}
|
435 |
|
|
|
436 |
|
|
/*
|
437 |
|
|
* protected versions of growfs function acquire and release locks on the mount
|
438 |
|
|
* point - exported through ioctls: XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG,
|
439 |
|
|
* XFS_IOC_FSGROWFSRT
|
440 |
|
|
*/
|
441 |
|
|
|
442 |
|
|
|
443 |
|
|
int
|
444 |
|
|
xfs_growfs_data(
|
445 |
|
|
xfs_mount_t *mp,
|
446 |
|
|
xfs_growfs_data_t *in)
|
447 |
|
|
{
|
448 |
|
|
int error;
|
449 |
|
|
if (!cpsema(&mp->m_growlock))
|
450 |
|
|
return XFS_ERROR(EWOULDBLOCK);
|
451 |
|
|
error = xfs_growfs_data_private(mp, in);
|
452 |
|
|
vsema(&mp->m_growlock);
|
453 |
|
|
return error;
|
454 |
|
|
}
|
455 |
|
|
|
456 |
|
|
int
|
457 |
|
|
xfs_growfs_log(
|
458 |
|
|
xfs_mount_t *mp,
|
459 |
|
|
xfs_growfs_log_t *in)
|
460 |
|
|
{
|
461 |
|
|
int error;
|
462 |
|
|
if (!cpsema(&mp->m_growlock))
|
463 |
|
|
return XFS_ERROR(EWOULDBLOCK);
|
464 |
|
|
error = xfs_growfs_log_private(mp, in);
|
465 |
|
|
vsema(&mp->m_growlock);
|
466 |
|
|
return error;
|
467 |
|
|
}
|
468 |
|
|
|
469 |
|
|
/*
|
470 |
|
|
* exported through ioctl XFS_IOC_FSCOUNTS
|
471 |
|
|
*/
|
472 |
|
|
|
473 |
|
|
int
|
474 |
|
|
xfs_fs_counts(
|
475 |
|
|
xfs_mount_t *mp,
|
476 |
|
|
xfs_fsop_counts_t *cnt)
|
477 |
|
|
{
|
478 |
|
|
unsigned long s;
|
479 |
|
|
|
480 |
|
|
s = XFS_SB_LOCK(mp);
|
481 |
|
|
cnt->freedata = mp->m_sb.sb_fdblocks;
|
482 |
|
|
cnt->freertx = mp->m_sb.sb_frextents;
|
483 |
|
|
cnt->freeino = mp->m_sb.sb_ifree;
|
484 |
|
|
cnt->allocino = mp->m_sb.sb_icount;
|
485 |
|
|
XFS_SB_UNLOCK(mp, s);
|
486 |
|
|
return 0;
|
487 |
|
|
}
|
488 |
|
|
|
489 |
|
|
/*
|
490 |
|
|
* exported through ioctl XFS_IOC_SET_RESBLKS & XFS_IOC_GET_RESBLKS
|
491 |
|
|
*
|
492 |
|
|
* xfs_reserve_blocks is called to set m_resblks
|
493 |
|
|
* in the in-core mount table. The number of unused reserved blocks
|
494 |
|
|
* is kept in m_resbls_avail.
|
495 |
|
|
*
|
496 |
|
|
* Reserve the requested number of blocks if available. Otherwise return
|
497 |
|
|
* as many as possible to satisfy the request. The actual number
|
498 |
|
|
* reserved are returned in outval
|
499 |
|
|
*
|
500 |
|
|
* A null inval pointer indicates that only the current reserved blocks
|
501 |
|
|
* available should be returned no settings are changed.
|
502 |
|
|
*/
|
503 |
|
|
|
504 |
|
|
int
|
505 |
|
|
xfs_reserve_blocks(
|
506 |
|
|
xfs_mount_t *mp,
|
507 |
|
|
__uint64_t *inval,
|
508 |
|
|
xfs_fsop_resblks_t *outval)
|
509 |
|
|
{
|
510 |
|
|
__uint64_t lcounter, delta;
|
511 |
|
|
__uint64_t request;
|
512 |
|
|
unsigned long s;
|
513 |
|
|
|
514 |
|
|
/* If inval is null, report current values and return */
|
515 |
|
|
|
516 |
|
|
if (inval == (__uint64_t *)NULL) {
|
517 |
|
|
outval->resblks = mp->m_resblks;
|
518 |
|
|
outval->resblks_avail = mp->m_resblks_avail;
|
519 |
|
|
return(0);
|
520 |
|
|
}
|
521 |
|
|
|
522 |
|
|
request = *inval;
|
523 |
|
|
s = XFS_SB_LOCK(mp);
|
524 |
|
|
|
525 |
|
|
/*
|
526 |
|
|
* If our previous reservation was larger than the current value,
|
527 |
|
|
* then move any unused blocks back to the free pool.
|
528 |
|
|
*/
|
529 |
|
|
|
530 |
|
|
if (mp->m_resblks > request) {
|
531 |
|
|
lcounter = mp->m_resblks_avail - request;
|
532 |
|
|
if (lcounter > 0) { /* release unused blocks */
|
533 |
|
|
mp->m_sb.sb_fdblocks += lcounter;
|
534 |
|
|
mp->m_resblks_avail -= lcounter;
|
535 |
|
|
}
|
536 |
|
|
mp->m_resblks = request;
|
537 |
|
|
} else {
|
538 |
|
|
delta = request - mp->m_resblks;
|
539 |
|
|
lcounter = mp->m_sb.sb_fdblocks;
|
540 |
|
|
lcounter -= delta;
|
541 |
|
|
if (lcounter < 0) {
|
542 |
|
|
/* We can't satisfy the request, just get what we can */
|
543 |
|
|
mp->m_resblks += mp->m_sb.sb_fdblocks;
|
544 |
|
|
mp->m_resblks_avail += mp->m_sb.sb_fdblocks;
|
545 |
|
|
mp->m_sb.sb_fdblocks = 0;
|
546 |
|
|
} else {
|
547 |
|
|
mp->m_sb.sb_fdblocks = lcounter;
|
548 |
|
|
mp->m_resblks = request;
|
549 |
|
|
mp->m_resblks_avail += delta;
|
550 |
|
|
}
|
551 |
|
|
}
|
552 |
|
|
|
553 |
|
|
outval->resblks = mp->m_resblks;
|
554 |
|
|
outval->resblks_avail = mp->m_resblks_avail;
|
555 |
|
|
XFS_SB_UNLOCK(mp, s);
|
556 |
|
|
return(0);
|
557 |
|
|
}
|
558 |
|
|
|
559 |
|
|
void
|
560 |
|
|
xfs_fs_log_dummy(xfs_mount_t *mp)
|
561 |
|
|
{
|
562 |
|
|
xfs_trans_t *tp;
|
563 |
|
|
xfs_inode_t *ip;
|
564 |
|
|
|
565 |
|
|
|
566 |
|
|
tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1);
|
567 |
|
|
atomic_inc(&mp->m_active_trans);
|
568 |
|
|
if (xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0)) {
|
569 |
|
|
xfs_trans_cancel(tp, 0);
|
570 |
|
|
return;
|
571 |
|
|
}
|
572 |
|
|
|
573 |
|
|
ip = mp->m_rootip;
|
574 |
|
|
xfs_ilock(ip, XFS_ILOCK_EXCL);
|
575 |
|
|
|
576 |
|
|
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
|
577 |
|
|
xfs_trans_ihold(tp, ip);
|
578 |
|
|
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
|
579 |
|
|
xfs_trans_commit(tp, XFS_TRANS_SYNC, NULL);
|
580 |
|
|
|
581 |
|
|
xfs_iunlock(ip, XFS_ILOCK_EXCL);
|
582 |
|
|
}
|
583 |
|
|
|
584 |
|
|
int
|
585 |
|
|
xfs_fs_freeze(
|
586 |
|
|
xfs_mount_t *mp)
|
587 |
|
|
{
|
588 |
|
|
vfs_t *vfsp;
|
589 |
|
|
/*REFERENCED*/
|
590 |
|
|
int error;
|
591 |
|
|
|
592 |
|
|
vfsp = XFS_MTOVFS(mp);
|
593 |
|
|
|
594 |
|
|
/* Stop new writers */
|
595 |
|
|
xfs_start_freeze(mp, XFS_FREEZE_WRITE);
|
596 |
|
|
|
597 |
|
|
/* Flush the refcache */
|
598 |
|
|
xfs_refcache_purge_mp(mp);
|
599 |
|
|
|
600 |
|
|
/* Flush delalloc and delwri data */
|
601 |
|
|
VFS_SYNC(vfsp, SYNC_DELWRI|SYNC_WAIT, NULL, error);
|
602 |
|
|
|
603 |
|
|
/* Pause transaction subsystem */
|
604 |
|
|
xfs_start_freeze(mp, XFS_FREEZE_TRANS);
|
605 |
|
|
|
606 |
|
|
/* Flush any remaining inodes into buffers */
|
607 |
|
|
VFS_SYNC(vfsp, SYNC_ATTR|SYNC_WAIT, NULL, error);
|
608 |
|
|
|
609 |
|
|
/* Push all buffers out to disk */
|
610 |
|
|
xfs_binval(mp->m_ddev_targp);
|
611 |
|
|
if (mp->m_rtdev_targp) {
|
612 |
|
|
xfs_binval(mp->m_rtdev_targp);
|
613 |
|
|
}
|
614 |
|
|
|
615 |
|
|
/* Push the superblock and write an unmount record */
|
616 |
|
|
xfs_log_unmount_write(mp);
|
617 |
|
|
xfs_unmountfs_writesb(mp);
|
618 |
|
|
|
619 |
|
|
return 0;
|
620 |
|
|
}
|
621 |
|
|
|
622 |
|
|
int
|
623 |
|
|
xfs_fs_thaw(
|
624 |
|
|
xfs_mount_t *mp)
|
625 |
|
|
{
|
626 |
|
|
xfs_finish_freeze(mp);
|
627 |
|
|
return 0;
|
628 |
|
|
}
|
629 |
|
|
|
630 |
|
|
int
|
631 |
|
|
xfs_fs_goingdown(
|
632 |
|
|
xfs_mount_t *mp,
|
633 |
|
|
__uint32_t inflags)
|
634 |
|
|
{
|
635 |
|
|
switch (inflags)
|
636 |
|
|
{
|
637 |
|
|
case XFS_FSOP_GOING_FLAGS_DEFAULT:
|
638 |
|
|
xfs_fs_freeze(mp);
|
639 |
|
|
xfs_force_shutdown(mp, XFS_FORCE_UMOUNT);
|
640 |
|
|
xfs_fs_thaw(mp);
|
641 |
|
|
break;
|
642 |
|
|
case XFS_FSOP_GOING_FLAGS_LOGFLUSH:
|
643 |
|
|
xfs_force_shutdown(mp, XFS_FORCE_UMOUNT);
|
644 |
|
|
break;
|
645 |
|
|
case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH:
|
646 |
|
|
xfs_force_shutdown(mp, XFS_FORCE_UMOUNT|XFS_LOG_IO_ERROR);
|
647 |
|
|
break;
|
648 |
|
|
default:
|
649 |
|
|
return XFS_ERROR(EINVAL);
|
650 |
|
|
}
|
651 |
|
|
|
652 |
|
|
return 0;
|
653 |
|
|
}
|