0001
0002
0003
0004
0005
0006 #include "xfs.h"
0007 #include "xfs_fs.h"
0008 #include "xfs_shared.h"
0009 #include "xfs_format.h"
0010 #include "xfs_log_format.h"
0011 #include "xfs_trans_resv.h"
0012 #include "xfs_sb.h"
0013 #include "xfs_mount.h"
0014 #include "xfs_trans.h"
0015 #include "xfs_error.h"
0016 #include "xfs_alloc.h"
0017 #include "xfs_fsops.h"
0018 #include "xfs_trans_space.h"
0019 #include "xfs_log.h"
0020 #include "xfs_log_priv.h"
0021 #include "xfs_ag.h"
0022 #include "xfs_ag_resv.h"
0023 #include "xfs_trace.h"
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 static int
0038 xfs_resizefs_init_new_ags(
0039 struct xfs_trans *tp,
0040 struct aghdr_init_data *id,
0041 xfs_agnumber_t oagcount,
0042 xfs_agnumber_t nagcount,
0043 xfs_rfsblock_t delta,
0044 struct xfs_perag *last_pag,
0045 bool *lastag_extended)
0046 {
0047 struct xfs_mount *mp = tp->t_mountp;
0048 xfs_rfsblock_t nb = mp->m_sb.sb_dblocks + delta;
0049 int error;
0050
0051 *lastag_extended = false;
0052
0053 INIT_LIST_HEAD(&id->buffer_list);
0054 for (id->agno = nagcount - 1;
0055 id->agno >= oagcount;
0056 id->agno--, delta -= id->agsize) {
0057
0058 if (id->agno == nagcount - 1)
0059 id->agsize = nb - (id->agno *
0060 (xfs_rfsblock_t)mp->m_sb.sb_agblocks);
0061 else
0062 id->agsize = mp->m_sb.sb_agblocks;
0063
0064 error = xfs_ag_init_headers(mp, id);
0065 if (error) {
0066 xfs_buf_delwri_cancel(&id->buffer_list);
0067 return error;
0068 }
0069 }
0070
0071 error = xfs_buf_delwri_submit(&id->buffer_list);
0072 if (error)
0073 return error;
0074
0075 if (delta) {
0076 *lastag_extended = true;
0077 error = xfs_ag_extend_space(last_pag, tp, delta);
0078 }
0079 return error;
0080 }
0081
0082
0083
0084
0085 static int
0086 xfs_growfs_data_private(
0087 struct xfs_mount *mp,
0088 struct xfs_growfs_data *in)
0089 {
0090 struct xfs_buf *bp;
0091 int error;
0092 xfs_agnumber_t nagcount;
0093 xfs_agnumber_t nagimax = 0;
0094 xfs_rfsblock_t nb, nb_div, nb_mod;
0095 int64_t delta;
0096 bool lastag_extended;
0097 xfs_agnumber_t oagcount;
0098 struct xfs_trans *tp;
0099 struct aghdr_init_data id = {};
0100 struct xfs_perag *last_pag;
0101
0102 nb = in->newblocks;
0103 error = xfs_sb_validate_fsb_count(&mp->m_sb, nb);
0104 if (error)
0105 return error;
0106
0107 if (nb > mp->m_sb.sb_dblocks) {
0108 error = xfs_buf_read_uncached(mp->m_ddev_targp,
0109 XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
0110 XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL);
0111 if (error)
0112 return error;
0113 xfs_buf_relse(bp);
0114 }
0115
0116 nb_div = nb;
0117 nb_mod = do_div(nb_div, mp->m_sb.sb_agblocks);
0118 nagcount = nb_div + (nb_mod != 0);
0119 if (nb_mod && nb_mod < XFS_MIN_AG_BLOCKS) {
0120 nagcount--;
0121 nb = (xfs_rfsblock_t)nagcount * mp->m_sb.sb_agblocks;
0122 }
0123 delta = nb - mp->m_sb.sb_dblocks;
0124
0125
0126
0127
0128
0129 if (delta < 0 && nagcount < 2)
0130 return -EINVAL;
0131
0132 oagcount = mp->m_sb.sb_agcount;
0133
0134 if (nagcount > oagcount) {
0135 error = xfs_initialize_perag(mp, nagcount, nb, &nagimax);
0136 if (error)
0137 return error;
0138 } else if (nagcount < oagcount) {
0139
0140 return -EINVAL;
0141 }
0142
0143 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata,
0144 (delta > 0 ? XFS_GROWFS_SPACE_RES(mp) : -delta), 0,
0145 XFS_TRANS_RESERVE, &tp);
0146 if (error)
0147 return error;
0148
0149 last_pag = xfs_perag_get(mp, oagcount - 1);
0150 if (delta > 0) {
0151 error = xfs_resizefs_init_new_ags(tp, &id, oagcount, nagcount,
0152 delta, last_pag, &lastag_extended);
0153 } else {
0154 xfs_warn_mount(mp, XFS_OPSTATE_WARNED_SHRINK,
0155 "EXPERIMENTAL online shrink feature in use. Use at your own risk!");
0156
0157 error = xfs_ag_shrink_space(last_pag, &tp, -delta);
0158 }
0159 xfs_perag_put(last_pag);
0160 if (error)
0161 goto out_trans_cancel;
0162
0163
0164
0165
0166
0167
0168 if (nagcount > oagcount)
0169 xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount);
0170 if (delta)
0171 xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS, delta);
0172 if (id.nfree)
0173 xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, id.nfree);
0174
0175
0176
0177
0178
0179
0180 if (xfs_has_lazysbcount(mp))
0181 xfs_log_sb(tp);
0182
0183 xfs_trans_set_sync(tp);
0184 error = xfs_trans_commit(tp);
0185 if (error)
0186 return error;
0187
0188
0189 if (nagimax)
0190 mp->m_maxagi = nagimax;
0191 xfs_set_low_space_thresholds(mp);
0192 mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
0193
0194 if (delta > 0) {
0195
0196
0197
0198
0199 if (lastag_extended) {
0200 struct xfs_perag *pag;
0201
0202 pag = xfs_perag_get(mp, id.agno);
0203 error = xfs_ag_resv_free(pag);
0204 xfs_perag_put(pag);
0205 if (error)
0206 return error;
0207 }
0208
0209
0210
0211
0212
0213 error = xfs_fs_reserve_ag_blocks(mp);
0214 if (error == -ENOSPC)
0215 error = 0;
0216 }
0217 return error;
0218
0219 out_trans_cancel:
0220 xfs_trans_cancel(tp);
0221 return error;
0222 }
0223
0224 static int
0225 xfs_growfs_log_private(
0226 struct xfs_mount *mp,
0227 struct xfs_growfs_log *in)
0228 {
0229 xfs_extlen_t nb;
0230
0231 nb = in->newblocks;
0232 if (nb < XFS_MIN_LOG_BLOCKS || nb < XFS_B_TO_FSB(mp, XFS_MIN_LOG_BYTES))
0233 return -EINVAL;
0234 if (nb == mp->m_sb.sb_logblocks &&
0235 in->isint == (mp->m_sb.sb_logstart != 0))
0236 return -EINVAL;
0237
0238
0239
0240
0241
0242
0243 return -ENOSYS;
0244 }
0245
0246 static int
0247 xfs_growfs_imaxpct(
0248 struct xfs_mount *mp,
0249 __u32 imaxpct)
0250 {
0251 struct xfs_trans *tp;
0252 int dpct;
0253 int error;
0254
0255 if (imaxpct > 100)
0256 return -EINVAL;
0257
0258 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata,
0259 XFS_GROWFS_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp);
0260 if (error)
0261 return error;
0262
0263 dpct = imaxpct - mp->m_sb.sb_imax_pct;
0264 xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct);
0265 xfs_trans_set_sync(tp);
0266 return xfs_trans_commit(tp);
0267 }
0268
0269
0270
0271
0272
0273
0274 int
0275 xfs_growfs_data(
0276 struct xfs_mount *mp,
0277 struct xfs_growfs_data *in)
0278 {
0279 int error = 0;
0280
0281 if (!capable(CAP_SYS_ADMIN))
0282 return -EPERM;
0283 if (!mutex_trylock(&mp->m_growlock))
0284 return -EWOULDBLOCK;
0285
0286
0287 if (in->imaxpct != mp->m_sb.sb_imax_pct) {
0288 error = xfs_growfs_imaxpct(mp, in->imaxpct);
0289 if (error)
0290 goto out_error;
0291 }
0292
0293 if (in->newblocks != mp->m_sb.sb_dblocks) {
0294 error = xfs_growfs_data_private(mp, in);
0295 if (error)
0296 goto out_error;
0297 }
0298
0299
0300 if (mp->m_sb.sb_imax_pct) {
0301 uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct;
0302 do_div(icount, 100);
0303 M_IGEO(mp)->maxicount = XFS_FSB_TO_INO(mp, icount);
0304 } else
0305 M_IGEO(mp)->maxicount = 0;
0306
0307
0308 error = xfs_update_secondary_sbs(mp);
0309
0310 out_error:
0311
0312
0313
0314
0315
0316 mp->m_generation++;
0317 mutex_unlock(&mp->m_growlock);
0318 return error;
0319 }
0320
0321 int
0322 xfs_growfs_log(
0323 xfs_mount_t *mp,
0324 struct xfs_growfs_log *in)
0325 {
0326 int error;
0327
0328 if (!capable(CAP_SYS_ADMIN))
0329 return -EPERM;
0330 if (!mutex_trylock(&mp->m_growlock))
0331 return -EWOULDBLOCK;
0332 error = xfs_growfs_log_private(mp, in);
0333 mutex_unlock(&mp->m_growlock);
0334 return error;
0335 }
0336
0337
0338
0339
0340
0341 void
0342 xfs_fs_counts(
0343 xfs_mount_t *mp,
0344 xfs_fsop_counts_t *cnt)
0345 {
0346 cnt->allocino = percpu_counter_read_positive(&mp->m_icount);
0347 cnt->freeino = percpu_counter_read_positive(&mp->m_ifree);
0348 cnt->freedata = percpu_counter_read_positive(&mp->m_fdblocks) -
0349 xfs_fdblocks_unavailable(mp);
0350 cnt->freertx = percpu_counter_read_positive(&mp->m_frextents);
0351 }
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368 int
0369 xfs_reserve_blocks(
0370 xfs_mount_t *mp,
0371 uint64_t *inval,
0372 xfs_fsop_resblks_t *outval)
0373 {
0374 int64_t lcounter, delta;
0375 int64_t fdblks_delta = 0;
0376 uint64_t request;
0377 int64_t free;
0378 int error = 0;
0379
0380
0381 if (inval == (uint64_t *)NULL) {
0382 if (!outval)
0383 return -EINVAL;
0384 outval->resblks = mp->m_resblks;
0385 outval->resblks_avail = mp->m_resblks_avail;
0386 return 0;
0387 }
0388
0389 request = *inval;
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401 spin_lock(&mp->m_sb_lock);
0402
0403
0404
0405
0406
0407
0408
0409 if (mp->m_resblks > request) {
0410 lcounter = mp->m_resblks_avail - request;
0411 if (lcounter > 0) {
0412 fdblks_delta = lcounter;
0413 mp->m_resblks_avail -= lcounter;
0414 }
0415 mp->m_resblks = request;
0416 if (fdblks_delta) {
0417 spin_unlock(&mp->m_sb_lock);
0418 error = xfs_mod_fdblocks(mp, fdblks_delta, 0);
0419 spin_lock(&mp->m_sb_lock);
0420 }
0421
0422 goto out;
0423 }
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437 free = percpu_counter_sum(&mp->m_fdblocks) -
0438 xfs_fdblocks_unavailable(mp);
0439 delta = request - mp->m_resblks;
0440 mp->m_resblks = request;
0441 if (delta > 0 && free > 0) {
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452 fdblks_delta = min(free, delta);
0453 spin_unlock(&mp->m_sb_lock);
0454 error = xfs_mod_fdblocks(mp, -fdblks_delta, 0);
0455 if (!error)
0456 xfs_mod_fdblocks(mp, fdblks_delta, 0);
0457 spin_lock(&mp->m_sb_lock);
0458 }
0459 out:
0460 if (outval) {
0461 outval->resblks = mp->m_resblks;
0462 outval->resblks_avail = mp->m_resblks_avail;
0463 }
0464
0465 spin_unlock(&mp->m_sb_lock);
0466 return error;
0467 }
0468
0469 int
0470 xfs_fs_goingdown(
0471 xfs_mount_t *mp,
0472 uint32_t inflags)
0473 {
0474 switch (inflags) {
0475 case XFS_FSOP_GOING_FLAGS_DEFAULT: {
0476 if (!freeze_bdev(mp->m_super->s_bdev)) {
0477 xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
0478 thaw_bdev(mp->m_super->s_bdev);
0479 }
0480 break;
0481 }
0482 case XFS_FSOP_GOING_FLAGS_LOGFLUSH:
0483 xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
0484 break;
0485 case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH:
0486 xfs_force_shutdown(mp,
0487 SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR);
0488 break;
0489 default:
0490 return -EINVAL;
0491 }
0492
0493 return 0;
0494 }
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507 void
0508 xfs_do_force_shutdown(
0509 struct xfs_mount *mp,
0510 uint32_t flags,
0511 char *fname,
0512 int lnnum)
0513 {
0514 int tag;
0515 const char *why;
0516
0517
0518 if (test_and_set_bit(XFS_OPSTATE_SHUTDOWN, &mp->m_opstate)) {
0519 xlog_shutdown_wait(mp->m_log);
0520 return;
0521 }
0522 if (mp->m_sb_bp)
0523 mp->m_sb_bp->b_flags |= XBF_DONE;
0524
0525 if (flags & SHUTDOWN_FORCE_UMOUNT)
0526 xfs_alert(mp, "User initiated shutdown received.");
0527
0528 if (xlog_force_shutdown(mp->m_log, flags)) {
0529 tag = XFS_PTAG_SHUTDOWN_LOGERROR;
0530 why = "Log I/O Error";
0531 } else if (flags & SHUTDOWN_CORRUPT_INCORE) {
0532 tag = XFS_PTAG_SHUTDOWN_CORRUPT;
0533 why = "Corruption of in-memory data";
0534 } else if (flags & SHUTDOWN_CORRUPT_ONDISK) {
0535 tag = XFS_PTAG_SHUTDOWN_CORRUPT;
0536 why = "Corruption of on-disk metadata";
0537 } else {
0538 tag = XFS_PTAG_SHUTDOWN_IOERROR;
0539 why = "Metadata I/O Error";
0540 }
0541
0542 trace_xfs_force_shutdown(mp, tag, flags, fname, lnnum);
0543
0544 xfs_alert_tag(mp, tag,
0545 "%s (0x%x) detected at %pS (%s:%d). Shutting down filesystem.",
0546 why, flags, __return_address, fname, lnnum);
0547 xfs_alert(mp,
0548 "Please unmount the filesystem and rectify the problem(s)");
0549 if (xfs_error_level >= XFS_ERRLEVEL_HIGH)
0550 xfs_stack_trace();
0551 }
0552
0553
0554
0555
0556 int
0557 xfs_fs_reserve_ag_blocks(
0558 struct xfs_mount *mp)
0559 {
0560 xfs_agnumber_t agno;
0561 struct xfs_perag *pag;
0562 int error = 0;
0563 int err2;
0564
0565 mp->m_finobt_nores = false;
0566 for_each_perag(mp, agno, pag) {
0567 err2 = xfs_ag_resv_init(pag, NULL);
0568 if (err2 && !error)
0569 error = err2;
0570 }
0571
0572 if (error && error != -ENOSPC) {
0573 xfs_warn(mp,
0574 "Error %d reserving per-AG metadata reserve pool.", error);
0575 xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
0576 }
0577
0578 return error;
0579 }
0580
0581
0582
0583
0584 int
0585 xfs_fs_unreserve_ag_blocks(
0586 struct xfs_mount *mp)
0587 {
0588 xfs_agnumber_t agno;
0589 struct xfs_perag *pag;
0590 int error = 0;
0591 int err2;
0592
0593 for_each_perag(mp, agno, pag) {
0594 err2 = xfs_ag_resv_free(pag);
0595 if (err2 && !error)
0596 error = err2;
0597 }
0598
0599 if (error)
0600 xfs_warn(mp,
0601 "Error %d freeing per-AG metadata reserve pool.", error);
0602
0603 return error;
0604 }