]> Git Repo - linux.git/commitdiff
Merge branch 'xfs-misc-fixes-4.6-3' into for-next
authorDave Chinner <[email protected]>
Tue, 8 Mar 2016 21:18:30 +0000 (08:18 +1100)
committerDave Chinner <[email protected]>
Tue, 8 Mar 2016 21:18:30 +0000 (08:18 +1100)
1  2 
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_super.c

diff --combined fs/xfs/libxfs/xfs_bmap.c
index cb58d728a4d0d025822abfa258013826c4b555de,9054c500ce4436507c9b7dea14d9c3c18f397d1b..79e898cb5562c1278e8831c3f7128d16f2ced8ba
@@@ -477,10 -477,7 +477,7 @@@ xfs_bmap_check_leaf_extents
                }
                block = XFS_BUF_TO_BLOCK(bp);
        }
-       if (bp_release) {
-               bp_release = 0;
-               xfs_trans_brelse(NULL, bp);
-       }
        return;
  
  error0:
@@@ -912,7 -909,7 +909,7 @@@ xfs_bmap_local_to_extents
         * We don't want to deal with the case of keeping inode data inline yet.
         * So sending the data fork of a regular inode is invalid.
         */
 -      ASSERT(!(S_ISREG(ip->i_d.di_mode) && whichfork == XFS_DATA_FORK));
 +      ASSERT(!(S_ISREG(VFS_I(ip)->i_mode) && whichfork == XFS_DATA_FORK));
        ifp = XFS_IFORK_PTR(ip, whichfork);
        ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
  
