linux/fs/xfs/xfs_fsops.c
<<
>>
Prefs
   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_types.h"
  21#include "xfs_log.h"
  22#include "xfs_trans.h"
  23#include "xfs_sb.h"
  24#include "xfs_ag.h"
  25#include "xfs_mount.h"
  26#include "xfs_bmap_btree.h"
  27#include "xfs_alloc_btree.h"
  28#include "xfs_ialloc_btree.h"
  29#include "xfs_dinode.h"
  30#include "xfs_inode.h"
  31#include "xfs_inode_item.h"
  32#include "xfs_btree.h"
  33#include "xfs_error.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_filestream.h"
  41#include "xfs_trace.h"
  42
  43/*
  44 * File system operations
  45 */
  46
  47int
  48xfs_fs_geometry(
  49        xfs_mount_t             *mp,
  50        xfs_fsop_geom_t         *geo,
  51        int                     new_version)
  52{
  53
  54        memset(geo, 0, sizeof(*geo));
  55
  56        geo->blocksize = mp->m_sb.sb_blocksize;
  57        geo->rtextsize = mp->m_sb.sb_rextsize;
  58        geo->agblocks = mp->m_sb.sb_agblocks;
  59        geo->agcount = mp->m_sb.sb_agcount;
  60        geo->logblocks = mp->m_sb.sb_logblocks;
  61        geo->sectsize = mp->m_sb.sb_sectsize;
  62        geo->inodesize = mp->m_sb.sb_inodesize;
  63        geo->imaxpct = mp->m_sb.sb_imax_pct;
  64        geo->datablocks = mp->m_sb.sb_dblocks;
  65        geo->rtblocks = mp->m_sb.sb_rblocks;
  66        geo->rtextents = mp->m_sb.sb_rextents;
  67        geo->logstart = mp->m_sb.sb_logstart;
  68        ASSERT(sizeof(geo->uuid)==sizeof(mp->m_sb.sb_uuid));
  69        memcpy(geo->uuid, &mp->m_sb.sb_uuid, sizeof(mp->m_sb.sb_uuid));
  70        if (new_version >= 2) {
  71                geo->sunit = mp->m_sb.sb_unit;
  72                geo->swidth = mp->m_sb.sb_width;
  73        }
  74        if (new_version >= 3) {
  75                geo->version = XFS_FSOP_GEOM_VERSION;
  76                geo->flags =
  77                        (xfs_sb_version_hasattr(&mp->m_sb) ?
  78                                XFS_FSOP_GEOM_FLAGS_ATTR : 0) |
  79                        (xfs_sb_version_hasnlink(&mp->m_sb) ?
  80                                XFS_FSOP_GEOM_FLAGS_NLINK : 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_hasshared(&mp->m_sb) ?
  88                                XFS_FSOP_GEOM_FLAGS_SHARED : 0) |
  89                        (xfs_sb_version_hasextflgbit(&mp->m_sb) ?
  90                                XFS_FSOP_GEOM_FLAGS_EXTFLG : 0) |
  91                        (xfs_sb_version_hasdirv2(&mp->m_sb) ?
  92                                XFS_FSOP_GEOM_FLAGS_DIRV2 : 0) |
  93                        (xfs_sb_version_hassector(&mp->m_sb) ?
  94                                XFS_FSOP_GEOM_FLAGS_SECTOR : 0) |
  95                        (xfs_sb_version_hasasciici(&mp->m_sb) ?
  96                                XFS_FSOP_GEOM_FLAGS_DIRV2CI : 0) |
  97                        (xfs_sb_version_haslazysbcount(&mp->m_sb) ?
  98                                XFS_FSOP_GEOM_FLAGS_LAZYSB : 0) |
  99                        (xfs_sb_version_hasattr2(&mp->m_sb) ?
 100                                XFS_FSOP_GEOM_FLAGS_ATTR2 : 0);
 101                geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ?
 102                                mp->m_sb.sb_logsectsize : BBSIZE;
 103                geo->rtsectsize = mp->m_sb.sb_blocksize;
 104                geo->dirblocksize = mp->m_dirblksize;
 105        }
 106        if (new_version >= 4) {
 107                geo->flags |=
 108                        (xfs_sb_version_haslogv2(&mp->m_sb) ?
 109                                XFS_FSOP_GEOM_FLAGS_LOGV2 : 0);
 110                geo->logsunit = mp->m_sb.sb_logsunit;
 111        }
 112        return 0;
 113}
 114
 115static int
 116xfs_growfs_data_private(
 117        xfs_mount_t             *mp,            /* mount point for filesystem */
 118        xfs_growfs_data_t       *in)            /* growfs data input struct */
 119{
 120        xfs_agf_t               *agf;
 121        xfs_agi_t               *agi;
 122        xfs_agnumber_t          agno;
 123        xfs_extlen_t            agsize;
 124        xfs_extlen_t            tmpsize;
 125        xfs_alloc_rec_t         *arec;
 126        struct xfs_btree_block  *block;
 127        xfs_buf_t               *bp;
 128        int                     bucket;
 129        int                     dpct;
 130        int                     error;
 131        xfs_agnumber_t          nagcount;
 132        xfs_agnumber_t          nagimax = 0;
 133        xfs_rfsblock_t          nb, nb_mod;
 134        xfs_rfsblock_t          new;
 135        xfs_rfsblock_t          nfree;
 136        xfs_agnumber_t          oagcount;
 137        int                     pct;
 138        xfs_trans_t             *tp;
 139
 140        nb = in->newblocks;
 141        pct = in->imaxpct;
 142        if (nb < mp->m_sb.sb_dblocks || pct < 0 || pct > 100)
 143                return XFS_ERROR(EINVAL);
 144        if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb)))
 145                return error;
 146        dpct = pct - mp->m_sb.sb_imax_pct;
 147        bp = xfs_buf_read_uncached(mp->m_ddev_targp,
 148                                XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
 149                                XFS_FSS_TO_BB(mp, 1), 0);
 150        if (!bp)
 151                return EIO;
 152        xfs_buf_relse(bp);
 153
 154        new = nb;       /* use new as a temporary here */
 155        nb_mod = do_div(new, mp->m_sb.sb_agblocks);
 156        nagcount = new + (nb_mod != 0);
 157        if (nb_mod && nb_mod < XFS_MIN_AG_BLOCKS) {
 158                nagcount--;
 159                nb = (xfs_rfsblock_t)nagcount * mp->m_sb.sb_agblocks;
 160                if (nb < mp->m_sb.sb_dblocks)
 161                        return XFS_ERROR(EINVAL);
 162        }
 163        new = nb - mp->m_sb.sb_dblocks;
 164        oagcount = mp->m_sb.sb_agcount;
 165
 166        /* allocate the new per-ag structures */
 167        if (nagcount > oagcount) {
 168                error = xfs_initialize_perag(mp, nagcount, &nagimax);
 169                if (error)
 170                        return error;
 171        }
 172
 173        tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS);
 174        tp->t_flags |= XFS_TRANS_RESERVE;
 175        if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp),
 176                        XFS_GROWDATA_LOG_RES(mp), 0, 0, 0))) {
 177                xfs_trans_cancel(tp, 0);
 178                return error;
 179        }
 180
 181        /*
 182         * Write new AG headers to disk. Non-transactional, but written
 183         * synchronously so they are completed prior to the growfs transaction
 184         * being logged.
 185         */
 186        nfree = 0;
 187        for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) {
 188                /*
 189                 * AG freelist header block
 190                 */
 191                bp = xfs_buf_get(mp->m_ddev_targp,
 192                                 XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
 193                                 XFS_FSS_TO_BB(mp, 1), 0);
 194                if (!bp) {
 195                        error = ENOMEM;
 196                        goto error0;
 197                }
 198                agf = XFS_BUF_TO_AGF(bp);
 199                memset(agf, 0, mp->m_sb.sb_sectsize);
 200                agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC);
 201                agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION);
 202                agf->agf_seqno = cpu_to_be32(agno);
 203                if (agno == nagcount - 1)
 204                        agsize =
 205                                nb -
 206                                (agno * (xfs_rfsblock_t)mp->m_sb.sb_agblocks);
 207                else
 208                        agsize = mp->m_sb.sb_agblocks;
 209                agf->agf_length = cpu_to_be32(agsize);
 210                agf->agf_roots[XFS_BTNUM_BNOi] = cpu_to_be32(XFS_BNO_BLOCK(mp));
 211                agf->agf_roots[XFS_BTNUM_CNTi] = cpu_to_be32(XFS_CNT_BLOCK(mp));
 212                agf->agf_levels[XFS_BTNUM_BNOi] = cpu_to_be32(1);
 213                agf->agf_levels[XFS_BTNUM_CNTi] = cpu_to_be32(1);
 214                agf->agf_flfirst = 0;
 215                agf->agf_fllast = cpu_to_be32(XFS_AGFL_SIZE(mp) - 1);
 216                agf->agf_flcount = 0;
 217                tmpsize = agsize - XFS_PREALLOC_BLOCKS(mp);
 218                agf->agf_freeblks = cpu_to_be32(tmpsize);
 219                agf->agf_longest = cpu_to_be32(tmpsize);
 220                error = xfs_bwrite(bp);
 221                xfs_buf_relse(bp);
 222                if (error)
 223                        goto error0;
 224
 225                /*
 226                 * AG inode header block
 227                 */
 228                bp = xfs_buf_get(mp->m_ddev_targp,
 229                                 XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
 230                                 XFS_FSS_TO_BB(mp, 1), 0);
 231                if (!bp) {
 232                        error = ENOMEM;
 233                        goto error0;
 234                }
 235                agi = XFS_BUF_TO_AGI(bp);
 236                memset(agi, 0, mp->m_sb.sb_sectsize);
 237                agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC);
 238                agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION);
 239                agi->agi_seqno = cpu_to_be32(agno);
 240                agi->agi_length = cpu_to_be32(agsize);
 241                agi->agi_count = 0;
 242                agi->agi_root = cpu_to_be32(XFS_IBT_BLOCK(mp));
 243                agi->agi_level = cpu_to_be32(1);
 244                agi->agi_freecount = 0;
 245                agi->agi_newino = cpu_to_be32(NULLAGINO);
 246                agi->agi_dirino = cpu_to_be32(NULLAGINO);
 247                for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
 248                        agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
 249                error = xfs_bwrite(bp);
 250                xfs_buf_relse(bp);
 251                if (error)
 252                        goto error0;
 253
 254                /*
 255                 * BNO btree root block
 256                 */
 257                bp = xfs_buf_get(mp->m_ddev_targp,
 258                                 XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)),
 259                                 BTOBB(mp->m_sb.sb_blocksize), 0);
 260                if (!bp) {
 261                        error = ENOMEM;
 262                        goto error0;
 263                }
 264                block = XFS_BUF_TO_BLOCK(bp);
 265                memset(block, 0, mp->m_sb.sb_blocksize);
 266                block->bb_magic = cpu_to_be32(XFS_ABTB_MAGIC);
 267                block->bb_level = 0;
 268                block->bb_numrecs = cpu_to_be16(1);
 269                block->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
 270                block->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
 271                arec = XFS_ALLOC_REC_ADDR(mp, block, 1);
 272                arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
 273                arec->ar_blockcount = cpu_to_be32(
 274                        agsize - be32_to_cpu(arec->ar_startblock));
 275                error = xfs_bwrite(bp);
 276                xfs_buf_relse(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                if (!bp) {
 287                        error = ENOMEM;
 288                        goto error0;
 289                }
 290                block = XFS_BUF_TO_BLOCK(bp);
 291                memset(block, 0, mp->m_sb.sb_blocksize);
 292                block->bb_magic = cpu_to_be32(XFS_ABTC_MAGIC);
 293                block->bb_level = 0;
 294                block->bb_numrecs = cpu_to_be16(1);
 295                block->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
 296                block->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
 297                arec = XFS_ALLOC_REC_ADDR(mp, block, 1);
 298                arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp));
 299                arec->ar_blockcount = cpu_to_be32(
 300                        agsize - be32_to_cpu(arec->ar_startblock));
 301                nfree += be32_to_cpu(arec->ar_blockcount);
 302                error = xfs_bwrite(bp);
 303                xfs_buf_relse(bp);
 304                if (error)
 305                        goto error0;
 306
 307                /*
 308                 * INO btree root block
 309                 */
 310                bp = xfs_buf_get(mp->m_ddev_targp,
 311                                 XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)),
 312                                 BTOBB(mp->m_sb.sb_blocksize), 0);
 313                if (!bp) {
 314                        error = ENOMEM;
 315                        goto error0;
 316                }
 317                block = XFS_BUF_TO_BLOCK(bp);
 318                memset(block, 0, mp->m_sb.sb_blocksize);
 319                block->bb_magic = cpu_to_be32(XFS_IBT_MAGIC);
 320                block->bb_level = 0;
 321                block->bb_numrecs = 0;
 322                block->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
 323                block->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
 324                error = xfs_bwrite(bp);
 325                xfs_buf_relse(bp);
 326                if (error)
 327                        goto error0;
 328        }
 329        xfs_trans_agblocks_delta(tp, nfree);
 330        /*
 331         * There are new blocks in the old last a.g.
 332         */
 333        if (new) {
 334                /*
 335                 * Change the agi length.
 336                 */
 337                error = xfs_ialloc_read_agi(mp, tp, agno, &bp);
 338                if (error) {
 339                        goto error0;
 340                }
 341                ASSERT(bp);
 342                agi = XFS_BUF_TO_AGI(bp);
 343                be32_add_cpu(&agi->agi_length, new);
 344                ASSERT(nagcount == oagcount ||
 345                       be32_to_cpu(agi->agi_length) == mp->m_sb.sb_agblocks);
 346                xfs_ialloc_log_agi(tp, bp, XFS_AGI_LENGTH);
 347                /*
 348                 * Change agf length.
 349                 */
 350                error = xfs_alloc_read_agf(mp, tp, agno, 0, &bp);
 351                if (error) {
 352                        goto error0;
 353                }
 354                ASSERT(bp);
 355                agf = XFS_BUF_TO_AGF(bp);
 356                be32_add_cpu(&agf->agf_length, new);
 357                ASSERT(be32_to_cpu(agf->agf_length) ==
 358                       be32_to_cpu(agi->agi_length));
 359
 360                xfs_alloc_log_agf(tp, bp, XFS_AGF_LENGTH);
 361                /*
 362                 * Free the new space.
 363                 */
 364                error = xfs_free_extent(tp, XFS_AGB_TO_FSB(mp, agno,
 365                        be32_to_cpu(agf->agf_length) - new), new);
 366                if (error) {
 367                        goto error0;
 368                }
 369        }
 370
 371        /*
 372         * Update changed superblock fields transactionally. These are not
 373         * seen by the rest of the world until the transaction commit applies
 374         * them atomically to the superblock.
 375         */
 376        if (nagcount > oagcount)
 377                xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount);
 378        if (nb > mp->m_sb.sb_dblocks)
 379                xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS,
 380                                 nb - mp->m_sb.sb_dblocks);
 381        if (nfree)
 382                xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, nfree);
 383        if (dpct)
 384                xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct);
 385        error = xfs_trans_commit(tp, 0);
 386        if (error)
 387                return error;
 388
 389        /* New allocation groups fully initialized, so update mount struct */
 390        if (nagimax)
 391                mp->m_maxagi = nagimax;
 392        if (mp->m_sb.sb_imax_pct) {
 393                __uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct;
 394                do_div(icount, 100);
 395                mp->m_maxicount = icount << mp->m_sb.sb_inopblog;
 396        } else
 397                mp->m_maxicount = 0;
 398        xfs_set_low_space_thresholds(mp);
 399
 400        /* update secondary superblocks. */
 401        for (agno = 1; agno < nagcount; agno++) {
 402                error = 0;
 403                /*
 404                 * new secondary superblocks need to be zeroed, not read from
 405                 * disk as the contents of the new area we are growing into is
 406                 * completely unknown.
 407                 */
 408                if (agno < oagcount) {
 409                        error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
 410                                  XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
 411                                  XFS_FSS_TO_BB(mp, 1), 0, &bp);
 412                } else {
 413                        bp = xfs_trans_get_buf(NULL, mp->m_ddev_targp,
 414                                  XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
 415                                  XFS_FSS_TO_BB(mp, 1), 0);
 416                        if (bp)
 417                                xfs_buf_zero(bp, 0, BBTOB(bp->b_length));
 418                        else
 419                                error = ENOMEM;
 420                }
 421
 422                if (error) {
 423                        xfs_warn(mp,
 424                "error %d reading secondary superblock for ag %d",
 425                                error, agno);
 426                        break;
 427                }
 428                xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, XFS_SB_ALL_BITS);
 429                /*
 430                 * If we get an error writing out the alternate superblocks,
 431                 * just issue a warning and continue.  The real work is
 432                 * already done and committed.
 433                 */
 434                error = xfs_bwrite(bp);
 435                xfs_buf_relse(bp);
 436                if (error) {
 437                        xfs_warn(mp,
 438                "write error %d updating secondary superblock for ag %d",
 439                                error, agno);
 440                        break; /* no point in continuing */
 441                }
 442        }
 443        return error;
 444
 445 error0:
 446        xfs_trans_cancel(tp, XFS_TRANS_ABORT);
 447        return error;
 448}
 449
 450static int
 451xfs_growfs_log_private(
 452        xfs_mount_t             *mp,    /* mount point for filesystem */
 453        xfs_growfs_log_t        *in)    /* growfs log input struct */
 454{
 455        xfs_extlen_t            nb;
 456
 457        nb = in->newblocks;
 458        if (nb < XFS_MIN_LOG_BLOCKS || nb < XFS_B_TO_FSB(mp, XFS_MIN_LOG_BYTES))
 459                return XFS_ERROR(EINVAL);
 460        if (nb == mp->m_sb.sb_logblocks &&
 461            in->isint == (mp->m_sb.sb_logstart != 0))
 462                return XFS_ERROR(EINVAL);
 463        /*
 464         * Moving the log is hard, need new interfaces to sync
 465         * the log first, hold off all activity while moving it.
 466         * Can have shorter or longer log in the same space,
 467         * or transform internal to external log or vice versa.
 468         */
 469        return XFS_ERROR(ENOSYS);
 470}
 471
 472/*
 473 * protected versions of growfs function acquire and release locks on the mount
 474 * point - exported through ioctls: XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG,
 475 * XFS_IOC_FSGROWFSRT
 476 */
 477
 478
 479int
 480xfs_growfs_data(
 481        xfs_mount_t             *mp,
 482        xfs_growfs_data_t       *in)
 483{
 484        int error;
 485
 486        if (!capable(CAP_SYS_ADMIN))
 487                return XFS_ERROR(EPERM);
 488        if (!mutex_trylock(&mp->m_growlock))
 489                return XFS_ERROR(EWOULDBLOCK);
 490        error = xfs_growfs_data_private(mp, in);
 491        mutex_unlock(&mp->m_growlock);
 492        return error;
 493}
 494
 495int
 496xfs_growfs_log(
 497        xfs_mount_t             *mp,
 498        xfs_growfs_log_t        *in)
 499{
 500        int error;
 501
 502        if (!capable(CAP_SYS_ADMIN))
 503                return XFS_ERROR(EPERM);
 504        if (!mutex_trylock(&mp->m_growlock))
 505                return XFS_ERROR(EWOULDBLOCK);
 506        error = xfs_growfs_log_private(mp, in);
 507        mutex_unlock(&mp->m_growlock);
 508        return error;
 509}
 510
 511/*
 512 * exported through ioctl XFS_IOC_FSCOUNTS
 513 */
 514
 515int
 516xfs_fs_counts(
 517        xfs_mount_t             *mp,
 518        xfs_fsop_counts_t       *cnt)
 519{
 520        xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT);
 521        spin_lock(&mp->m_sb_lock);
 522        cnt->freedata = mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);
 523        cnt->freertx = mp->m_sb.sb_frextents;
 524        cnt->freeino = mp->m_sb.sb_ifree;
 525        cnt->allocino = mp->m_sb.sb_icount;
 526        spin_unlock(&mp->m_sb_lock);
 527        return 0;
 528}
 529
 530/*
 531 * exported through ioctl XFS_IOC_SET_RESBLKS & XFS_IOC_GET_RESBLKS
 532 *
 533 * xfs_reserve_blocks is called to set m_resblks
 534 * in the in-core mount table. The number of unused reserved blocks
 535 * is kept in m_resblks_avail.
 536 *
 537 * Reserve the requested number of blocks if available. Otherwise return
 538 * as many as possible to satisfy the request. The actual number
 539 * reserved are returned in outval
 540 *
 541 * A null inval pointer indicates that only the current reserved blocks
 542 * available  should  be returned no settings are changed.
 543 */
 544
 545int
 546xfs_reserve_blocks(
 547        xfs_mount_t             *mp,
 548        __uint64_t              *inval,
 549        xfs_fsop_resblks_t      *outval)
 550{
 551        __int64_t               lcounter, delta, fdblks_delta;
 552        __uint64_t              request;
 553
 554        /* If inval is null, report current values and return */
 555        if (inval == (__uint64_t *)NULL) {
 556                if (!outval)
 557                        return EINVAL;
 558                outval->resblks = mp->m_resblks;
 559                outval->resblks_avail = mp->m_resblks_avail;
 560                return 0;
 561        }
 562
 563        request = *inval;
 564
 565        /*
 566         * With per-cpu counters, this becomes an interesting
 567         * problem. we needto work out if we are freeing or allocation
 568         * blocks first, then we can do the modification as necessary.
 569         *
 570         * We do this under the m_sb_lock so that if we are near
 571         * ENOSPC, we will hold out any changes while we work out
 572         * what to do. This means that the amount of free space can
 573         * change while we do this, so we need to retry if we end up
 574         * trying to reserve more space than is available.
 575         *
 576         * We also use the xfs_mod_incore_sb() interface so that we
 577         * don't have to care about whether per cpu counter are
 578         * enabled, disabled or even compiled in....
 579         */
 580retry:
 581        spin_lock(&mp->m_sb_lock);
 582        xfs_icsb_sync_counters_locked(mp, 0);
 583
 584        /*
 585         * If our previous reservation was larger than the current value,
 586         * then move any unused blocks back to the free pool.
 587         */
 588        fdblks_delta = 0;
 589        if (mp->m_resblks > request) {
 590                lcounter = mp->m_resblks_avail - request;
 591                if (lcounter  > 0) {            /* release unused blocks */
 592                        fdblks_delta = lcounter;
 593                        mp->m_resblks_avail -= lcounter;
 594                }
 595                mp->m_resblks = request;
 596        } else {
 597                __int64_t       free;
 598
 599                free =  mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);
 600                if (!free)
 601                        goto out; /* ENOSPC and fdblks_delta = 0 */
 602
 603                delta = request - mp->m_resblks;
 604                lcounter = free - delta;
 605                if (lcounter < 0) {
 606                        /* We can't satisfy the request, just get what we can */
 607                        mp->m_resblks += free;
 608                        mp->m_resblks_avail += free;
 609                        fdblks_delta = -free;
 610                } else {
 611                        fdblks_delta = -delta;
 612                        mp->m_resblks = request;
 613                        mp->m_resblks_avail += delta;
 614                }
 615        }
 616out:
 617        if (outval) {
 618                outval->resblks = mp->m_resblks;
 619                outval->resblks_avail = mp->m_resblks_avail;
 620        }
 621        spin_unlock(&mp->m_sb_lock);
 622
 623        if (fdblks_delta) {
 624                /*
 625                 * If we are putting blocks back here, m_resblks_avail is
 626                 * already at its max so this will put it in the free pool.
 627                 *
 628                 * If we need space, we'll either succeed in getting it
 629                 * from the free block count or we'll get an enospc. If
 630                 * we get a ENOSPC, it means things changed while we were
 631                 * calculating fdblks_delta and so we should try again to
 632                 * see if there is anything left to reserve.
 633                 *
 634                 * Don't set the reserved flag here - we don't want to reserve
 635                 * the extra reserve blocks from the reserve.....
 636                 */
 637                int error;
 638                error = xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS,
 639                                                 fdblks_delta, 0);
 640                if (error == ENOSPC)
 641                        goto retry;
 642        }
 643        return 0;
 644}
 645
 646/*
 647 * Dump a transaction into the log that contains no real change. This is needed
 648 * to be able to make the log dirty or stamp the current tail LSN into the log
 649 * during the covering operation.
 650 *
 651 * We cannot use an inode here for this - that will push dirty state back up
 652 * into the VFS and then periodic inode flushing will prevent log covering from
 653 * making progress. Hence we log a field in the superblock instead and use a
 654 * synchronous transaction to ensure the superblock is immediately unpinned
 655 * and can be written back.
 656 */
 657int
 658xfs_fs_log_dummy(
 659        xfs_mount_t     *mp)
 660{
 661        xfs_trans_t     *tp;
 662        int             error;
 663
 664        tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1, KM_SLEEP);
 665        error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
 666                                        XFS_DEFAULT_LOG_COUNT);
 667        if (error) {
 668                xfs_trans_cancel(tp, 0);
 669                return error;
 670        }
 671
 672        /* log the UUID because it is an unchanging field */
 673        xfs_mod_sb(tp, XFS_SB_UUID);
 674        xfs_trans_set_sync(tp);
 675        return xfs_trans_commit(tp, 0);
 676}
 677
 678int
 679xfs_fs_goingdown(
 680        xfs_mount_t     *mp,
 681        __uint32_t      inflags)
 682{
 683        switch (inflags) {
 684        case XFS_FSOP_GOING_FLAGS_DEFAULT: {
 685                struct super_block *sb = freeze_bdev(mp->m_super->s_bdev);
 686
 687                if (sb && !IS_ERR(sb)) {
 688                        xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
 689                        thaw_bdev(sb->s_bdev, sb);
 690                }
 691
 692                break;
 693        }
 694        case XFS_FSOP_GOING_FLAGS_LOGFLUSH:
 695                xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT);
 696                break;
 697        case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH:
 698                xfs_force_shutdown(mp,
 699                                SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR);
 700                break;
 701        default:
 702                return XFS_ERROR(EINVAL);
 703        }
 704
 705        return 0;
 706}
 707
 708/*
 709 * Force a shutdown of the filesystem instantly while keeping the filesystem
 710 * consistent. We don't do an unmount here; just shutdown the shop, make sure
 711 * that absolutely nothing persistent happens to this filesystem after this
 712 * point.
 713 */
 714void
 715xfs_do_force_shutdown(
 716        xfs_mount_t     *mp,
 717        int             flags,
 718        char            *fname,
 719        int             lnnum)
 720{
 721        int             logerror;
 722
 723        logerror = flags & SHUTDOWN_LOG_IO_ERROR;
 724
 725        if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
 726                xfs_notice(mp,
 727        "%s(0x%x) called from line %d of file %s.  Return address = 0x%p",
 728                        __func__, flags, lnnum, fname, __return_address);
 729        }
 730        /*
 731         * No need to duplicate efforts.
 732         */
 733        if (XFS_FORCED_SHUTDOWN(mp) && !logerror)
 734                return;
 735
 736        /*
 737         * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't
 738         * queue up anybody new on the log reservations, and wakes up
 739         * everybody who's sleeping on log reservations to tell them
 740         * the bad news.
 741         */
 742        if (xfs_log_force_umount(mp, logerror))
 743                return;
 744
 745        if (flags & SHUTDOWN_CORRUPT_INCORE) {
 746                xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT,
 747    "Corruption of in-memory data detected.  Shutting down filesystem");
 748                if (XFS_ERRLEVEL_HIGH <= xfs_error_level)
 749                        xfs_stack_trace();
 750        } else if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
 751                if (logerror) {
 752                        xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR,
 753                "Log I/O Error Detected.  Shutting down filesystem");
 754                } else if (flags & SHUTDOWN_DEVICE_REQ) {
 755                        xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
 756                "All device paths lost.  Shutting down filesystem");
 757                } else if (!(flags & SHUTDOWN_REMOTE_REQ)) {
 758                        xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
 759                "I/O Error Detected. Shutting down filesystem");
 760                }
 761        }
 762        if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
 763                xfs_alert(mp,
 764        "Please umount the filesystem and rectify the problem(s)");
 765        }
 766}
 767
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.