Skip to content

Commit 801cc4e

Browse files
Brian Fosterdchinner
authored andcommitted
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 <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: Dave Chinner <[email protected]>
1 parent 36f90b0 commit 801cc4e

File tree

3 files changed

+101
-11
lines changed

3 files changed

+101
-11
lines changed

fs/xfs/xfs_aops.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1752,6 +1752,7 @@ xfs_vm_write_failed(
17521752
loff_t from = pos & (PAGE_CACHE_SIZE - 1);
17531753
loff_t to = from + len;
17541754
struct buffer_head *bh, *head;
1755+
struct xfs_mount *mp = XFS_I(inode)->i_mount;
17551756

17561757
/*
17571758
* The request pos offset might be 32 or 64 bit, this is all fine
@@ -1786,7 +1787,8 @@ xfs_vm_write_failed(
17861787
if (!buffer_delay(bh))
17871788
continue;
17881789

1789-
if (!buffer_new(bh) && block_offset < i_size_read(inode))
1790+
if (!xfs_mp_fail_writes(mp) && !buffer_new(bh) &&
1791+
block_offset < i_size_read(inode))
17901792
continue;
17911793

17921794
xfs_vm_kill_delalloc_range(inode, block_offset,
@@ -1824,6 +1826,7 @@ xfs_vm_write_begin(
18241826
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
18251827
struct page *page;
18261828
int status;
1829+
struct xfs_mount *mp = XFS_I(mapping->host)->i_mount;
18271830

18281831
ASSERT(len <= PAGE_CACHE_SIZE);
18291832

@@ -1832,6 +1835,8 @@ xfs_vm_write_begin(
18321835
return -ENOMEM;
18331836

18341837
status = __block_write_begin(page, pos, len, xfs_get_blocks);
1838+
if (xfs_mp_fail_writes(mp))
1839+
status = -EIO;
18351840
if (unlikely(status)) {
18361841
struct inode *inode = mapping->host;
18371842
size_t isize = i_size_read(inode);
@@ -1844,6 +1849,8 @@ xfs_vm_write_begin(
18441849
* allocated in this write, not blocks that were previously
18451850
* written successfully.
18461851
*/
1852+
if (xfs_mp_fail_writes(mp))
1853+
isize = 0;
18471854
if (pos + len > isize) {
18481855
ssize_t start = max_t(ssize_t, pos, isize);
18491856

fs/xfs/xfs_mount.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,17 @@ typedef struct xfs_mount {
147147
* to various other kinds of pain inflicted on the pNFS server.
148148
*/
149149
__uint32_t m_generation;
150+
151+
#ifdef DEBUG
152+
/*
153+
* DEBUG mode instrumentation to test and/or trigger delayed allocation
154+
* block killing in the event of failed writes. When enabled, all
155+
* buffered writes are forced to fail. All delalloc blocks in the range
156+
* of the write (including pre-existing delalloc blocks!) are tossed as
157+
* part of the write failure error handling sequence.
158+
*/
159+
bool m_fail_writes;
160+
#endif
150161
} xfs_mount_t;
151162

152163
/*
@@ -264,6 +275,20 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d)
264275
return (xfs_agblock_t) do_div(ld, mp->m_sb.sb_agblocks);
265276
}
266277

278+
#ifdef DEBUG
279+
static inline bool
280+
xfs_mp_fail_writes(struct xfs_mount *mp)
281+
{
282+
return mp->m_fail_writes;
283+
}
284+
#else
285+
static inline bool
286+
xfs_mp_fail_writes(struct xfs_mount *mp)
287+
{
288+
return 0;
289+
}
290+
#endif
291+
267292
/*
268293
* Per-ag incore structure, copies of information in agf and agi, to improve the
269294
* performance of allocation group selection.

fs/xfs/xfs_sysfs.c

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@
1818

1919
#include "xfs.h"
2020
#include "xfs_sysfs.h"
21+
#include "xfs_format.h"
2122
#include "xfs_log_format.h"
23+
#include "xfs_trans_resv.h"
2224
#include "xfs_log.h"
2325
#include "xfs_log_priv.h"
2426
#include "xfs_stats.h"
27+
#include "xfs_mount.h"
2528

2629
struct xfs_sysfs_attr {
2730
struct attribute attr;
@@ -45,16 +48,6 @@ to_attr(struct attribute *attr)
4548

4649
#define ATTR_LIST(name) &xfs_sysfs_attr_##name.attr
4750

48-
/*
49-
* xfs_mount kobject. This currently has no attributes and thus no need for show
50-
* and store helpers. The mp kobject serves as the per-mount parent object that
51-
* is identified by the fsname under sysfs.
52-
*/
53-
54-
struct kobj_type xfs_mp_ktype = {
55-
.release = xfs_sysfs_release,
56-
};
57-
5851
STATIC ssize_t
5952
xfs_sysfs_object_show(
6053
struct kobject *kobject,
@@ -83,6 +76,71 @@ static const struct sysfs_ops xfs_sysfs_ops = {
8376
.store = xfs_sysfs_object_store,
8477
};
8578

79+
/*
80+
* xfs_mount kobject. The mp kobject also serves as the per-mount parent object
81+
* that is identified by the fsname under sysfs.
82+
*/
83+
84+
static inline struct xfs_mount *
85+
to_mp(struct kobject *kobject)
86+
{
87+
struct xfs_kobj *kobj = to_kobj(kobject);
88+
89+
return container_of(kobj, struct xfs_mount, m_kobj);
90+
}
91+
92+
#ifdef DEBUG
93+
94+
STATIC ssize_t
95+
fail_writes_store(
96+
struct kobject *kobject,
97+
const char *buf,
98+
size_t count)
99+
{
100+
struct xfs_mount *mp = to_mp(kobject);
101+
int ret;
102+
int val;
103+
104+
ret = kstrtoint(buf, 0, &val);
105+
if (ret)
106+
return ret;
107+
108+
if (val == 1)
109+
mp->m_fail_writes = true;
110+
else if (val == 0)
111+
mp->m_fail_writes = false;
112+
else
113+
return -EINVAL;
114+
115+
return count;
116+
}
117+
118+
STATIC ssize_t
119+
fail_writes_show(
120+
struct kobject *kobject,
121+
char *buf)
122+
{
123+
struct xfs_mount *mp = to_mp(kobject);
124+
125+
return snprintf(buf, PAGE_SIZE, "%d\n", mp->m_fail_writes ? 1 : 0);
126+
}
127+
XFS_SYSFS_ATTR_RW(fail_writes);
128+
129+
#endif /* DEBUG */
130+
131+
static struct attribute *xfs_mp_attrs[] = {
132+
#ifdef DEBUG
133+
ATTR_LIST(fail_writes),
134+
#endif
135+
NULL,
136+
};
137+
138+
struct kobj_type xfs_mp_ktype = {
139+
.release = xfs_sysfs_release,
140+
.sysfs_ops = &xfs_sysfs_ops,
141+
.default_attrs = xfs_mp_attrs,
142+
};
143+
86144
#ifdef DEBUG
87145
/* debug */
88146

0 commit comments

Comments
 (0)