@@@ -1079,7 -1076,7 +1076,7 @@@ xfs_bmap_add_attrfork_local
        if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip))
                return 0;
  
 -      if (S_ISDIR(ip->i_d.di_mode)) {
 +      if (S_ISDIR(VFS_I(ip)->i_mode)) {
                memset(&dargs, 0, sizeof(dargs));
                dargs.geo = ip->i_mount->m_dir_geo;
                dargs.dp = ip;
                return xfs_dir2_sf_to_block(&dargs);
        }
  
 -      if (S_ISLNK(ip->i_d.di_mode))
 +      if (S_ISLNK(VFS_I(ip)->i_mode))
                return xfs_bmap_local_to_extents(tp, ip, firstblock, 1,
                                                 flags, XFS_DATA_FORK,
                                                 xfs_symlink_local_to_remote);
@@@ -5210,7 -5207,7 +5207,7 @@@ xfs_bunmapi
                         * This is better than zeroing it.
                         */
                        ASSERT(del.br_state == XFS_EXT_NORM);
 -                      ASSERT(xfs_trans_get_block_res(tp) > 0);
 +                      ASSERT(tp->t_blk_res > 0);
                        /*
                         * If this spans a realtime extent boundary,
                         * chop it back to the start of the one we end at.
                                del.br_startblock += mod;
                        } else if ((del.br_startoff == start &&
                                    (del.br_state == XFS_EXT_UNWRITTEN ||
 -                                   xfs_trans_get_block_res(tp) == 0)) ||
 +                                   tp->t_blk_res == 0)) ||
                                   !xfs_sb_version_hasextflgbit(&mp->m_sb)) {
                                /*
                                 * Can't make it unwritten.  There isn't
                 * conversion to btree format, since the transaction
                 * will be dirty.
                 */
 -              if (!wasdel && xfs_trans_get_block_res(tp) == 0 &&
 +              if (!wasdel && tp->t_blk_res == 0 &&
                    XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&
                    XFS_IFORK_NEXTENTS(ip, whichfork) >= /* Note the >= */
                        XFS_IFORK_MAXEXT(ip, whichfork) &&
diff --combined fs/xfs/xfs_log_recover.c
index 9347bf1bdc001c4295450dcb4c151e16357abc46,60c385f43a538bf3cf82fe8b4900e82ed818c6c9..396565f4324764058b979cf5e4c5bd96744f8ef8
@@@ -1108,10 -1108,27 +1108,10 @@@ xlog_verify_head
        bool                    tmp_wrapped;
  
        /*
 -       * Search backwards through the log looking for the log record header
 -       * block. This wraps all the way back around to the head so something is
 -       * seriously wrong if we can't find it.
 -       */
 -      found = xlog_rseek_logrec_hdr(log, *head_blk, *head_blk, 1, bp, rhead_blk,
 -                                    rhead, wrapped);
 -      if (found < 0)
 -              return found;
 -      if (!found) {
 -              xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__);
 -              return -EIO;
 -      }
 -
 -      *tail_blk = BLOCK_LSN(be64_to_cpu((*rhead)->h_tail_lsn));
 -
 -      /*
 -       * Now that we have a tail block, check the head of the log for torn
 -       * writes. Search again until we hit the tail or the maximum number of
 -       * log record I/Os that could have been in flight at one time. Use a
 -       * temporary buffer so we don't trash the rhead/bp pointer from the
 -       * call above.
 +       * Check the head of the log for torn writes. Search backwards from the
 +       * head until we hit the tail or the maximum number of log record I/Os
 +       * that could have been in flight at one time. Use a temporary buffer so
 +       * we don't trash the rhead/bp pointers from the caller.
         */
        tmp_bp = xlog_get_bp(log, 1);
        if (!tmp_bp)
        return error;
  }
  
 +/*
 + * Check whether the head of the log points to an unmount record. In other
 + * words, determine whether the log is clean. If so, update the in-core state
 + * appropriately.
 + */
 +static int
 +xlog_check_unmount_rec(
 +      struct xlog             *log,
 +      xfs_daddr_t             *head_blk,
 +      xfs_daddr_t             *tail_blk,
 +      struct xlog_rec_header  *rhead,
 +      xfs_daddr_t             rhead_blk,
 +      struct xfs_buf          *bp,
 +      bool                    *clean)
 +{
 +      struct xlog_op_header   *op_head;
 +      xfs_daddr_t             umount_data_blk;
 +      xfs_daddr_t             after_umount_blk;
 +      int                     hblks;
 +      int                     error;
 +      char                    *offset;
 +
 +      *clean = false;
 +
 +      /*
 +       * Look for unmount record. If we find it, then we know there was a
 +       * clean unmount. Since 'i' could be the last block in the physical
 +       * log, we convert to a log block before comparing to the head_blk.
 +       *
 +       * Save the current tail lsn to use to pass to xlog_clear_stale_blocks()
 +       * below. We won't want to clear the unmount record if there is one, so
 +       * we pass the lsn of the unmount record rather than the block after it.
 +       */
 +      if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) {
 +              int     h_size = be32_to_cpu(rhead->h_size);
 +              int     h_version = be32_to_cpu(rhead->h_version);
 +
 +              if ((h_version & XLOG_VERSION_2) &&
 +                  (h_size > XLOG_HEADER_CYCLE_SIZE)) {
 +                      hblks = h_size / XLOG_HEADER_CYCLE_SIZE;
 +                      if (h_size % XLOG_HEADER_CYCLE_SIZE)
 +                              hblks++;
 +              } else {
 +                      hblks = 1;
 +              }
 +      } else {
 +              hblks = 1;
 +      }
 +      after_umount_blk = rhead_blk + hblks + BTOBB(be32_to_cpu(rhead->h_len));
 +      after_umount_blk = do_mod(after_umount_blk, log->l_logBBsize);
 +      if (*head_blk == after_umount_blk &&
 +          be32_to_cpu(rhead->h_num_logops) == 1) {
 +              umount_data_blk = rhead_blk + hblks;
 +              umount_data_blk = do_mod(umount_data_blk, log->l_logBBsize);
 +              error = xlog_bread(log, umount_data_blk, 1, bp, &offset);
 +              if (error)
 +                      return error;
 +
 +              op_head = (struct xlog_op_header *)offset;
 +              if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) {
 +                      /*
 +                       * Set tail and last sync so that newly written log
 +                       * records will point recovery to after the current
 +                       * unmount record.
 +                       */
 +                      xlog_assign_atomic_lsn(&log->l_tail_lsn,
 +                                      log->l_curr_cycle, after_umount_blk);
 +                      xlog_assign_atomic_lsn(&log->l_last_sync_lsn,
 +                                      log->l_curr_cycle, after_umount_blk);
 +                      *tail_blk = after_umount_blk;
 +
 +                      *clean = true;
 +              }
 +      }
 +
 +      return 0;
 +}
 +
 +static void
 +xlog_set_state(
 +      struct xlog             *log,
 +      xfs_daddr_t             head_blk,
 +      struct xlog_rec_header  *rhead,
 +      xfs_daddr_t             rhead_blk,
 +      bool                    bump_cycle)
 +{
 +      /*
 +       * Reset log values according to the state of the log when we
 +       * crashed.  In the case where head_blk == 0, we bump curr_cycle
 +       * one because the next write starts a new cycle rather than
 +       * continuing the cycle of the last good log record.  At this
 +       * point we have guaranteed that all partial log records have been
 +       * accounted for.  Therefore, we know that the last good log record
 +       * written was complete and ended exactly on the end boundary
 +       * of the physical log.
 +       */
 +      log->l_prev_block = rhead_blk;
 +      log->l_curr_block = (int)head_blk;
 +      log->l_curr_cycle = be32_to_cpu(rhead->h_cycle);
 +      if (bump_cycle)
 +              log->l_curr_cycle++;
 +      atomic64_set(&log->l_tail_lsn, be64_to_cpu(rhead->h_tail_lsn));
 +      atomic64_set(&log->l_last_sync_lsn, be64_to_cpu(rhead->h_lsn));
 +      xlog_assign_grant_head(&log->l_reserve_head.grant, log->l_curr_cycle,
 +                                      BBTOB(log->l_curr_block));
 +      xlog_assign_grant_head(&log->l_write_head.grant, log->l_curr_cycle,
 +                                      BBTOB(log->l_curr_block));
 +}
 +
  /*
   * Find the sync block number or the tail of the log.
   *
@@@ -1329,20 -1237,22 +1329,20 @@@ xlog_find_tail
        xfs_daddr_t             *tail_blk)
  {
        xlog_rec_header_t       *rhead;
 -      xlog_op_header_t        *op_head;
        char                    *offset = NULL;
        xfs_buf_t               *bp;
        int                     error;
 -      xfs_daddr_t             umount_data_blk;
 -      xfs_daddr_t             after_umount_blk;
        xfs_daddr_t             rhead_blk;
        xfs_lsn_t               tail_lsn;
 -      int                     hblks;
        bool                    wrapped = false;
 +      bool                    clean = false;
  
        /*
         * Find previous log record
         */
        if ((error = xlog_find_head(log, head_blk)))
                return error;
 +      ASSERT(*head_blk < INT_MAX);
  
        bp = xlog_get_bp(log, 1);
        if (!bp)
        }
  
        /*
 -       * Trim the head block back to skip over torn records. We can have
 -       * multiple log I/Os in flight at any time, so we assume CRC failures
 -       * back through the previous several records are torn writes and skip
 -       * them.
 +       * Search backwards through the log looking for the log record header
 +       * block. This wraps all the way back around to the head so something is
 +       * seriously wrong if we can't find it.
         */
 -      ASSERT(*head_blk < INT_MAX);
 -      error = xlog_verify_head(log, head_blk, tail_blk, bp, &rhead_blk,
 -                               &rhead, &wrapped);
 -      if (error)
 -              goto done;
 +      error = xlog_rseek_logrec_hdr(log, *head_blk, *head_blk, 1, bp,
 +                                    &rhead_blk, &rhead, &wrapped);
 +      if (error < 0)
 +              return error;
 +      if (!error) {
 +              xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__);
 +              return -EIO;
 +      }
 +      *tail_blk = BLOCK_LSN(be64_to_cpu(rhead->h_tail_lsn));
  
        /*
 -       * Reset log values according to the state of the log when we
 -       * crashed.  In the case where head_blk == 0, we bump curr_cycle
 -       * one because the next write starts a new cycle rather than
 -       * continuing the cycle of the last good log record.  At this
 -       * point we have guaranteed that all partial log records have been
 -       * accounted for.  Therefore, we know that the last good log record
 -       * written was complete and ended exactly on the end boundary
 -       * of the physical log.
 +       * Set the log state based on the current head record.
         */
 -      log->l_prev_block = rhead_blk;
 -      log->l_curr_block = (int)*head_blk;
 -      log->l_curr_cycle = be32_to_cpu(rhead->h_cycle);
 -      if (wrapped)
 -              log->l_curr_cycle++;
 -      atomic64_set(&log->l_tail_lsn, be64_to_cpu(rhead->h_tail_lsn));
 -      atomic64_set(&log->l_last_sync_lsn, be64_to_cpu(rhead->h_lsn));
 -      xlog_assign_grant_head(&log->l_reserve_head.grant, log->l_curr_cycle,
 -                                      BBTOB(log->l_curr_block));
 -      xlog_assign_grant_head(&log->l_write_head.grant, log->l_curr_cycle,
 -                                      BBTOB(log->l_curr_block));
 +      xlog_set_state(log, *head_blk, rhead, rhead_blk, wrapped);
 +      tail_lsn = atomic64_read(&log->l_tail_lsn);
 +
 +      /*
 +       * Look for an unmount record at the head of the log. This sets the log
 +       * state to determine whether recovery is necessary.
 +       */
 +      error = xlog_check_unmount_rec(log, head_blk, tail_blk, rhead,
 +                                     rhead_blk, bp, &clean);
 +      if (error)
 +              goto done;
  
        /*
 -       * Look for unmount record.  If we find it, then we know there
 -       * was a clean unmount.  Since 'i' could be the last block in
 -       * the physical log, we convert to a log block before comparing
 -       * to the head_blk.
 +       * Verify the log head if the log is not clean (e.g., we have anything
 +       * but an unmount record at the head). This uses CRC verification to
 +       * detect and trim torn writes. If discovered, CRC failures are
 +       * considered torn writes and the log head is trimmed accordingly.
         *
 -       * Save the current tail lsn to use to pass to
 -       * xlog_clear_stale_blocks() below.  We won't want to clear the
 -       * unmount record if there is one, so we pass the lsn of the
 -       * unmount record rather than the block after it.
 +       * Note that we can only run CRC verification when the log is dirty
 +       * because there's no guarantee that the log data behind an unmount
 +       * record is compatible with the current architecture.
         */
 -      if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) {
 -              int     h_size = be32_to_cpu(rhead->h_size);
 -              int     h_version = be32_to_cpu(rhead->h_version);
 +      if (!clean) {
 +              xfs_daddr_t     orig_head = *head_blk;
  
 -              if ((h_version & XLOG_VERSION_2) &&
 -                  (h_size > XLOG_HEADER_CYCLE_SIZE)) {
 -                      hblks = h_size / XLOG_HEADER_CYCLE_SIZE;
 -                      if (h_size % XLOG_HEADER_CYCLE_SIZE)
 -                              hblks++;
 -              } else {
 -                      hblks = 1;
 -              }
 -      } else {
 -              hblks = 1;
 -      }
 -      after_umount_blk = rhead_blk + hblks + BTOBB(be32_to_cpu(rhead->h_len));
 -      after_umount_blk = do_mod(after_umount_blk, log->l_logBBsize);
 -      tail_lsn = atomic64_read(&log->l_tail_lsn);
 -      if (*head_blk == after_umount_blk &&
 -          be32_to_cpu(rhead->h_num_logops) == 1) {
 -              umount_data_blk = rhead_blk + hblks;
 -              umount_data_blk = do_mod(umount_data_blk, log->l_logBBsize);
 -              error = xlog_bread(log, umount_data_blk, 1, bp, &offset);
 +              error = xlog_verify_head(log, head_blk, tail_blk, bp,
 +                                       &rhead_blk, &rhead, &wrapped);
                if (error)
                        goto done;
  
 -              op_head = (xlog_op_header_t *)offset;
 -              if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) {
 -                      /*
 -                       * Set tail and last sync so that newly written
 -                       * log records will point recovery to after the
 -                       * current unmount record.
 -                       */
 -                      xlog_assign_atomic_lsn(&log->l_tail_lsn,
 -                                      log->l_curr_cycle, after_umount_blk);
 -                      xlog_assign_atomic_lsn(&log->l_last_sync_lsn,
 -                                      log->l_curr_cycle, after_umount_blk);
 -                      *tail_blk = after_umount_blk;
 -
 -                      /*
 -                       * Note that the unmount was clean. If the unmount
 -                       * was not clean, we need to know this to rebuild the
 -                       * superblock counters from the perag headers if we
 -                       * have a filesystem using non-persistent counters.
 -                       */
 -                      log->l_mp->m_flags |= XFS_MOUNT_WAS_CLEAN;
 +              /* update in-core state again if the head changed */
 +              if (*head_blk != orig_head) {
 +                      xlog_set_state(log, *head_blk, rhead, rhead_blk,
 +                                     wrapped);
 +                      tail_lsn = atomic64_read(&log->l_tail_lsn);
 +                      error = xlog_check_unmount_rec(log, head_blk, tail_blk,
 +                                                     rhead, rhead_blk, bp,
 +                                                     &clean);
 +                      if (error)
 +                              goto done;
                }
        }
  
 +      /*
 +       * Note that the unmount was clean. If the unmount was not clean, we
 +       * need to know this to rebuild the superblock counters from the perag
 +       * headers if we have a filesystem using non-persistent counters.
 +       */
 +      if (clean)
 +              log->l_mp->m_flags |= XFS_MOUNT_WAS_CLEAN;
 +
        /*
         * Make sure that there are no blocks in front of the head
         * with the same cycle number as the head.  This can happen
@@@ -2537,13 -2472,6 +2537,13 @@@ xlog_recover_validate_buf_type
                }
                bp->b_ops = &xfs_sb_buf_ops;
                break;
 +#ifdef CONFIG_XFS_RT
 +      case XFS_BLFT_RTBITMAP_BUF:
 +      case XFS_BLFT_RTSUMMARY_BUF:
 +              /* no magic numbers for verification of RT buffers */
 +              bp->b_ops = &xfs_rtbuf_ops;
 +              break;
 +#endif /* CONFIG_XFS_RT */
        default:
                xfs_warn(mp, "Unknown buffer type %d!",
                         xfs_blft_from_flags(buf_f));
@@@ -2864,7 -2792,7 +2864,7 @@@ xfs_recover_inode_owner_change
                return -ENOMEM;
  
        /* instantiate the inode */
 -      xfs_dinode_from_disk(&ip->i_d, dip);
 +      xfs_inode_from_disk(ip, dip);
        ASSERT(ip->i_d.di_version >= 3);
  
        error = xfs_iformat_fork(ip, dip);
@@@ -2910,7 -2838,7 +2910,7 @@@ xlog_recover_inode_pass2
        int                     error;
        int                     attr_index;
        uint                    fields;
 -      xfs_icdinode_t          *dicp;
 +      struct xfs_log_dinode   *ldip;
        uint                    isize;
        int                     need_free = 0;
  
                error = -EFSCORRUPTED;
                goto out_release;
        }
 -      dicp = item->ri_buf[1].i_addr;
 -      if (unlikely(dicp->di_magic != XFS_DINODE_MAGIC)) {
 +      ldip = item->ri_buf[1].i_addr;
 +      if (unlikely(ldip->di_magic != XFS_DINODE_MAGIC)) {
                xfs_alert(mp,
                        "%s: Bad inode log record, rec ptr 0x%p, ino %Ld",
                        __func__, item, in_f->ilf_ino);
         * to skip replay when the on disk inode is newer than the log one
         */
        if (!xfs_sb_version_hascrc(&mp->m_sb) &&
 -          dicp->di_flushiter < be16_to_cpu(dip->di_flushiter)) {
 +          ldip->di_flushiter < be16_to_cpu(dip->di_flushiter)) {
                /*
                 * Deal with the wrap case, DI_MAX_FLUSH is less
                 * than smaller numbers
                 */
                if (be16_to_cpu(dip->di_flushiter) == DI_MAX_FLUSH &&
 -                  dicp->di_flushiter < (DI_MAX_FLUSH >> 1)) {
 +                  ldip->di_flushiter < (DI_MAX_FLUSH >> 1)) {
                        /* do nothing */
                } else {
                        trace_xfs_log_recover_inode_skip(log, in_f);
        }
  
        /* Take the opportunity to reset the flush iteration count */
 -      dicp->di_flushiter = 0;
 +      ldip->di_flushiter = 0;
  
 -      if (unlikely(S_ISREG(dicp->di_mode))) {
 -              if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) &&
 -                  (dicp->di_format != XFS_DINODE_FMT_BTREE)) {
 +      if (unlikely(S_ISREG(ldip->di_mode))) {
 +              if ((ldip->di_format != XFS_DINODE_FMT_EXTENTS) &&
 +                  (ldip->di_format != XFS_DINODE_FMT_BTREE)) {
                        XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(3)",
 -                                       XFS_ERRLEVEL_LOW, mp, dicp);
 +                                       XFS_ERRLEVEL_LOW, mp, ldip);
                        xfs_alert(mp,
                "%s: Bad regular inode log record, rec ptr 0x%p, "
                "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
                        error = -EFSCORRUPTED;
                        goto out_release;
                }
 -      } else if (unlikely(S_ISDIR(dicp->di_mode))) {
 -              if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) &&
 -                  (dicp->di_format != XFS_DINODE_FMT_BTREE) &&
 -                  (dicp->di_format != XFS_DINODE_FMT_LOCAL)) {
 +      } else if (unlikely(S_ISDIR(ldip->di_mode))) {
 +              if ((ldip->di_format != XFS_DINODE_FMT_EXTENTS) &&
 +                  (ldip->di_format != XFS_DINODE_FMT_BTREE) &&
 +                  (ldip->di_format != XFS_DINODE_FMT_LOCAL)) {
                        XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(4)",
 -                                           XFS_ERRLEVEL_LOW, mp, dicp);
 +                                           XFS_ERRLEVEL_LOW, mp, ldip);
                        xfs_alert(mp,
                "%s: Bad dir inode log record, rec ptr 0x%p, "
                "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
                        goto out_release;
                }
        }
 -      if (unlikely(dicp->di_nextents + dicp->di_anextents > dicp->di_nblocks)){
 +      if (unlikely(ldip->di_nextents + ldip->di_anextents > ldip->di_nblocks)){
                XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(5)",
 -                                   XFS_ERRLEVEL_LOW, mp, dicp);
 +                                   XFS_ERRLEVEL_LOW, mp, ldip);
                xfs_alert(mp,
        "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, "
        "dino bp 0x%p, ino %Ld, total extents = %d, nblocks = %Ld",
                        __func__, item, dip, bp, in_f->ilf_ino,
 -                      dicp->di_nextents + dicp->di_anextents,
 -                      dicp->di_nblocks);
 +                      ldip->di_nextents + ldip->di_anextents,
 +                      ldip->di_nblocks);
                error = -EFSCORRUPTED;
                goto out_release;
        }
 -      if (unlikely(dicp->di_forkoff > mp->m_sb.sb_inodesize)) {
 +      if (unlikely(ldip->di_forkoff > mp->m_sb.sb_inodesize)) {
                XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(6)",
 -                                   XFS_ERRLEVEL_LOW, mp, dicp);
 +                                   XFS_ERRLEVEL_LOW, mp, ldip);
                xfs_alert(mp,
        "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, "
        "dino bp 0x%p, ino %Ld, forkoff 0x%x", __func__,
 -                      item, dip, bp, in_f->ilf_ino, dicp->di_forkoff);
 +                      item, dip, bp, in_f->ilf_ino, ldip->di_forkoff);
                error = -EFSCORRUPTED;
                goto out_release;
        }
 -      isize = xfs_icdinode_size(dicp->di_version);
 +      isize = xfs_log_dinode_size(ldip->di_version);
        if (unlikely(item->ri_buf[1].i_len > isize)) {
                XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(7)",
 -                                   XFS_ERRLEVEL_LOW, mp, dicp);
 +                                   XFS_ERRLEVEL_LOW, mp, ldip);
                xfs_alert(mp,
                        "%s: Bad inode log record length %d, rec ptr 0x%p",
                        __func__, item->ri_buf[1].i_len, item);
                goto out_release;
        }
  
 -      /* The core is in in-core format */
 -      xfs_dinode_to_disk(dip, dicp);
 +      /* recover the log dinode inode into the on disk inode */
 +      xfs_log_dinode_to_disk(ldip, dip);
  
        /* the rest is in on-disk format */
        if (item->ri_buf[1].i_len > isize) {
@@@ -4408,8 -4336,8 +4408,8 @@@ xlog_recover_process_one_iunlink
        if (error)
                goto fail_iput;
  
 -      ASSERT(ip->i_d.di_nlink == 0);
 -      ASSERT(ip->i_d.di_mode != 0);
 +      ASSERT(VFS_I(ip)->i_nlink == 0);
 +      ASSERT(VFS_I(ip)->i_mode != 0);
  
        /* setup for the next pass */
        agino = be32_to_cpu(dip->di_next_unlinked);
@@@ -4562,7 -4490,7 +4562,7 @@@ xlog_recover_process
         * know precisely what failed.
         */
        if (pass == XLOG_RECOVER_CRCPASS) {
 -              if (rhead->h_crc && crc != le32_to_cpu(rhead->h_crc))
 +              if (rhead->h_crc && crc != rhead->h_crc)
                        return -EFSBADCRC;
                return 0;
        }
         * zero CRC check prevents warnings from being emitted when upgrading
         * the kernel from one that does not add CRCs by default.
         */
 -      if (crc != le32_to_cpu(rhead->h_crc)) {
 +      if (crc != rhead->h_crc) {
                if (rhead->h_crc || xfs_sb_version_hascrc(&log->l_mp->m_sb)) {
                        xfs_alert(log->l_mp,
                "log record CRC mismatch: found 0x%x, expected 0x%x.",
@@@ -4963,6 -4891,7 +4963,7 @@@ xlog_do_recover
        xfs_daddr_t     head_blk,
        xfs_daddr_t     tail_blk)
  {
+       struct xfs_mount *mp = log->l_mp;
        int             error;
        xfs_buf_t       *bp;
        xfs_sb_t        *sbp;
        /*
         * If IO errors happened during recovery, bail out.
         */
-       if (XFS_FORCED_SHUTDOWN(log->l_mp)) {
+       if (XFS_FORCED_SHUTDOWN(mp)) {
                return -EIO;
        }
  
         * or iunlinks they will have some entries in the AIL; so we look at
         * the AIL to determine how to set the tail_lsn.
         */
-       xlog_assign_tail_lsn(log->l_mp);
+       xlog_assign_tail_lsn(mp);
  
        /*
         * Now that we've finished replaying all buffer and inode
         * updates, re-read in the superblock and reverify it.
         */
-       bp = xfs_getsb(log->l_mp, 0);
+       bp = xfs_getsb(mp, 0);
        bp->b_flags &= ~(XBF_DONE | XBF_ASYNC);
        ASSERT(!(bp->b_flags & XBF_WRITE));
        bp->b_flags |= XBF_READ;
  
        error = xfs_buf_submit_wait(bp);
        if (error) {
-               if (!XFS_FORCED_SHUTDOWN(log->l_mp)) {
+               if (!XFS_FORCED_SHUTDOWN(mp)) {
                        xfs_buf_ioerror_alert(bp, __func__);
                        ASSERT(0);
                }
        }
  
        /* Convert superblock from on-disk format */
-       sbp = &log->l_mp->m_sb;
+       sbp = &mp->m_sb;
        xfs_sb_from_disk(sbp, XFS_BUF_TO_SBP(bp));
-       ASSERT(sbp->sb_magicnum == XFS_SB_MAGIC);
-       ASSERT(xfs_sb_good_version(sbp));
-       xfs_reinit_percpu_counters(log->l_mp);
        xfs_buf_relse(bp);
  
+       /* re-initialise in-core superblock and geometry structures */
+       xfs_reinit_percpu_counters(mp);
+       error = xfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi);
+       if (error) {
+               xfs_warn(mp, "Failed post-recovery per-ag init: %d", error);
+               return error;
+       }
  
        xlog_recover_check_summary(log);
  
diff --combined fs/xfs/xfs_super.c
index d85087bc0c406d6f36e4a90ade3a76f45753229c,3bd2027a7ea65cb1c1a7e94004e71578ead6a907..d760934109b5d628891ea3e91fa1a9e3f68ec36b
@@@ -45,6 -45,7 +45,7 @@@
  #include "xfs_filestream.h"
  #include "xfs_quota.h"
  #include "xfs_sysfs.h"
+ #include "xfs_ondisk.h"
  
  #include <linux/namei.h>
  #include <linux/init.h>
@@@ -65,85 -66,83 +66,85 @@@ static struct kset *xfs_kset;              /* top-l
  static struct xfs_kobj xfs_dbg_kobj;  /* global debug sysfs attrs */
  #endif
  
 -#define MNTOPT_LOGBUFS        "logbufs"       /* number of XFS log buffers */
 -#define MNTOPT_LOGBSIZE       "logbsize"      /* size of XFS log buffers */
 -#define MNTOPT_LOGDEV "logdev"        /* log device */
 -#define MNTOPT_RTDEV  "rtdev"         /* realtime I/O device */
 -#define MNTOPT_BIOSIZE        "biosize"       /* log2 of preferred buffered io size */
 -#define MNTOPT_WSYNC  "wsync"         /* safe-mode nfs compatible mount */
 -#define MNTOPT_NOALIGN        "noalign"       /* turn off stripe alignment */
 -#define MNTOPT_SWALLOC        "swalloc"       /* turn on stripe width allocation */
 -#define MNTOPT_SUNIT  "sunit"         /* data volume stripe unit */
 -#define MNTOPT_SWIDTH "swidth"        /* data volume stripe width */
 -#define MNTOPT_NOUUID "nouuid"        /* ignore filesystem UUID */
 -#define MNTOPT_MTPT   "mtpt"          /* filesystem mount point */
 -#define MNTOPT_GRPID  "grpid"         /* group-ID from parent directory */
 -#define MNTOPT_NOGRPID        "nogrpid"       /* group-ID from current process */
 -#define MNTOPT_BSDGROUPS    "bsdgroups"    /* group-ID from parent directory */
 -#define MNTOPT_SYSVGROUPS   "sysvgroups"   /* group-ID from current process */
 -#define MNTOPT_ALLOCSIZE    "allocsize"    /* preferred allocation size */
 -#define MNTOPT_NORECOVERY   "norecovery"   /* don't run XFS recovery */
 -#define MNTOPT_BARRIER        "barrier"       /* use writer barriers for log write and
 -                                       * unwritten extent conversion */
 -#define MNTOPT_NOBARRIER "nobarrier"  /* .. disable */
 -#define MNTOPT_64BITINODE   "inode64" /* inodes can be allocated anywhere */
 -#define MNTOPT_32BITINODE   "inode32" /* inode allocation limited to
 -                                       * XFS_MAXINUMBER_32 */
 -#define MNTOPT_IKEEP  "ikeep"         /* do not free empty inode clusters */
 -#define MNTOPT_NOIKEEP        "noikeep"       /* free empty inode clusters */
 -#define MNTOPT_LARGEIO           "largeio"    /* report large I/O sizes in stat() */
 -#define MNTOPT_NOLARGEIO   "nolargeio"        /* do not report large I/O sizes
 -                                       * in stat(). */
 -#define MNTOPT_ATTR2  "attr2"         /* do use attr2 attribute format */
 -#define MNTOPT_NOATTR2        "noattr2"       /* do not use attr2 attribute format */
 -#define MNTOPT_FILESTREAM  "filestreams" /* use filestreams allocator */
 -#define MNTOPT_QUOTA  "quota"         /* disk quotas (user) */
 -#define MNTOPT_NOQUOTA        "noquota"       /* no quotas */
 -#define MNTOPT_USRQUOTA       "usrquota"      /* user quota enabled */
 -#define MNTOPT_GRPQUOTA       "grpquota"      /* group quota enabled */
 -#define MNTOPT_PRJQUOTA       "prjquota"      /* project quota enabled */
 -#define MNTOPT_UQUOTA "uquota"        /* user quota (IRIX variant) */
 -#define MNTOPT_GQUOTA "gquota"        /* group quota (IRIX variant) */
 -#define MNTOPT_PQUOTA "pquota"        /* project quota (IRIX variant) */
 -#define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */
 -#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
 -#define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */
 -#define MNTOPT_QUOTANOENF  "qnoenforce"       /* same as uqnoenforce */
 -#define MNTOPT_DISCARD           "discard"    /* Discard unused blocks */
 -#define MNTOPT_NODISCARD   "nodiscard"        /* Do not discard unused blocks */
 -
 -#define MNTOPT_DAX    "dax"           /* Enable direct access to bdev pages */
 -
  /*
   * Table driven mount option parser.
 - *
 - * Currently only used for remount, but it will be used for mount
 - * in the future, too.
   */
  enum {
 -      Opt_barrier,
 -      Opt_nobarrier,
 -      Opt_inode64,
 -      Opt_inode32,
 -      Opt_err
 +      Opt_logbufs, Opt_logbsize, Opt_logdev, Opt_rtdev, Opt_biosize,
 +      Opt_wsync, Opt_noalign, Opt_swalloc, Opt_sunit, Opt_swidth, Opt_nouuid,
 +      Opt_mtpt, Opt_grpid, Opt_nogrpid, Opt_bsdgroups, Opt_sysvgroups,
 +      Opt_allocsize, Opt_norecovery, Opt_barrier, Opt_nobarrier,
 +      Opt_inode64, Opt_inode32, Opt_ikeep, Opt_noikeep,
 +      Opt_largeio, Opt_nolargeio, Opt_attr2, Opt_noattr2, Opt_filestreams,
 +      Opt_quota, Opt_noquota, Opt_usrquota, Opt_grpquota, Opt_prjquota,
 +      Opt_uquota, Opt_gquota, Opt_pquota,
 +      Opt_uqnoenforce, Opt_gqnoenforce, Opt_pqnoenforce, Opt_qnoenforce,
 +      Opt_discard, Opt_nodiscard, Opt_dax, Opt_err,
  };
  
  static const match_table_t tokens = {
 -      {Opt_barrier, "barrier"},
 -      {Opt_nobarrier, "nobarrier"},
 -      {Opt_inode64, "inode64"},
 -      {Opt_inode32, "inode32"},
 -      {Opt_err, NULL}
 +      {Opt_logbufs,   "logbufs=%u"},  /* number of XFS log buffers */
 +      {Opt_logbsize,  "logbsize=%s"}, /* size of XFS log buffers */
 +      {Opt_logdev,    "logdev=%s"},   /* log device */
 +      {Opt_rtdev,     "rtdev=%s"},    /* realtime I/O device */
 +      {Opt_biosize,   "biosize=%u"},  /* log2 of preferred buffered io size */
 +      {Opt_wsync,     "wsync"},       /* safe-mode nfs compatible mount */
 +      {Opt_noalign,   "noalign"},     /* turn off stripe alignment */
 +      {Opt_swalloc,   "swalloc"},     /* turn on stripe width allocation */
 +      {Opt_sunit,     "sunit=%u"},    /* data volume stripe unit */
 +      {Opt_swidth,    "swidth=%u"},   /* data volume stripe width */
 +      {Opt_nouuid,    "nouuid"},      /* ignore filesystem UUID */
 +      {Opt_mtpt,      "mtpt"},        /* filesystem mount point */
 +      {Opt_grpid,     "grpid"},       /* group-ID from parent directory */
 +      {Opt_nogrpid,   "nogrpid"},     /* group-ID from current process */
 +      {Opt_bsdgroups, "bsdgroups"},   /* group-ID from parent directory */
 +      {Opt_sysvgroups,"sysvgroups"},  /* group-ID from current process */
 +      {Opt_allocsize, "allocsize=%s"},/* preferred allocation size */
 +      {Opt_norecovery,"norecovery"},  /* don't run XFS recovery */
 +      {Opt_barrier,   "barrier"},     /* use writer barriers for log write and
 +                                       * unwritten extent conversion */
 +      {Opt_nobarrier, "nobarrier"},   /* .. disable */
 +      {Opt_inode64,   "inode64"},     /* inodes can be allocated anywhere */
 +      {Opt_inode32,   "inode32"},     /* inode allocation limited to
 +                                       * XFS_MAXINUMBER_32 */
 +      {Opt_ikeep,     "ikeep"},       /* do not free empty inode clusters */
 +      {Opt_noikeep,   "noikeep"},     /* free empty inode clusters */
 +      {Opt_largeio,   "largeio"},     /* report large I/O sizes in stat() */
 +      {Opt_nolargeio, "nolargeio"},   /* do not report large I/O sizes
 +                                       * in stat(). */
 +      {Opt_attr2,     "attr2"},       /* do use attr2 attribute format */
 +      {Opt_noattr2,   "noattr2"},     /* do not use attr2 attribute format */
 +      {Opt_filestreams,"filestreams"},/* use filestreams allocator */
 +      {Opt_quota,     "quota"},       /* disk quotas (user) */
 +      {Opt_noquota,   "noquota"},     /* no quotas */
 +      {Opt_usrquota,  "usrquota"},    /* user quota enabled */
 +      {Opt_grpquota,  "grpquota"},    /* group quota enabled */
 +      {Opt_prjquota,  "prjquota"},    /* project quota enabled */
 +      {Opt_uquota,    "uquota"},      /* user quota (IRIX variant) */
 +      {Opt_gquota,    "gquota"},      /* group quota (IRIX variant) */
 +      {Opt_pquota,    "pquota"},      /* project quota (IRIX variant) */
 +      {Opt_uqnoenforce,"uqnoenforce"},/* user quota limit enforcement */
 +      {Opt_gqnoenforce,"gqnoenforce"},/* group quota limit enforcement */
 +      {Opt_pqnoenforce,"pqnoenforce"},/* project quota limit enforcement */
 +      {Opt_qnoenforce, "qnoenforce"}, /* same as uqnoenforce */
 +      {Opt_discard,   "discard"},     /* Discard unused blocks */
 +      {Opt_nodiscard, "nodiscard"},   /* Do not discard unused blocks */
 +
 +      {Opt_dax,       "dax"},         /* Enable direct access to bdev pages */
 +      {Opt_err,       NULL},
  };
  
  
  STATIC int
 -suffix_kstrtoint(char *s, unsigned int base, int *res)
 +suffix_kstrtoint(const substring_t *s, unsigned int base, int *res)
  {
        int     last, shift_left_factor = 0, _res;
 -      char    *value = s;
 +      char    *value;
 +      int     ret = 0;
 +
 +      value = match_strdup(s);
 +      if (!value)
 +              return -ENOMEM;
  
        last = strlen(value) - 1;
        if (value[last] == 'K' || value[last] == 'k') {
                value[last] = '\0';
        }
  
 -      if (kstrtoint(s, base, &_res))
 -              return -EINVAL;
 +      if (kstrtoint(value, base, &_res))
 +              ret = -EINVAL;
 +      kfree(value);
        *res = _res << shift_left_factor;
 -      return 0;
 +      return ret;
  }
  
  /*
   *
   * Note that this function leaks the various device name allocations on
   * failure.  The caller takes care of them.
 + *
 + * *sb is const because this is also used to test options on the remount
 + * path, and we don't want this to have any side effects at remount time.
 + * Today this function does not change *sb, but just to future-proof...
   */
  STATIC int
  xfs_parseargs(
        struct xfs_mount        *mp,
        char                    *options)
  {
 -      struct super_block      *sb = mp->m_super;
 -      char                    *this_char, *value;
 +      const struct super_block *sb = mp->m_super;
 +      char                    *p;
 +      substring_t             args[MAX_OPT_ARGS];
        int                     dsunit = 0;
        int                     dswidth = 0;
        int                     iosize = 0;
        if (!options)
                goto done;
  
 -      while ((this_char = strsep(&options, ",")) != NULL) {
 -              if (!*this_char)
 +      while ((p = strsep(&options, ",")) != NULL) {
 +              int             token;
 +
 +              if (!*p)
                        continue;
 -              if ((value = strchr(this_char, '=')) != NULL)
 -                      *value++ = 0;
  
 -              if (!strcmp(this_char, MNTOPT_LOGBUFS)) {
 -                      if (!value || !*value) {
 -                              xfs_warn(mp, "%s option requires an argument",
 -                                      this_char);
 -                              return -EINVAL;
 -                      }
 -                      if (kstrtoint(value, 10, &mp->m_logbufs))
 -                              return -EINVAL;
 -              } else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) {
 -                      if (!value || !*value) {
 -                              xfs_warn(mp, "%s option requires an argument",
 -                                      this_char);
 -                              return -EINVAL;
 -                      }
 -                      if (suffix_kstrtoint(value, 10, &mp->m_logbsize))
 +              token = match_token(p, tokens, args);
 +              switch (token) {
 +              case Opt_logbufs:
 +                      if (match_int(args, &mp->m_logbufs))
                                return -EINVAL;
 -              } else if (!strcmp(this_char, MNTOPT_LOGDEV)) {
 -                      if (!value || !*value) {
 -                              xfs_warn(mp, "%s option requires an argument",
 -                                      this_char);
 +                      break;
 +              case Opt_logbsize:
 +                      if (suffix_kstrtoint(args, 10, &mp->m_logbsize))
                                return -EINVAL;
 -                      }
 -                      mp->m_logname = kstrndup(value, MAXNAMELEN, GFP_KERNEL);
 +                      break;
 +              case Opt_logdev:
 +                      mp->m_logname = match_strdup(args);
                        if (!mp->m_logname)
                                return -ENOMEM;
 -              } else if (!strcmp(this_char, MNTOPT_MTPT)) {
 -                      xfs_warn(mp, "%s option not allowed on this system",
 -                              this_char);
 +                      break;
 +              case Opt_mtpt:
 +                      xfs_warn(mp, "%s option not allowed on this system", p);
                        return -EINVAL;
 -              } else if (!strcmp(this_char, MNTOPT_RTDEV)) {
 -                      if (!value || !*value) {
 -                              xfs_warn(mp, "%s option requires an argument",
 -                                      this_char);
 -                              return -EINVAL;
 -                      }
 -                      mp->m_rtname = kstrndup(value, MAXNAMELEN, GFP_KERNEL);
 +              case Opt_rtdev:
 +                      mp->m_rtname = match_strdup(args);
                        if (!mp->m_rtname)
                                return -ENOMEM;
 -              } else if (!strcmp(this_char, MNTOPT_ALLOCSIZE) ||
 -                         !strcmp(this_char, MNTOPT_BIOSIZE)) {
 -                      if (!value || !*value) {
 -                              xfs_warn(mp, "%s option requires an argument",
 -                                      this_char);
 -                              return -EINVAL;
 -                      }
 -                      if (suffix_kstrtoint(value, 10, &iosize))
 +                      break;
 +              case Opt_allocsize:
 +              case Opt_biosize:
 +                      if (suffix_kstrtoint(args, 10, &iosize))
                                return -EINVAL;
                        iosizelog = ffs(iosize) - 1;
 -              } else if (!strcmp(this_char, MNTOPT_GRPID) ||
 -                         !strcmp(this_char, MNTOPT_BSDGROUPS)) {
 +                      break;
 +              case Opt_grpid:
 +              case Opt_bsdgroups:
                        mp->m_flags |= XFS_MOUNT_GRPID;
 -              } else if (!strcmp(this_char, MNTOPT_NOGRPID) ||
 -                         !strcmp(this_char, MNTOPT_SYSVGROUPS)) {
 +                      break;
 +              case Opt_nogrpid:
 +              case Opt_sysvgroups:
                        mp->m_flags &= ~XFS_MOUNT_GRPID;
 -              } else if (!strcmp(this_char, MNTOPT_WSYNC)) {
 +                      break;
 +              case Opt_wsync:
                        mp->m_flags |= XFS_MOUNT_WSYNC;
 -              } else if (!strcmp(this_char, MNTOPT_NORECOVERY)) {
 +                      break;
 +              case Opt_norecovery:
                        mp->m_flags |= XFS_MOUNT_NORECOVERY;
 -              } else if (!strcmp(this_char, MNTOPT_NOALIGN)) {
 +                      break;
 +              case Opt_noalign:
                        mp->m_flags |= XFS_MOUNT_NOALIGN;
 -              } else if (!strcmp(this_char, MNTOPT_SWALLOC)) {
 +                      break;
 +              case Opt_swalloc:
                        mp->m_flags |= XFS_MOUNT_SWALLOC;
 -              } else if (!strcmp(this_char, MNTOPT_SUNIT)) {
 -                      if (!value || !*value) {
 -                              xfs_warn(mp, "%s option requires an argument",
 -                                      this_char);
 -                              return -EINVAL;
 -                      }
 -                      if (kstrtoint(value, 10, &dsunit))
 -                              return -EINVAL;
 -              } else if (!strcmp(this_char, MNTOPT_SWIDTH)) {
 -                      if (!value || !*value) {
 -                              xfs_warn(mp, "%s option requires an argument",
 -                                      this_char);
 +                      break;
 +              case Opt_sunit:
 +                      if (match_int(args, &dsunit))
                                return -EINVAL;
 -                      }
 -                      if (kstrtoint(value, 10, &dswidth))
 +                      break;
 +              case Opt_swidth:
 +                      if (match_int(args, &dswidth))
                                return -EINVAL;
 -              } else if (!strcmp(this_char, MNTOPT_32BITINODE)) {
 +                      break;
 +              case Opt_inode32:
                        mp->m_flags |= XFS_MOUNT_SMALL_INUMS;
 -              } else if (!strcmp(this_char, MNTOPT_64BITINODE)) {
 +                      break;
 +              case Opt_inode64:
                        mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS;
 -              } else if (!strcmp(this_char, MNTOPT_NOUUID)) {
 +                      break;
 +              case Opt_nouuid:
                        mp->m_flags |= XFS_MOUNT_NOUUID;
 -              } else if (!strcmp(this_char, MNTOPT_BARRIER)) {
 +                      break;
 +              case Opt_barrier:
                        mp->m_flags |= XFS_MOUNT_BARRIER;
 -              } else if (!strcmp(this_char, MNTOPT_NOBARRIER)) {
 +                      break;
 +              case Opt_nobarrier:
                        mp->m_flags &= ~XFS_MOUNT_BARRIER;
 -              } else if (!strcmp(this_char, MNTOPT_IKEEP)) {
 +                      break;
 +              case Opt_ikeep:
                        mp->m_flags |= XFS_MOUNT_IKEEP;
 -              } else if (!strcmp(this_char, MNTOPT_NOIKEEP)) {
 +                      break;
 +              case Opt_noikeep:
                        mp->m_flags &= ~XFS_MOUNT_IKEEP;
 -              } else if (!strcmp(this_char, MNTOPT_LARGEIO)) {
 +                      break;
 +              case Opt_largeio:
                        mp->m_flags &= ~XFS_MOUNT_COMPAT_IOSIZE;
 -              } else if (!strcmp(this_char, MNTOPT_NOLARGEIO)) {
 +                      break;
 +              case Opt_nolargeio:
                        mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE;
 -              } else if (!strcmp(this_char, MNTOPT_ATTR2)) {
 +                      break;
 +              case Opt_attr2:
                        mp->m_flags |= XFS_MOUNT_ATTR2;
 -              } else if (!strcmp(this_char, MNTOPT_NOATTR2)) {
 +                      break;
 +              case Opt_noattr2:
                        mp->m_flags &= ~XFS_MOUNT_ATTR2;
                        mp->m_flags |= XFS_MOUNT_NOATTR2;
 -              } else if (!strcmp(this_char, MNTOPT_FILESTREAM)) {
 +                      break;
 +              case Opt_filestreams:
                        mp->m_flags |= XFS_MOUNT_FILESTREAMS;
 -              } else if (!strcmp(this_char, MNTOPT_NOQUOTA)) {
 +                      break;
 +              case Opt_noquota:
                        mp->m_qflags &= ~XFS_ALL_QUOTA_ACCT;
                        mp->m_qflags &= ~XFS_ALL_QUOTA_ENFD;
                        mp->m_qflags &= ~XFS_ALL_QUOTA_ACTIVE;
 -              } else if (!strcmp(this_char, MNTOPT_QUOTA) ||
 -                         !strcmp(this_char, MNTOPT_UQUOTA) ||
 -                         !strcmp(this_char, MNTOPT_USRQUOTA)) {
 +                      break;
 +              case Opt_quota:
 +              case Opt_uquota:
 +              case Opt_usrquota:
                        mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE |
                                         XFS_UQUOTA_ENFD);
 -              } else if (!strcmp(this_char, MNTOPT_QUOTANOENF) ||
 -                         !strcmp(this_char, MNTOPT_UQUOTANOENF)) {
 +                      break;
 +              case Opt_qnoenforce:
 +              case Opt_uqnoenforce:
                        mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE);
                        mp->m_qflags &= ~XFS_UQUOTA_ENFD;
 -              } else if (!strcmp(this_char, MNTOPT_PQUOTA) ||
 -                         !strcmp(this_char, MNTOPT_PRJQUOTA)) {
 +                      break;
 +              case Opt_pquota:
 +              case Opt_prjquota:
                        mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE |
                                         XFS_PQUOTA_ENFD);
 -              } else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) {
 +                      break;
 +              case Opt_pqnoenforce:
                        mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE);
                        mp->m_qflags &= ~XFS_PQUOTA_ENFD;
 -              } else if (!strcmp(this_char, MNTOPT_GQUOTA) ||
 -                         !strcmp(this_char, MNTOPT_GRPQUOTA)) {
 +              case Opt_gquota:
 +              case Opt_grpquota:
                        mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE |
                                         XFS_GQUOTA_ENFD);
 -              } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
 +                      break;
 +              case Opt_gqnoenforce:
                        mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
                        mp->m_qflags &= ~XFS_GQUOTA_ENFD;
 -              } else if (!strcmp(this_char, MNTOPT_DISCARD)) {
 +                      break;
 +              case Opt_discard:
                        mp->m_flags |= XFS_MOUNT_DISCARD;
 -              } else if (!strcmp(this_char, MNTOPT_NODISCARD)) {
 +                      break;
 +              case Opt_nodiscard:
                        mp->m_flags &= ~XFS_MOUNT_DISCARD;
 +                      break;
  #ifdef CONFIG_FS_DAX
 -              } else if (!strcmp(this_char, MNTOPT_DAX)) {
 +              case Opt_dax:
                        mp->m_flags |= XFS_MOUNT_DAX;
 +                      break;
  #endif
 -              } else {
 -                      xfs_warn(mp, "unknown mount option [%s].", this_char);
 +              default:
 +                      xfs_warn(mp, "unknown mount option [%s].", p);
                        return -EINVAL;
                }
        }
@@@ -469,25 -462,25 +470,25 @@@ xfs_showargs
  {
        static struct proc_xfs_info xfs_info_set[] = {
                /* the few simple ones we can get from the mount struct */
 -              { XFS_MOUNT_IKEEP,              "," MNTOPT_IKEEP },
 -              { XFS_MOUNT_WSYNC,              "," MNTOPT_WSYNC },
 -              { XFS_MOUNT_NOALIGN,            "," MNTOPT_NOALIGN },
 -              { XFS_MOUNT_SWALLOC,            "," MNTOPT_SWALLOC },
 -              { XFS_MOUNT_NOUUID,             "," MNTOPT_NOUUID },
 -              { XFS_MOUNT_NORECOVERY,         "," MNTOPT_NORECOVERY },
 -              { XFS_MOUNT_ATTR2,              "," MNTOPT_ATTR2 },
 -              { XFS_MOUNT_FILESTREAMS,        "," MNTOPT_FILESTREAM },
 -              { XFS_MOUNT_GRPID,              "," MNTOPT_GRPID },
 -              { XFS_MOUNT_DISCARD,            "," MNTOPT_DISCARD },
 -              { XFS_MOUNT_SMALL_INUMS,        "," MNTOPT_32BITINODE },
 -              { XFS_MOUNT_DAX,                "," MNTOPT_DAX },
 +              { XFS_MOUNT_IKEEP,              ",ikeep" },
 +              { XFS_MOUNT_WSYNC,              ",wsync" },
 +              { XFS_MOUNT_NOALIGN,            ",noalign" },
 +              { XFS_MOUNT_SWALLOC,            ",swalloc" },
 +              { XFS_MOUNT_NOUUID,             ",nouuid" },
 +              { XFS_MOUNT_NORECOVERY,         ",norecovery" },
 +              { XFS_MOUNT_ATTR2,              ",attr2" },
 +              { XFS_MOUNT_FILESTREAMS,        ",filestreams" },
 +              { XFS_MOUNT_GRPID,              ",grpid" },
 +              { XFS_MOUNT_DISCARD,            ",discard" },
 +              { XFS_MOUNT_SMALL_INUMS,        ",inode32" },
 +              { XFS_MOUNT_DAX,                ",dax" },
                { 0, NULL }
        };
        static struct proc_xfs_info xfs_info_unset[] = {
                /* the few simple ones we can get from the mount struct */
 -              { XFS_MOUNT_COMPAT_IOSIZE,      "," MNTOPT_LARGEIO },
 -              { XFS_MOUNT_BARRIER,            "," MNTOPT_NOBARRIER },
 -              { XFS_MOUNT_SMALL_INUMS,        "," MNTOPT_64BITINODE },
 +              { XFS_MOUNT_COMPAT_IOSIZE,      ",largeio" },
 +              { XFS_MOUNT_BARRIER,            ",nobarrier" },
 +              { XFS_MOUNT_SMALL_INUMS,        ",inode64" },
                { 0, NULL }
        };
        struct proc_xfs_info    *xfs_infop;
        }
  
        if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)
 -              seq_printf(m, "," MNTOPT_ALLOCSIZE "=%dk",
 +              seq_printf(m, ",allocsize=%dk",
                                (int)(1 << mp->m_writeio_log) >> 10);
  
        if (mp->m_logbufs > 0)
 -              seq_printf(m, "," MNTOPT_LOGBUFS "=%d", mp->m_logbufs);
 +              seq_printf(m, ",logbufs=%d", mp->m_logbufs);
        if (mp->m_logbsize > 0)
 -              seq_printf(m, "," MNTOPT_LOGBSIZE "=%dk", mp->m_logbsize >> 10);
 +              seq_printf(m, ",logbsize=%dk", mp->m_logbsize >> 10);
  
        if (mp->m_logname)
 -              seq_show_option(m, MNTOPT_LOGDEV, mp->m_logname);
 +              seq_show_option(m, "logdev", mp->m_logname);
        if (mp->m_rtname)
 -              seq_show_option(m, MNTOPT_RTDEV, mp->m_rtname);
 +              seq_show_option(m, "rtdev", mp->m_rtname);
  
        if (mp->m_dalign > 0)
 -              seq_printf(m, "," MNTOPT_SUNIT "=%d",
 +              seq_printf(m, ",sunit=%d",
                                (int)XFS_FSB_TO_BB(mp, mp->m_dalign));
        if (mp->m_swidth > 0)
 -              seq_printf(m, "," MNTOPT_SWIDTH "=%d",
 +              seq_printf(m, ",swidth=%d",
                                (int)XFS_FSB_TO_BB(mp, mp->m_swidth));
  
        if (mp->m_qflags & (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD))
 -              seq_puts(m, "," MNTOPT_USRQUOTA);
 +              seq_puts(m, ",usrquota");
        else if (mp->m_qflags & XFS_UQUOTA_ACCT)
 -              seq_puts(m, "," MNTOPT_UQUOTANOENF);
 +              seq_puts(m, ",uqnoenforce");
  
        if (mp->m_qflags & XFS_PQUOTA_ACCT) {
                if (mp->m_qflags & XFS_PQUOTA_ENFD)
 -                      seq_puts(m, "," MNTOPT_PRJQUOTA);
 +                      seq_puts(m, ",prjquota");
                else
 -                      seq_puts(m, "," MNTOPT_PQUOTANOENF);
 +                      seq_puts(m, ",pqnoenforce");
        }
        if (mp->m_qflags & XFS_GQUOTA_ACCT) {
                if (mp->m_qflags & XFS_GQUOTA_ENFD)
 -                      seq_puts(m, "," MNTOPT_GRPQUOTA);
 +                      seq_puts(m, ",grpquota");
                else
 -                      seq_puts(m, "," MNTOPT_GQUOTANOENF);
 +                      seq_puts(m, ",gqnoenforce");
        }
  
        if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT))
 -              seq_puts(m, "," MNTOPT_NOQUOTA);
 +              seq_puts(m, ",noquota");
  
        return 0;
  }
