diff options
author | Eric Sandeen <sandeen@redhat.com> | 2016-03-01 17:58:09 -0500 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2016-03-01 17:58:09 -0500 |
commit | 12c3f05c7b592ae3bf2219392f1cbf252645cd79 (patch) | |
tree | 84d13db49ec7de70cee1ae873c3f05e9e89b3fe2 | |
parent | 5d518bd6cec6f921ee1be504094762496afb45fb (diff) |
xfs: fix up inode32/64 (re)mount handling
inode32/inode64 allocator behavior with respect to mount, remount
and growfs is a little tricky.
The inode32 mount option should only enable the inode32 allocator
heuristics if the filesystem is large enough for 64-bit inodes to
exist. Today, it has this behavior on the initial mount, but a
remount with inode32 unconditionally changes the allocation
heuristics, even for a small fs.
Also, an inode32 mounted small filesystem should transition to the
inode32 allocator if the filesystem is subsequently grown to a
sufficient size. Today that does not happen.
This patch consolidates xfs_set_inode32 and xfs_set_inode64 into a
single new function, and moves the "is the maximum inode number big
enough to matter" test into that function, so it doesn't rely on the
caller to get it right - which remount did not do, previously.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r-- | fs/xfs/xfs_mount.c | 20 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.h | 5 | ||||
-rw-r--r-- | fs/xfs/xfs_super.c | 102 | ||||
-rw-r--r-- | fs/xfs/xfs_super.h | 4 |
4 files changed, 60 insertions, 71 deletions
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index bb753b359bee..a773ef33f559 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -185,9 +185,6 @@ xfs_initialize_perag( | |||
185 | xfs_agnumber_t index; | 185 | xfs_agnumber_t index; |
186 | xfs_agnumber_t first_initialised = 0; | 186 | xfs_agnumber_t first_initialised = 0; |
187 | xfs_perag_t *pag; | 187 | xfs_perag_t *pag; |
188 | xfs_agino_t agino; | ||
189 | xfs_ino_t ino; | ||
190 | xfs_sb_t *sbp = &mp->m_sb; | ||
191 | int error = -ENOMEM; | 188 | int error = -ENOMEM; |
192 | 189 | ||
193 | /* | 190 | /* |
@@ -230,22 +227,7 @@ xfs_initialize_perag( | |||
230 | radix_tree_preload_end(); | 227 | radix_tree_preload_end(); |
231 | } | 228 | } |
232 | 229 | ||
233 | /* | 230 | index = xfs_set_inode_alloc(mp, agcount); |
234 | * If we mount with the inode64 option, or no inode overflows | ||
235 | * the legacy 32-bit address space clear the inode32 option. | ||
236 | */ | ||
237 | agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); | ||
238 | ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); | ||
239 | |||
240 | if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > XFS_MAXINUMBER_32) | ||
241 | mp->m_flags |= XFS_MOUNT_32BITINODES; | ||
242 | else | ||
243 | mp->m_flags &= ~XFS_MOUNT_32BITINODES; | ||
244 | |||
245 | if (mp->m_flags & XFS_MOUNT_32BITINODES) | ||
246 | index = xfs_set_inode32(mp, agcount); | ||
247 | else | ||
248 | index = xfs_set_inode64(mp, agcount); | ||
249 | 231 | ||
250 | if (maxagi) | 232 | if (maxagi) |
251 | *maxagi = index; | 233 | *maxagi = index; |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index b57098481c10..af01458def6a 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
@@ -166,9 +166,8 @@ typedef struct xfs_mount { | |||
166 | #define XFS_MOUNT_GRPID (1ULL << 9) /* group-ID assigned from directory */ | 166 | #define XFS_MOUNT_GRPID (1ULL << 9) /* group-ID assigned from directory */ |
167 | #define XFS_MOUNT_NORECOVERY (1ULL << 10) /* no recovery - dirty fs */ | 167 | #define XFS_MOUNT_NORECOVERY (1ULL << 10) /* no recovery - dirty fs */ |
168 | #define XFS_MOUNT_DFLT_IOSIZE (1ULL << 12) /* set default i/o size */ | 168 | #define XFS_MOUNT_DFLT_IOSIZE (1ULL << 12) /* set default i/o size */ |
169 | #define XFS_MOUNT_32BITINODES (1ULL << 14) /* do not create inodes above | 169 | #define XFS_MOUNT_SMALL_INUMS (1ULL << 14) /* user wants 32bit inodes */ |
170 | * 32 bits in size */ | 170 | #define XFS_MOUNT_32BITINODES (1ULL << 15) /* inode32 allocator active */ |
171 | #define XFS_MOUNT_SMALL_INUMS (1ULL << 15) /* users wants 32bit inodes */ | ||
172 | #define XFS_MOUNT_NOUUID (1ULL << 16) /* ignore uuid during mount */ | 171 | #define XFS_MOUNT_NOUUID (1ULL << 16) /* ignore uuid during mount */ |
173 | #define XFS_MOUNT_BARRIER (1ULL << 17) | 172 | #define XFS_MOUNT_BARRIER (1ULL << 17) |
174 | #define XFS_MOUNT_IKEEP (1ULL << 18) /* keep empty inode clusters*/ | 173 | #define XFS_MOUNT_IKEEP (1ULL << 18) /* keep empty inode clusters*/ |
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 8dd7d165902d..d85087bc0c40 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c | |||
@@ -580,23 +580,35 @@ xfs_max_file_offset( | |||
580 | } | 580 | } |
581 | 581 | ||
582 | /* | 582 | /* |
583 | * xfs_set_inode32() and xfs_set_inode64() are passed an agcount | 583 | * Set parameters for inode allocation heuristics, taking into account |
584 | * because in the growfs case, mp->m_sb.sb_agcount is not updated | 584 | * filesystem size and inode32/inode64 mount options; i.e. specifically |
585 | * yet to the potentially higher ag count. | 585 | * whether or not XFS_MOUNT_SMALL_INUMS is set. |
586 | * | ||
587 | * Inode allocation patterns are altered only if inode32 is requested | ||
588 | * (XFS_MOUNT_SMALL_INUMS), and the filesystem is sufficiently large. | ||
589 | * If altered, XFS_MOUNT_32BITINODES is set as well. | ||
590 | * | ||
591 | * An agcount independent of that in the mount structure is provided | ||
592 | * because in the growfs case, mp->m_sb.sb_agcount is not yet updated | ||
593 | * to the potentially higher ag count. | ||
594 | * | ||
595 | * Returns the maximum AG index which may contain inodes. | ||
586 | */ | 596 | */ |
587 | xfs_agnumber_t | 597 | xfs_agnumber_t |
588 | xfs_set_inode32(struct xfs_mount *mp, xfs_agnumber_t agcount) | 598 | xfs_set_inode_alloc( |
599 | struct xfs_mount *mp, | ||
600 | xfs_agnumber_t agcount) | ||
589 | { | 601 | { |
590 | xfs_agnumber_t index = 0; | 602 | xfs_agnumber_t index; |
591 | xfs_agnumber_t maxagi = 0; | 603 | xfs_agnumber_t maxagi = 0; |
592 | xfs_sb_t *sbp = &mp->m_sb; | 604 | xfs_sb_t *sbp = &mp->m_sb; |
593 | xfs_agnumber_t max_metadata; | 605 | xfs_agnumber_t max_metadata; |
594 | xfs_agino_t agino; | 606 | xfs_agino_t agino; |
595 | xfs_ino_t ino; | 607 | xfs_ino_t ino; |
596 | xfs_perag_t *pag; | ||
597 | 608 | ||
598 | /* Calculate how much should be reserved for inodes to meet | 609 | /* |
599 | * the max inode percentage. | 610 | * Calculate how much should be reserved for inodes to meet |
611 | * the max inode percentage. Used only for inode32. | ||
600 | */ | 612 | */ |
601 | if (mp->m_maxicount) { | 613 | if (mp->m_maxicount) { |
602 | __uint64_t icount; | 614 | __uint64_t icount; |
@@ -610,54 +622,48 @@ xfs_set_inode32(struct xfs_mount *mp, xfs_agnumber_t agcount) | |||
610 | max_metadata = agcount; | 622 | max_metadata = agcount; |
611 | } | 623 | } |
612 | 624 | ||
625 | /* Get the last possible inode in the filesystem */ | ||
613 | agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); | 626 | agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); |
627 | ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); | ||
628 | |||
629 | /* | ||
630 | * If user asked for no more than 32-bit inodes, and the fs is | ||
631 | * sufficiently large, set XFS_MOUNT_32BITINODES if we must alter | ||
632 | * the allocator to accommodate the request. | ||
633 | */ | ||
634 | if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > XFS_MAXINUMBER_32) | ||
635 | mp->m_flags |= XFS_MOUNT_32BITINODES; | ||
636 | else | ||
637 | mp->m_flags &= ~XFS_MOUNT_32BITINODES; | ||
614 | 638 | ||
615 | for (index = 0; index < agcount; index++) { | 639 | for (index = 0; index < agcount; index++) { |
616 | ino = XFS_AGINO_TO_INO(mp, index, agino); | 640 | struct xfs_perag *pag; |
617 | 641 | ||
618 | if (ino > XFS_MAXINUMBER_32) { | 642 | ino = XFS_AGINO_TO_INO(mp, index, agino); |
619 | pag = xfs_perag_get(mp, index); | ||
620 | pag->pagi_inodeok = 0; | ||
621 | pag->pagf_metadata = 0; | ||
622 | xfs_perag_put(pag); | ||
623 | continue; | ||
624 | } | ||
625 | 643 | ||
626 | pag = xfs_perag_get(mp, index); | 644 | pag = xfs_perag_get(mp, index); |
627 | pag->pagi_inodeok = 1; | ||
628 | maxagi++; | ||
629 | if (index < max_metadata) | ||
630 | pag->pagf_metadata = 1; | ||
631 | xfs_perag_put(pag); | ||
632 | } | ||
633 | mp->m_flags |= (XFS_MOUNT_32BITINODES | | ||
634 | XFS_MOUNT_SMALL_INUMS); | ||
635 | 645 | ||
636 | return maxagi; | 646 | if (mp->m_flags & XFS_MOUNT_32BITINODES) { |
637 | } | 647 | if (ino > XFS_MAXINUMBER_32) { |
638 | 648 | pag->pagi_inodeok = 0; | |
639 | xfs_agnumber_t | 649 | pag->pagf_metadata = 0; |
640 | xfs_set_inode64(struct xfs_mount *mp, xfs_agnumber_t agcount) | 650 | } else { |
641 | { | 651 | pag->pagi_inodeok = 1; |
642 | xfs_agnumber_t index = 0; | 652 | maxagi++; |
643 | 653 | if (index < max_metadata) | |
644 | for (index = 0; index < agcount; index++) { | 654 | pag->pagf_metadata = 1; |
645 | struct xfs_perag *pag; | 655 | else |
656 | pag->pagf_metadata = 0; | ||
657 | } | ||
658 | } else { | ||
659 | pag->pagi_inodeok = 1; | ||
660 | pag->pagf_metadata = 0; | ||
661 | } | ||
646 | 662 | ||
647 | pag = xfs_perag_get(mp, index); | ||
648 | pag->pagi_inodeok = 1; | ||
649 | pag->pagf_metadata = 0; | ||
650 | xfs_perag_put(pag); | 663 | xfs_perag_put(pag); |
651 | } | 664 | } |
652 | 665 | ||
653 | /* There is no need for lock protection on m_flags, | 666 | return (mp->m_flags & XFS_MOUNT_32BITINODES) ? maxagi : agcount; |
654 | * the rw_semaphore of the VFS superblock is locked | ||
655 | * during mount/umount/remount operations, so this is | ||
656 | * enough to avoid concurency on the m_flags field | ||
657 | */ | ||
658 | mp->m_flags &= ~(XFS_MOUNT_32BITINODES | | ||
659 | XFS_MOUNT_SMALL_INUMS); | ||
660 | return index; | ||
661 | } | 667 | } |
662 | 668 | ||
663 | STATIC int | 669 | STATIC int |
@@ -1227,10 +1233,12 @@ xfs_fs_remount( | |||
1227 | mp->m_flags &= ~XFS_MOUNT_BARRIER; | 1233 | mp->m_flags &= ~XFS_MOUNT_BARRIER; |
1228 | break; | 1234 | break; |
1229 | case Opt_inode64: | 1235 | case Opt_inode64: |
1230 | mp->m_maxagi = xfs_set_inode64(mp, sbp->sb_agcount); | 1236 | mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS; |
1237 | mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount); | ||
1231 | break; | 1238 | break; |
1232 | case Opt_inode32: | 1239 | case Opt_inode32: |
1233 | mp->m_maxagi = xfs_set_inode32(mp, sbp->sb_agcount); | 1240 | mp->m_flags |= XFS_MOUNT_SMALL_INUMS; |
1241 | mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount); | ||
1234 | break; | 1242 | break; |
1235 | default: | 1243 | default: |
1236 | /* | 1244 | /* |
diff --git a/fs/xfs/xfs_super.h b/fs/xfs/xfs_super.h index 499058fea303..2dfb1ce4585f 100644 --- a/fs/xfs/xfs_super.h +++ b/fs/xfs/xfs_super.h | |||
@@ -65,8 +65,8 @@ extern __uint64_t xfs_max_file_offset(unsigned int); | |||
65 | 65 | ||
66 | extern void xfs_flush_inodes(struct xfs_mount *mp); | 66 | extern void xfs_flush_inodes(struct xfs_mount *mp); |
67 | extern void xfs_blkdev_issue_flush(struct xfs_buftarg *); | 67 | extern void xfs_blkdev_issue_flush(struct xfs_buftarg *); |
68 | extern xfs_agnumber_t xfs_set_inode32(struct xfs_mount *, xfs_agnumber_t agcount); | 68 | extern xfs_agnumber_t xfs_set_inode_alloc(struct xfs_mount *, |
69 | extern xfs_agnumber_t xfs_set_inode64(struct xfs_mount *, xfs_agnumber_t agcount); | 69 | xfs_agnumber_t agcount); |
70 | 70 | ||
71 | extern const struct export_operations xfs_export_operations; | 71 | extern const struct export_operations xfs_export_operations; |
72 | extern const struct xattr_handler *xfs_xattr_handlers[]; | 72 | extern const struct xattr_handler *xfs_xattr_handlers[]; |