1 From: Darrick J. Wong <darrick.wong@oracle.com>
\r
3 When we added a new defer op type for agfl block freeing to the kernel,
\r
4 we forgot to add that type to the userspace side of things. This will
\r
5 cause spontaneous combustion in xfs_repair if we try to rebuild
\r
8 Fixes: d5c1b462232 ("xfs: defer agfl block frees when dfops is available")
\r
9 Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
\r
11 libxfs/defer_item.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
\r
12 1 file changed, 44 insertions(+)
\r
14 diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
\r
15 index b7185c1a..82aa32a8 100644
\r
16 --- a/libxfs/defer_item.c
\r
17 +++ b/libxfs/defer_item.c
\r
18 @@ -118,11 +118,55 @@ static const struct xfs_defer_op_type xfs_extent_free_defer_type = {
\r
19 .cancel_item = xfs_extent_free_cancel_item,
\r
23 + * AGFL blocks are accounted differently in the reserve pools and are not
\r
24 + * inserted into the busy extent list.
\r
27 +xfs_agfl_free_finish_item(
\r
28 + struct xfs_trans *tp,
\r
29 + struct list_head *item,
\r
33 + struct xfs_mount *mp = tp->t_mountp;
\r
34 + struct xfs_extent_free_item *free;
\r
35 + struct xfs_buf *agbp;
\r
37 + xfs_agnumber_t agno;
\r
38 + xfs_agblock_t agbno;
\r
40 + free = container_of(item, struct xfs_extent_free_item, xefi_list);
\r
41 + ASSERT(free->xefi_blockcount == 1);
\r
42 + agno = XFS_FSB_TO_AGNO(mp, free->xefi_startblock);
\r
43 + agbno = XFS_FSB_TO_AGBNO(mp, free->xefi_startblock);
\r
45 + error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
\r
47 + error = xfs_free_agfl_block(tp, agno, agbno, agbp,
\r
48 + &free->xefi_oinfo);
\r
53 +/* sub-type with special handling for AGFL deferred frees */
\r
54 +static const struct xfs_defer_op_type xfs_agfl_free_defer_type = {
\r
55 + .type = XFS_DEFER_OPS_TYPE_AGFL_FREE,
\r
56 + .diff_items = xfs_extent_free_diff_items,
\r
57 + .create_intent = xfs_extent_free_create_intent,
\r
58 + .abort_intent = xfs_extent_free_abort_intent,
\r
59 + .log_item = xfs_extent_free_log_item,
\r
60 + .create_done = xfs_extent_free_create_done,
\r
61 + .finish_item = xfs_agfl_free_finish_item,
\r
62 + .cancel_item = xfs_extent_free_cancel_item,
\r
65 /* Register the deferred op type. */
\r
67 xfs_extent_free_init_defer_op(void)
\r
69 xfs_defer_init_op_type(&xfs_extent_free_defer_type);
\r
70 + xfs_defer_init_op_type(&xfs_agfl_free_defer_type);
\r
73 /* Reverse Mapping */
\r
74 Subject: [PATCH 1/2] xfs_repair: initialize realloced bplist in
\r
75 longform_dir2_entry_check
\r
76 From: Eric Sandeen <sandeen@sandeen.net>
\r
78 If we need to realloc the bplist[] array holding buffers for a given
\r
79 directory, we don't initialize the new slots. This causes a problem
\r
80 if the directory has holes, because those slots never get filled in.
\r
82 At the end of the function we call libxfs_putbuf for every non-null
\r
83 slot, and any uninitialized slots are segfault landmines.
\r
85 Make sure we initialize all new slots to NULL for this reason.
\r
87 Reported-by: Oleg Davydov <burunduk3@gmail.com>
\r
88 Signed-off-by: Eric Sandeen <sandeen@redhat.com>
\r
91 diff --git a/repair/phase6.c b/repair/phase6.c
\r
92 index b87c751..9d24a4f 100644
\r
93 --- a/repair/phase6.c
\r
94 +++ b/repair/phase6.c
\r
95 @@ -2348,6 +2348,8 @@ longform_dir2_entry_check(xfs_mount_t *mp,
\r
97 db = xfs_dir2_da_to_db(mp->m_dir_geo, da_bno);
\r
98 if (db >= num_bps) {
\r
99 + int last_size = num_bps;
\r
101 /* more data blocks than expected */
\r
103 bplist = realloc(bplist, num_bps * sizeof(struct xfs_buf*));
\r
104 @@ -2355,6 +2357,9 @@ longform_dir2_entry_check(xfs_mount_t *mp,
\r
105 do_error(_("realloc failed in %s (%zu bytes)\n"),
\r
107 num_bps * sizeof(struct xfs_buf*));
\r
108 + /* Initialize the new elements */
\r
109 + for (i = last_size; i < num_bps; i++)
\r
110 + bplist[i] = NULL;
\r
115 Subject: [PATCH 2/2] xfs_repair: continue after xfs_bunmapi deadlock avoidance
\r
116 From: Eric Sandeen <sandeen@sandeen.net>
\r
120 15a8bcc xfs: fix multi-AG deadlock in xfs_bunmapi
\r
122 xfs_bunmapi can legitimately return before all work is done.
\r
123 Sadly nobody told xfs_repair, so it fires an assert:
\r
125 phase6.c:1410: longform_dir2_rebuild: Assertion `done' failed.
\r
127 Fix this by calling back in until all work is done, as we do
\r
130 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1641116
\r
131 Reported-by: Tomasz Torcz <tomek@pipebreaker.pl>
\r
132 Signed-off-by: Eric Sandeen <sandeen@redhat.com>
\r
135 diff --git a/repair/phase6.c b/repair/phase6.c
\r
136 index e017326..b87c751 100644
\r
137 --- a/repair/phase6.c
\r
138 +++ b/repair/phase6.c
\r
139 @@ -1317,7 +1317,7 @@ longform_dir2_rebuild(
\r
140 xfs_fileoff_t lastblock;
\r
147 * trash directory completely and rebuild from scratch using the
\r
148 @@ -1352,12 +1352,25 @@ longform_dir2_rebuild(
\r
151 /* free all data, leaf, node and freespace blocks */
\r
152 - error = -libxfs_bunmapi(tp, ip, 0, lastblock, XFS_BMAPI_METADATA, 0,
\r
153 - &firstblock, &dfops, &done);
\r
155 - do_warn(_("xfs_bunmapi failed -- error - %d\n"), error);
\r
156 - goto out_bmap_cancel;
\r
159 + error = -libxfs_bunmapi(tp, ip, 0, lastblock, XFS_BMAPI_METADATA,
\r
160 + 0, &firstblock, &dfops, &done);
\r
162 + do_warn(_("xfs_bunmapi failed -- error - %d\n"), error);
\r
163 + goto out_bmap_cancel;
\r
165 + error = xfs_defer_finish(&tp, &dfops);
\r
167 + do_warn(("defer_finish failed -- error - %d\n"), error);
\r
168 + goto out_bmap_cancel;
\r
171 + * Close out trans and start the next one in the chain.
\r
173 + error = xfs_trans_roll_inode(&tp, ip);
\r
175 + goto out_bmap_cancel;
\r
181 From: "Darrick J. Wong" <darrick.wong@oracle.com>
\r
182 Subject: [PATCH] libxfs: check all defer ops types
\r
184 From: Darrick J. Wong <darrick.wong@oracle.com>
\r
186 Make sure we have all the defer ops types loaded before proceeding.
\r
188 Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
\r
190 libxfs/init.c | 5 +++++
\r
191 libxfs/xfs_defer.c | 12 ++++++++++++
\r
192 libxfs/xfs_defer.h | 1 +
\r
193 3 files changed, 18 insertions(+)
\r
195 diff --git a/libxfs/init.c b/libxfs/init.c
\r
196 index 750b8f20..d1fdc3a8 100644
\r
197 --- a/libxfs/init.c
\r
198 +++ b/libxfs/init.c
\r
199 @@ -253,6 +253,11 @@ libxfs_init(libxfs_init_t *a)
\r
200 xfs_rmap_update_init_defer_op();
\r
201 xfs_refcount_update_init_defer_op();
\r
202 xfs_bmap_update_init_defer_op();
\r
203 + if (!xfs_defer_check_all_present()) {
\r
204 + fprintf(stderr, _("%s: defer ops not all there\n"),
\r
211 diff --git a/libxfs/xfs_defer.c b/libxfs/xfs_defer.c
\r
212 index 5a6da0f3..cd3a8ef3 100644
\r
213 --- a/libxfs/xfs_defer.c
\r
214 +++ b/libxfs/xfs_defer.c
\r
215 @@ -545,3 +545,15 @@ xfs_defer_move(
\r
217 xfs_defer_reset(stp);
\r
220 +/* Make sure we filled out all the defer_ops types. */
\r
222 +xfs_defer_check_all_present(void)
\r
226 + for(x = 0; x < XFS_DEFER_OPS_TYPE_MAX; x++)
\r
227 + if (defer_op_types[x] == NULL)
\r
231 diff --git a/libxfs/xfs_defer.h b/libxfs/xfs_defer.h
\r
232 index 2584a5b9..bc7ae7ff 100644
\r
233 --- a/libxfs/xfs_defer.h
\r
234 +++ b/libxfs/xfs_defer.h
\r
235 @@ -57,5 +57,6 @@ struct xfs_defer_op_type {
\r
238 void xfs_defer_init_op_type(const struct xfs_defer_op_type *type);
\r
239 +bool xfs_defer_check_all_present(void);
\r
241 #endif /* __XFS_DEFER_H__ */
\r