@@@ -580,35 -573,23 +581,35 @@@ xfs_max_file_offset
  }
  
  /*
 - * xfs_set_inode32() and xfs_set_inode64() are passed an agcount
 - * because in the growfs case, mp->m_sb.sb_agcount is not updated
 - * yet to the potentially higher ag count.
 + * Set parameters for inode allocation heuristics, taking into account
 + * filesystem size and inode32/inode64 mount options; i.e. specifically
 + * whether or not XFS_MOUNT_SMALL_INUMS is set.
 + *
 + * Inode allocation patterns are altered only if inode32 is requested
 + * (XFS_MOUNT_SMALL_INUMS), and the filesystem is sufficiently large.
 + * If altered, XFS_MOUNT_32BITINODES is set as well.
 + *
 + * An agcount independent of that in the mount structure is provided
 + * because in the growfs case, mp->m_sb.sb_agcount is not yet updated
 + * to the potentially higher ag count.
 + *
 + * Returns the maximum AG index which may contain inodes.
   */
  xfs_agnumber_t
 -xfs_set_inode32(struct xfs_mount *mp, xfs_agnumber_t agcount)
 +xfs_set_inode_alloc(
 +      struct xfs_mount *mp,
 +      xfs_agnumber_t  agcount)
  {
 -      xfs_agnumber_t  index = 0;
 +      xfs_agnumber_t  index;
        xfs_agnumber_t  maxagi = 0;
        xfs_sb_t        *sbp = &mp->m_sb;
        xfs_agnumber_t  max_metadata;
        xfs_agino_t     agino;
        xfs_ino_t       ino;
 -      xfs_perag_t     *pag;
  
 -      /* Calculate how much should be reserved for inodes to meet
 -       * the max inode percentage.
 +      /*
 +       * Calculate how much should be reserved for inodes to meet
 +       * the max inode percentage.  Used only for inode32.
         */
        if (mp->m_maxicount) {
                __uint64_t      icount;
                max_metadata = agcount;
        }
  
 +      /* Get the last possible inode in the filesystem */
        agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0);
 +      ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino);
 +
 +      /*
 +       * If user asked for no more than 32-bit inodes, and the fs is
 +       * sufficiently large, set XFS_MOUNT_32BITINODES if we must alter
 +       * the allocator to accommodate the request.
 +       */
 +      if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > XFS_MAXINUMBER_32)
 +              mp->m_flags |= XFS_MOUNT_32BITINODES;
 +      else
 +              mp->m_flags &= ~XFS_MOUNT_32BITINODES;
  
        for (index = 0; index < agcount; index++) {
 -              ino = XFS_AGINO_TO_INO(mp, index, agino);
 +              struct xfs_perag        *pag;
  
 -              if (ino > XFS_MAXINUMBER_32) {
 -                      pag = xfs_perag_get(mp, index);
 -                      pag->pagi_inodeok = 0;
 -                      pag->pagf_metadata = 0;
 -                      xfs_perag_put(pag);
 -                      continue;
 -              }
 +              ino = XFS_AGINO_TO_INO(mp, index, agino);
  
                pag = xfs_perag_get(mp, index);
 -              pag->pagi_inodeok = 1;
 -              maxagi++;
 -              if (index < max_metadata)
 -                      pag->pagf_metadata = 1;
 -              xfs_perag_put(pag);
 -      }
 -      mp->m_flags |= (XFS_MOUNT_32BITINODES |
 -                      XFS_MOUNT_SMALL_INUMS);
 -
 -      return maxagi;
 -}
  
 -xfs_agnumber_t
 -xfs_set_inode64(struct xfs_mount *mp, xfs_agnumber_t agcount)
 -{
 -      xfs_agnumber_t index = 0;
 -
 -      for (index = 0; index < agcount; index++) {
 -              struct xfs_perag        *pag;
 +              if (mp->m_flags & XFS_MOUNT_32BITINODES) {
 +                      if (ino > XFS_MAXINUMBER_32) {
 +                              pag->pagi_inodeok = 0;
 +                              pag->pagf_metadata = 0;
 +                      } else {
 +                              pag->pagi_inodeok = 1;
 +                              maxagi++;
 +                              if (index < max_metadata)
 +                                      pag->pagf_metadata = 1;
 +                              else
 +                                      pag->pagf_metadata = 0;
 +                      }
 +              } else {
 +                      pag->pagi_inodeok = 1;
 +                      pag->pagf_metadata = 0;
 +              }
  
 -              pag = xfs_perag_get(mp, index);
 -              pag->pagi_inodeok = 1;
 -              pag->pagf_metadata = 0;
                xfs_perag_put(pag);
        }
  
 -      /* There is no need for lock protection on m_flags,
 -       * the rw_semaphore of the VFS superblock is locked
 -       * during mount/umount/remount operations, so this is
 -       * enough to avoid concurency on the m_flags field
 -       */
 -      mp->m_flags &= ~(XFS_MOUNT_32BITINODES |
 -                       XFS_MOUNT_SMALL_INUMS);
 -      return index;
 +      return (mp->m_flags & XFS_MOUNT_32BITINODES) ? maxagi : agcount;
  }
  
  STATIC int
