From de0b85a8cf24f8c535b7f719c454e3951298d17a Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Mon, 8 Feb 2016 14:58:07 +1100 Subject: xfs: remove unused function definitions Old leftovers. Signed-off-by: Eric Sandeen Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/xfs_mount.h | 1 - 1 file changed, 1 deletion(-) (limited to 'fs/xfs/xfs_mount.h') diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index b57098481c10..a4e03ab50342 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -327,7 +327,6 @@ extern int xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta, bool reserved); extern int xfs_mod_frextents(struct xfs_mount *mp, int64_t delta); -extern int xfs_mount_log_sb(xfs_mount_t *); extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int); extern int xfs_readsb(xfs_mount_t *, int); extern void xfs_freesb(xfs_mount_t *); -- cgit v1.2.3 From 12c3f05c7b592ae3bf2219392f1cbf252645cd79 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Wed, 2 Mar 2016 09:58:09 +1100 Subject: 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 Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_mount.c | 20 +---------- fs/xfs/xfs_mount.h | 5 ++- fs/xfs/xfs_super.c | 102 +++++++++++++++++++++++++++++------------------------ fs/xfs/xfs_super.h | 4 +-- 4 files changed, 60 insertions(+), 71 deletions(-) (limited to 'fs/xfs/xfs_mount.h') 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( xfs_agnumber_t index; xfs_agnumber_t first_initialised = 0; xfs_perag_t *pag; - xfs_agino_t agino; - xfs_ino_t ino; - xfs_sb_t *sbp = &mp->m_sb; int error = -ENOMEM; /* @@ -230,22 +227,7 @@ xfs_initialize_perag( radix_tree_preload_end(); } - /* - * If we mount with the inode64 option, or no inode overflows - * the legacy 32-bit address space clear the inode32 option. - */ - agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); - ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); - - 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; - - if (mp->m_flags & XFS_MOUNT_32BITINODES) - index = xfs_set_inode32(mp, agcount); - else - index = xfs_set_inode64(mp, agcount); + index = xfs_set_inode_alloc(mp, agcount); if (maxagi) *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 { #define XFS_MOUNT_GRPID (1ULL << 9) /* group-ID assigned from directory */ #define XFS_MOUNT_NORECOVERY (1ULL << 10) /* no recovery - dirty fs */ #define XFS_MOUNT_DFLT_IOSIZE (1ULL << 12) /* set default i/o size */ -#define XFS_MOUNT_32BITINODES (1ULL << 14) /* do not create inodes above - * 32 bits in size */ -#define XFS_MOUNT_SMALL_INUMS (1ULL << 15) /* users wants 32bit inodes */ +#define XFS_MOUNT_SMALL_INUMS (1ULL << 14) /* user wants 32bit inodes */ +#define XFS_MOUNT_32BITINODES (1ULL << 15) /* inode32 allocator active */ #define XFS_MOUNT_NOUUID (1ULL << 16) /* ignore uuid during mount */ #define XFS_MOUNT_BARRIER (1ULL << 17) #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( } /* - * 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; @@ -610,54 +622,48 @@ xfs_set_inode32(struct xfs_mount *mp, xfs_agnumber_t agcount) 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 @@ -1227,10 +1233,12 @@ xfs_fs_remount( 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: /* 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); extern void xfs_flush_inodes(struct xfs_mount *mp); extern void xfs_blkdev_issue_flush(struct xfs_buftarg *); -extern xfs_agnumber_t xfs_set_inode32(struct xfs_mount *, xfs_agnumber_t agcount); -extern xfs_agnumber_t xfs_set_inode64(struct xfs_mount *, xfs_agnumber_t agcount); +extern xfs_agnumber_t xfs_set_inode_alloc(struct xfs_mount *, + xfs_agnumber_t agcount); extern const struct export_operations xfs_export_operations; extern const struct xattr_handler *xfs_xattr_handlers[]; -- cgit v1.2.3 From 801cc4e17a34c32e1527827292fac9cec5d3393b Mon Sep 17 00:00:00 2001 From: Brian Foster Date: Tue, 15 Mar 2016 11:42:44 +1100 Subject: xfs: debug mode forced buffered write failure Add a DEBUG mode-only sysfs knob to enable forced buffered write failure. An additional side effect of this mode is brute force killing of delayed allocation blocks in the range of the write. The latter is the prime motiviation behind this patch, as userspace test infrastructure requires a reliable mechanism to create and split delalloc extents without causing extent conversion. Certain fallocate operations (i.e., zero range) were used for this in the past, but the implementations have changed such that delalloc extents are flushed and converted to real blocks, rendering the test useless. Signed-off-by: Brian Foster Reviewed-by: Christoph Hellwig Signed-off-by: Dave Chinner --- fs/xfs/xfs_aops.c | 9 ++++++- fs/xfs/xfs_mount.h | 25 +++++++++++++++++ fs/xfs/xfs_sysfs.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 101 insertions(+), 11 deletions(-) (limited to 'fs/xfs/xfs_mount.h') diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 379c089fb051..eed0bfc4443c 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -1752,6 +1752,7 @@ xfs_vm_write_failed( loff_t from = pos & (PAGE_CACHE_SIZE - 1); loff_t to = from + len; struct buffer_head *bh, *head; + struct xfs_mount *mp = XFS_I(inode)->i_mount; /* * The request pos offset might be 32 or 64 bit, this is all fine @@ -1786,7 +1787,8 @@ xfs_vm_write_failed( if (!buffer_delay(bh)) continue; - if (!buffer_new(bh) && block_offset < i_size_read(inode)) + if (!xfs_mp_fail_writes(mp) && !buffer_new(bh) && + block_offset < i_size_read(inode)) continue; xfs_vm_kill_delalloc_range(inode, block_offset, @@ -1824,6 +1826,7 @@ xfs_vm_write_begin( pgoff_t index = pos >> PAGE_CACHE_SHIFT; struct page *page; int status; + struct xfs_mount *mp = XFS_I(mapping->host)->i_mount; ASSERT(len <= PAGE_CACHE_SIZE); @@ -1832,6 +1835,8 @@ xfs_vm_write_begin( return -ENOMEM; status = __block_write_begin(page, pos, len, xfs_get_blocks); + if (xfs_mp_fail_writes(mp)) + status = -EIO; if (unlikely(status)) { struct inode *inode = mapping->host; size_t isize = i_size_read(inode); @@ -1844,6 +1849,8 @@ xfs_vm_write_begin( * allocated in this write, not blocks that were previously * written successfully. */ + if (xfs_mp_fail_writes(mp)) + isize = 0; if (pos + len > isize) { ssize_t start = max_t(ssize_t, pos, isize); diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index b57098481c10..546cf46a97ce 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -147,6 +147,17 @@ typedef struct xfs_mount { * to various other kinds of pain inflicted on the pNFS server. */ __uint32_t m_generation; + +#ifdef DEBUG + /* + * DEBUG mode instrumentation to test and/or trigger delayed allocation + * block killing in the event of failed writes. When enabled, all + * buffered writes are forced to fail. All delalloc blocks in the range + * of the write (including pre-existing delalloc blocks!) are tossed as + * part of the write failure error handling sequence. + */ + bool m_fail_writes; +#endif } xfs_mount_t; /* @@ -264,6 +275,20 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d) return (xfs_agblock_t) do_div(ld, mp->m_sb.sb_agblocks); } +#ifdef DEBUG +static inline bool +xfs_mp_fail_writes(struct xfs_mount *mp) +{ + return mp->m_fail_writes; +} +#else +static inline bool +xfs_mp_fail_writes(struct xfs_mount *mp) +{ + return 0; +} +#endif + /* * Per-ag incore structure, copies of information in agf and agi, to improve the * performance of allocation group selection. diff --git a/fs/xfs/xfs_sysfs.c b/fs/xfs/xfs_sysfs.c index 641d625eb334..6ced4f143494 100644 --- a/fs/xfs/xfs_sysfs.c +++ b/fs/xfs/xfs_sysfs.c @@ -18,10 +18,13 @@ #include "xfs.h" #include "xfs_sysfs.h" +#include "xfs_format.h" #include "xfs_log_format.h" +#include "xfs_trans_resv.h" #include "xfs_log.h" #include "xfs_log_priv.h" #include "xfs_stats.h" +#include "xfs_mount.h" struct xfs_sysfs_attr { struct attribute attr; @@ -45,16 +48,6 @@ to_attr(struct attribute *attr) #define ATTR_LIST(name) &xfs_sysfs_attr_##name.attr -/* - * xfs_mount kobject. This currently has no attributes and thus no need for show - * and store helpers. The mp kobject serves as the per-mount parent object that - * is identified by the fsname under sysfs. - */ - -struct kobj_type xfs_mp_ktype = { - .release = xfs_sysfs_release, -}; - STATIC ssize_t xfs_sysfs_object_show( struct kobject *kobject, @@ -83,6 +76,71 @@ static const struct sysfs_ops xfs_sysfs_ops = { .store = xfs_sysfs_object_store, }; +/* + * xfs_mount kobject. The mp kobject also serves as the per-mount parent object + * that is identified by the fsname under sysfs. + */ + +static inline struct xfs_mount * +to_mp(struct kobject *kobject) +{ + struct xfs_kobj *kobj = to_kobj(kobject); + + return container_of(kobj, struct xfs_mount, m_kobj); +} + +#ifdef DEBUG + +STATIC ssize_t +fail_writes_store( + struct kobject *kobject, + const char *buf, + size_t count) +{ + struct xfs_mount *mp = to_mp(kobject); + int ret; + int val; + + ret = kstrtoint(buf, 0, &val); + if (ret) + return ret; + + if (val == 1) + mp->m_fail_writes = true; + else if (val == 0) + mp->m_fail_writes = false; + else + return -EINVAL; + + return count; +} + +STATIC ssize_t +fail_writes_show( + struct kobject *kobject, + char *buf) +{ + struct xfs_mount *mp = to_mp(kobject); + + return snprintf(buf, PAGE_SIZE, "%d\n", mp->m_fail_writes ? 1 : 0); +} +XFS_SYSFS_ATTR_RW(fail_writes); + +#endif /* DEBUG */ + +static struct attribute *xfs_mp_attrs[] = { +#ifdef DEBUG + ATTR_LIST(fail_writes), +#endif + NULL, +}; + +struct kobj_type xfs_mp_ktype = { + .release = xfs_sysfs_release, + .sysfs_ops = &xfs_sysfs_ops, + .default_attrs = xfs_mp_attrs, +}; + #ifdef DEBUG /* debug */ -- cgit v1.2.3