1
2
3
4
5
6#include "xfs.h"
7#include "xfs_fs.h"
8#include "xfs_shared.h"
9#include "xfs_format.h"
10#include "xfs_log_format.h"
11#include "xfs_trans_resv.h"
12#include "xfs_sb.h"
13#include "xfs_mount.h"
14#include "xfs_trans.h"
15#include "xfs_error.h"
16#include "xfs_alloc.h"
17#include "xfs_fsops.h"
18#include "xfs_trans_space.h"
19#include "xfs_log.h"
20#include "xfs_ag.h"
21#include "xfs_ag_resv.h"
22
23
24
25
26static int
27xfs_growfs_data_private(
28 xfs_mount_t *mp,
29 xfs_growfs_data_t *in)
30{
31 xfs_buf_t *bp;
32 int error;
33 xfs_agnumber_t nagcount;
34 xfs_agnumber_t nagimax = 0;
35 xfs_rfsblock_t nb, nb_mod;
36 xfs_rfsblock_t new;
37 xfs_agnumber_t oagcount;
38 xfs_trans_t *tp;
39 struct aghdr_init_data id = {};
40
41 nb = in->newblocks;
42 if (nb < mp->m_sb.sb_dblocks)
43 return -EINVAL;
44 if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb)))
45 return error;
46 error = xfs_buf_read_uncached(mp->m_ddev_targp,
47 XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
48 XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
49 if (error)
50 return error;
51 xfs_buf_relse(bp);
52
53 new = nb;
54 nb_mod = do_div(new, mp->m_sb.sb_agblocks);
55 nagcount = new + (nb_mod != 0);
56 if (nb_mod && nb_mod < XFS_MIN_AG_BLOCKS) {
57 nagcount--;
58 nb = (xfs_rfsblock_t)nagcount * mp->m_sb.sb_agblocks;
59 if (nb < mp->m_sb.sb_dblocks)
60 return -EINVAL;
61 }
62 new = nb - mp->m_sb.sb_dblocks;
63 oagcount = mp->m_sb.sb_agcount;
64
65
66 if (nagcount > oagcount) {
67 error = xfs_initialize_perag(mp, nagcount, &nagimax);
68 if (error)
69 return error;
70 }
71
72 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata,
73 XFS_GROWFS_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp);
74 if (error)
75 return error;
76
77
78
79
80
81
82
83
84
85
86
87
88
89 INIT_LIST_HEAD(&id.buffer_list);
90 for (id.agno = nagcount - 1;
91 id.agno >= oagcount;
92 id.agno--, new -= id.agsize) {
93
94 if (id.agno == nagcount - 1)
95 id.agsize = nb -
96 (id.agno * (xfs_rfsblock_t)mp->m_sb.sb_agblocks);
97 else
98 id.agsize = mp->m_sb.sb_agblocks;
99
100 error = xfs_ag_init_headers(mp, &id);
101 if (error) {
102 xfs_buf_delwri_cancel(&id.buffer_list);
103 goto out_trans_cancel;
104 }
105 }
106 error = xfs_buf_delwri_submit(&id.buffer_list);
107 if (error)
108 goto out_trans_cancel;
109
110 xfs_trans_agblocks_delta(tp, id.nfree);
111
112
113 if (new) {
114 error = xfs_ag_extend_space(mp, tp, &id, new);
115 if (error)
116 goto out_trans_cancel;
117 }
118
119
120
121
122
123
124 if (nagcount > oagcount)
125 xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount);
126 if (nb > mp->m_sb.sb_dblocks)
127 xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS,
128 nb - mp->m_sb.sb_dblocks);
129 if (id.nfree)
130 xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, id.nfree);
131 xfs_trans_set_sync(tp);
132 error = xfs_trans_commit(tp);
133 if (error)
134 return error;
135
136
137 if (nagimax)
138 mp->m_maxagi = nagimax;
139 xfs_set_low_space_thresholds(mp);
140 mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
141
142
143
144
145
146 if (new) {
147 struct xfs_perag *pag;
148
149 pag = xfs_perag_get(mp, id.agno);
150 error = xfs_ag_resv_free(pag);
151 xfs_perag_put(pag);
152 if (error)
153 return error;
154 }
155
156
157
158
159
160
161 error = xfs_fs_reserve_ag_blocks(mp);
162 if (error == -ENOSPC)
163 error = 0;
164 return error;
165
166out_trans_cancel:
167 xfs_trans_cancel(tp);
168 return error;
169}
170
171static int
172xfs_growfs_log_private(
173 xfs_mount_t *mp,
174 xfs_growfs_log_t *in)
175{
176 xfs_extlen_t nb;
177
178 nb = in->newblocks;
179 if (nb < XFS_MIN_LOG_BLOCKS || nb < XFS_B_TO_FSB(mp, XFS_MIN_LOG_BYTES))
180 return -EINVAL;
181 if (nb == mp->m_sb.sb_logblocks &&
182 in->isint == (mp->m_sb.sb_logstart != 0))
183 return -EINVAL;
184
185
186
187
188
189
190 return -ENOSYS;
191}
192
193static int
194xfs_growfs_imaxpct(
195 struct xfs_mount *mp,
196 __u32 imaxpct)
197{
198 struct xfs_trans *tp;
199 int dpct;
200 int error;
201
202 if (imaxpct > 100)
203 return -EINVAL;
204
205 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata,
206 XFS_GROWFS_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp);
207 if (error)
208 return error;
209
210 dpct = imaxpct - mp->m_sb.sb_imax_pct;
211 xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct);
212 xfs_trans_set_sync(tp);
213 return xfs_trans_commit(tp);
214}
215
216
217
218
219
220
221int
222xfs_growfs_data(
223 struct xfs_mount *mp,
224 struct xfs_growfs_data *in)
225{
226 int error = 0;
227
228 if (!capable(CAP_SYS_ADMIN))
229 return -EPERM;
230 if (!mutex_trylock(&mp->m_growlock))
231 return -EWOULDBLOCK;
232
233
234 if (in->imaxpct != mp->m_sb.sb_imax_pct) {
235 error = xfs_growfs_imaxpct(mp, in->imaxpct);
236 if (error)
237 goto out_error;
238 }
239
240 if (in->newblocks != mp->m_sb.sb_dblocks) {
241 error = xfs_growfs_data_private(mp, in);
242 if (error)
243 goto out_error;
244 }
245
246
247 if (mp->m_sb.sb_imax_pct) {
248 uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct;
249 do_div(icount, 100);
250 M_IGEO(mp)->maxicount = XFS_FSB_TO_INO(mp, icount);
251 } else
252 M_IGEO(mp)->maxicount = 0;
253
254
255 error = xfs_update_secondary_sbs(mp);
256
257out_error:
258
259
260
261
262
263 mp->m_generation++;
264 mutex_unlock(&mp->m_growlock);
265 return error;
266}
267
268int
269xfs_growfs_log(
270 xfs_mount_t *mp,
271 xfs_growfs_log_t *in)
272{
273 int error;
274
275 if (!capable(CAP_SYS_ADMIN))
276 return -EPERM;
277 if (!mutex_trylock(&mp->m_growlock))
278 return -EWOULDBLOCK;
279 error = xfs_growfs_log_private(mp, in);
280 mutex_unlock(&mp->m_growlock);
281 return error;
282}
283
284
285
286
287
288void
289xfs_fs_counts(
290 xfs_mount_t *mp,
291 xfs_fsop_counts_t *cnt)
292{
293 cnt->allocino = percpu_counter_read_positive(&mp->m_icount);
294 cnt->freeino = percpu_counter_read_positive(&mp->m_ifree);
295 cnt->freedata = percpu_counter_read_positive(&mp->m_fdblocks) -
296 mp->m_alloc_set_aside;
297
298 spin_lock(&mp->m_sb_lock);
299 cnt->freertx = mp->m_sb.sb_frextents;
300 spin_unlock(&mp->m_sb_lock);
301}
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318int
319xfs_reserve_blocks(
320 xfs_mount_t *mp,
321 uint64_t *inval,
322 xfs_fsop_resblks_t *outval)
323{
324 int64_t lcounter, delta;
325 int64_t fdblks_delta = 0;
326 uint64_t request;
327 int64_t free;
328 int error = 0;
329
330
331 if (inval == (uint64_t *)NULL) {
332 if (!outval)
333 return -EINVAL;
334 outval->resblks = mp->m_resblks;
335 outval->resblks_avail = mp->m_resblks_avail;
336 return 0;
337 }
338
339 request = *inval;
340
341
342
343
344
345
346
347
348
349
350
351 spin_lock(&mp->m_sb_lock);
352
353
354
355
356
357
358
359 if (mp->m_resblks > request) {
360 lcounter = mp->m_resblks_avail - request;
361 if (lcounter > 0) {
362 fdblks_delta = lcounter;
363 mp->m_resblks_avail -= lcounter;
364 }
365 mp->m_resblks = request;
366 if (fdblks_delta) {
367 spin_unlock(&mp->m_sb_lock);
368 error = xfs_mod_fdblocks(mp, fdblks_delta, 0);
369 spin_lock(&mp->m_sb_lock);
370 }
371
372 goto out;
373 }
374
375
376
377
378
379
380 error = -ENOSPC;
381 do {
382 free = percpu_counter_sum(&mp->m_fdblocks) -
383 mp->m_alloc_set_aside;
384 if (free <= 0)
385 break;
386
387 delta = request - mp->m_resblks;
388 lcounter = free - delta;
389 if (lcounter < 0)
390
391 fdblks_delta = free;
392 else
393 fdblks_delta = delta;
394
395
396
397
398
399
400
401
402
403
404
405 spin_unlock(&mp->m_sb_lock);
406 error = xfs_mod_fdblocks(mp, -fdblks_delta, 0);
407 spin_lock(&mp->m_sb_lock);
408 } while (error == -ENOSPC);
409
410
411
412
413
414 if (!error && fdblks_delta) {
415 mp->m_resblks += fdblks_delta;
416 mp->m_resblks_avail += fdblks_delta;
417 }
418
419out:
420 if (outval) {
421 outval->resblks = mp->m_resblks;
422 outval->resblks_avail = mp->m_resblks_avail;
423 }
424
425 spin_unlock(&mp->m_sb_lock);
426 return error;
427}
428
429int
430xfs_fs_goingdown(
431 xfs_mount_t *mp,
432 uint32_t inflags)
433{
434 switch (inflags) {
435 case XFS_FSOP_GOING_FLAGS_DEFAULT: {
436 struct super_block *sb = freeze_bdev(mp->m_super->s_bdev);
437
438 if (sb && !IS_ERR(sb)) {
439 xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
440 thaw_bdev(sb->s_bdev, sb);
441 }
442
443 break;
444 }
445 case XFS_FSOP_GOING_FLAGS_LOGFLUSH:
446 xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
447 break;
448 case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH:
449 xfs_force_shutdown(mp,
450 SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR);
451 break;
452 default:
453 return -EINVAL;
454 }
455
456 return 0;
457}
458
459
460
461
462
463
464
465void
466xfs_do_force_shutdown(
467 struct xfs_mount *mp,
468 int flags,
469 char *fname,
470 int lnnum)
471{
472 bool logerror = flags & SHUTDOWN_LOG_IO_ERROR;
473
474
475
476
477 if (XFS_FORCED_SHUTDOWN(mp) && !logerror)
478 return;
479
480
481
482
483
484
485
486 if (xfs_log_force_umount(mp, logerror))
487 return;
488
489 if (flags & SHUTDOWN_FORCE_UMOUNT) {
490 xfs_alert(mp,
491"User initiated shutdown received. Shutting down filesystem");
492 return;
493 }
494
495 xfs_notice(mp,
496"%s(0x%x) called from line %d of file %s. Return address = "PTR_FMT,
497 __func__, flags, lnnum, fname, __return_address);
498
499 if (flags & SHUTDOWN_CORRUPT_INCORE) {
500 xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT,
501"Corruption of in-memory data detected. Shutting down filesystem");
502 if (XFS_ERRLEVEL_HIGH <= xfs_error_level)
503 xfs_stack_trace();
504 } else if (logerror) {
505 xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR,
506 "Log I/O Error Detected. Shutting down filesystem");
507 } else {
508 xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
509 "I/O Error Detected. Shutting down filesystem");
510 }
511
512 xfs_alert(mp,
513 "Please unmount the filesystem and rectify the problem(s)");
514}
515
516
517
518
519int
520xfs_fs_reserve_ag_blocks(
521 struct xfs_mount *mp)
522{
523 xfs_agnumber_t agno;
524 struct xfs_perag *pag;
525 int error = 0;
526 int err2;
527
528 mp->m_finobt_nores = false;
529 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
530 pag = xfs_perag_get(mp, agno);
531 err2 = xfs_ag_resv_init(pag, NULL);
532 xfs_perag_put(pag);
533 if (err2 && !error)
534 error = err2;
535 }
536
537 if (error && error != -ENOSPC) {
538 xfs_warn(mp,
539 "Error %d reserving per-AG metadata reserve pool.", error);
540 xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
541 }
542
543 return error;
544}
545
546
547
548
549int
550xfs_fs_unreserve_ag_blocks(
551 struct xfs_mount *mp)
552{
553 xfs_agnumber_t agno;
554 struct xfs_perag *pag;
555 int error = 0;
556 int err2;
557
558 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
559 pag = xfs_perag_get(mp, agno);
560 err2 = xfs_ag_resv_free(pag);
561 xfs_perag_put(pag);
562 if (err2 && !error)
563 error = err2;
564 }
565
566 if (error)
567 xfs_warn(mp,
568 "Error %d freeing per-AG metadata reserve pool.", error);
569
570 return error;
571}
572