@@@ -1179,27 -1166,6 +1180,27 @@@ xfs_quiesce_attr
        xfs_log_quiesce(mp);
  }
  
 +STATIC int
 +xfs_test_remount_options(
 +      struct super_block      *sb,
 +      struct xfs_mount        *mp,
 +      char                    *options)
 +{
 +      int                     error = 0;
 +      struct xfs_mount        *tmp_mp;
 +
 +      tmp_mp = kmem_zalloc(sizeof(*tmp_mp), KM_MAYFAIL);
 +      if (!tmp_mp)
 +              return -ENOMEM;
 +
 +      tmp_mp->m_super = sb;
 +      error = xfs_parseargs(tmp_mp, options);
 +      xfs_free_fsname(tmp_mp);
 +      kfree(tmp_mp);
 +
 +      return error;
 +}
 +
  STATIC int
  xfs_fs_remount(
        struct super_block      *sb,
        char                    *p;
        int                     error;
  
 +      /* First, check for complete junk; i.e. invalid options */
 +      error = xfs_test_remount_options(sb, mp, options);
 +      if (error)
 +              return error;
 +
        sync_filesystem(sb);
        while ((p = strsep(&options, ",")) != NULL) {
                int token;
                        mp->m_flags &= ~XFS_MOUNT_BARRIER;
                        break;
                case Opt_inode64:
 -                      mp->m_maxagi = xfs_set_inode64(mp, sbp->sb_agcount);
 +                      mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS;
 +                      mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount);
                        break;
                case Opt_inode32:
 -                      mp->m_maxagi = xfs_set_inode32(mp, sbp->sb_agcount);
 +                      mp->m_flags |= XFS_MOUNT_SMALL_INUMS;
 +                      mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount);
                        break;
                default:
                        /*
@@@ -1386,8 -1345,9 +1387,8 @@@ xfs_finish_flags
         */
        if (xfs_sb_version_hascrc(&mp->m_sb) &&
            (mp->m_flags & XFS_MOUNT_NOATTR2)) {
 -              xfs_warn(mp,
 -"Cannot mount a V5 filesystem as %s. %s is always enabled for V5 filesystems.",
 -                      MNTOPT_NOATTR2, MNTOPT_ATTR2);
 +              xfs_warn(mp, "Cannot mount a V5 filesystem as noattr2. "
 +                           "attr2 is always enabled for V5 filesystems.");
                return -EINVAL;
        }
  
@@@ -1858,6 -1818,8 +1859,8 @@@ init_xfs_fs(void
  {
        int                     error;
  
+       xfs_check_ondisk_structs();
        printk(KERN_INFO XFS_VERSION_STRING " with "
                         XFS_BUILD_OPTIONS " enabled\n");
  
This page took 0.113939 seconds and 4 git commands to generate.