Skip to content

Commit e9b7a02

Browse files
committed
Merge branch 'xfs-7.0-fixes' into for-next
Signed-off-by: Carlos Maiolino <cem@kernel.org>
2 parents 2c0ff61 + c6c56ff commit e9b7a02

7 files changed

Lines changed: 130 additions & 98 deletions

File tree

fs/xfs/libxfs/xfs_attr_leaf.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,6 +1415,28 @@ xfs_attr3_leaf_create(
14151415
return 0;
14161416
}
14171417

1418+
/*
1419+
* Reinitialize an existing attr fork block as an empty leaf, and attach
1420+
* the buffer to tp.
1421+
*/
1422+
int
1423+
xfs_attr3_leaf_init(
1424+
struct xfs_trans *tp,
1425+
struct xfs_inode *dp,
1426+
xfs_dablk_t blkno)
1427+
{
1428+
struct xfs_buf *bp = NULL;
1429+
struct xfs_da_args args = {
1430+
.trans = tp,
1431+
.dp = dp,
1432+
.owner = dp->i_ino,
1433+
.geo = dp->i_mount->m_attr_geo,
1434+
};
1435+
1436+
ASSERT(tp != NULL);
1437+
1438+
return xfs_attr3_leaf_create(&args, blkno, &bp);
1439+
}
14181440
/*
14191441
* Split the leaf node, rebalance, then add the new entry.
14201442
*

fs/xfs/libxfs/xfs_attr_leaf.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ int xfs_attr3_leaf_list_int(struct xfs_buf *bp,
8787
/*
8888
* Routines used for shrinking the Btree.
8989
*/
90+
91+
int xfs_attr3_leaf_init(struct xfs_trans *tp, struct xfs_inode *dp,
92+
xfs_dablk_t blkno);
9093
int xfs_attr3_leaf_toosmall(struct xfs_da_state *state, int *retval);
9194
void xfs_attr3_leaf_unbalance(struct xfs_da_state *state,
9295
struct xfs_da_state_blk *drop_blk,

fs/xfs/libxfs/xfs_da_btree.c

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,21 +1506,20 @@ xfs_da3_fixhashpath(
15061506
}
15071507

15081508
/*
1509-
* Remove an entry from an intermediate node.
1509+
* Internal implementation to remove an entry from an intermediate node.
15101510
*/
15111511
STATIC void
1512-
xfs_da3_node_remove(
1513-
struct xfs_da_state *state,
1514-
struct xfs_da_state_blk *drop_blk)
1512+
__xfs_da3_node_remove(
1513+
struct xfs_trans *tp,
1514+
struct xfs_inode *dp,
1515+
struct xfs_da_geometry *geo,
1516+
struct xfs_da_state_blk *drop_blk)
15151517
{
15161518
struct xfs_da_intnode *node;
15171519
struct xfs_da3_icnode_hdr nodehdr;
15181520
struct xfs_da_node_entry *btree;
15191521
int index;
15201522
int tmp;
1521-
struct xfs_inode *dp = state->args->dp;
1522-
1523-
trace_xfs_da_node_remove(state->args);
15241523

15251524
node = drop_blk->bp->b_addr;
15261525
xfs_da3_node_hdr_from_disk(dp->i_mount, &nodehdr, node);
@@ -1536,24 +1535,56 @@ xfs_da3_node_remove(
15361535
tmp = nodehdr.count - index - 1;
15371536
tmp *= (uint)sizeof(xfs_da_node_entry_t);
15381537
memmove(&btree[index], &btree[index + 1], tmp);
1539-
xfs_trans_log_buf(state->args->trans, drop_blk->bp,
1538+
xfs_trans_log_buf(tp, drop_blk->bp,
15401539
XFS_DA_LOGRANGE(node, &btree[index], tmp));
15411540
index = nodehdr.count - 1;
15421541
}
15431542
memset(&btree[index], 0, sizeof(xfs_da_node_entry_t));
1544-
xfs_trans_log_buf(state->args->trans, drop_blk->bp,
1543+
xfs_trans_log_buf(tp, drop_blk->bp,
15451544
XFS_DA_LOGRANGE(node, &btree[index], sizeof(btree[index])));
15461545
nodehdr.count -= 1;
15471546
xfs_da3_node_hdr_to_disk(dp->i_mount, node, &nodehdr);
1548-
xfs_trans_log_buf(state->args->trans, drop_blk->bp,
1549-
XFS_DA_LOGRANGE(node, &node->hdr, state->args->geo->node_hdr_size));
1547+
xfs_trans_log_buf(tp, drop_blk->bp,
1548+
XFS_DA_LOGRANGE(node, &node->hdr, geo->node_hdr_size));
15501549

15511550
/*
15521551
* Copy the last hash value from the block to propagate upwards.
15531552
*/
15541553
drop_blk->hashval = be32_to_cpu(btree[index - 1].hashval);
15551554
}
15561555

1556+
/*
1557+
* Remove an entry from an intermediate node.
1558+
*/
1559+
STATIC void
1560+
xfs_da3_node_remove(
1561+
struct xfs_da_state *state,
1562+
struct xfs_da_state_blk *drop_blk)
1563+
{
1564+
trace_xfs_da_node_remove(state->args);
1565+
1566+
__xfs_da3_node_remove(state->args->trans, state->args->dp,
1567+
state->args->geo, drop_blk);
1568+
}
1569+
1570+
/*
1571+
* Remove an entry from an intermediate attr node at the specified index.
1572+
*/
1573+
void
1574+
xfs_attr3_node_entry_remove(
1575+
struct xfs_trans *tp,
1576+
struct xfs_inode *dp,
1577+
struct xfs_buf *bp,
1578+
int index)
1579+
{
1580+
struct xfs_da_state_blk blk = {
1581+
.index = index,
1582+
.bp = bp,
1583+
};
1584+
1585+
__xfs_da3_node_remove(tp, dp, dp->i_mount->m_attr_geo, &blk);
1586+
}
1587+
15571588
/*
15581589
* Unbalance the elements between two intermediate nodes,
15591590
* move all Btree elements from one node into another.

fs/xfs/libxfs/xfs_da_btree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ int xfs_da3_split(xfs_da_state_t *state);
184184
int xfs_da3_join(xfs_da_state_t *state);
185185
void xfs_da3_fixhashpath(struct xfs_da_state *state,
186186
struct xfs_da_state_path *path_to_to_fix);
187+
void xfs_attr3_node_entry_remove(struct xfs_trans *tp, struct xfs_inode *dp,
188+
struct xfs_buf *bp, int index);
187189

188190
/*
189191
* Routines used for finding things in the Btree.

fs/xfs/xfs_attr_inactive.c

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ xfs_attr3_node_inactive(
140140
xfs_daddr_t parent_blkno, child_blkno;
141141
struct xfs_buf *child_bp;
142142
struct xfs_da3_icnode_hdr ichdr;
143-
int error, i;
143+
int error;
144144

145145
/*
146146
* Since this code is recursive (gasp!) we must protect ourselves.
@@ -152,7 +152,7 @@ xfs_attr3_node_inactive(
152152
return -EFSCORRUPTED;
153153
}
154154

155-
xfs_da3_node_hdr_from_disk(dp->i_mount, &ichdr, bp->b_addr);
155+
xfs_da3_node_hdr_from_disk(mp, &ichdr, bp->b_addr);
156156
parent_blkno = xfs_buf_daddr(bp);
157157
if (!ichdr.count) {
158158
xfs_trans_brelse(*trans, bp);
@@ -167,7 +167,7 @@ xfs_attr3_node_inactive(
167167
* over the leaves removing all of them. If this is higher up
168168
* in the tree, recurse downward.
169169
*/
170-
for (i = 0; i < ichdr.count; i++) {
170+
while (ichdr.count > 0) {
171171
/*
172172
* Read the subsidiary block to see what we have to work with.
173173
* Don't do this in a transaction. This is a depth-first
@@ -218,29 +218,32 @@ xfs_attr3_node_inactive(
218218
xfs_trans_binval(*trans, child_bp);
219219
child_bp = NULL;
220220

221+
error = xfs_da3_node_read_mapped(*trans, dp,
222+
parent_blkno, &bp, XFS_ATTR_FORK);
223+
if (error)
224+
return error;
225+
221226
/*
222-
* If we're not done, re-read the parent to get the next
223-
* child block number.
227+
* Remove entry from parent node, prevents being indexed to.
224228
*/
225-
if (i + 1 < ichdr.count) {
226-
struct xfs_da3_icnode_hdr phdr;
229+
xfs_attr3_node_entry_remove(*trans, dp, bp, 0);
230+
231+
xfs_da3_node_hdr_from_disk(mp, &ichdr, bp->b_addr);
232+
bp = NULL;
227233

228-
error = xfs_da3_node_read_mapped(*trans, dp,
229-
parent_blkno, &bp, XFS_ATTR_FORK);
234+
if (ichdr.count > 0) {
235+
/*
236+
* If we're not done, get the next child block number.
237+
*/
238+
child_fsb = be32_to_cpu(ichdr.btree[0].before);
239+
240+
/*
241+
* Atomically commit the whole invalidate stuff.
242+
*/
243+
error = xfs_trans_roll_inode(trans, dp);
230244
if (error)
231245
return error;
232-
xfs_da3_node_hdr_from_disk(dp->i_mount, &phdr,
233-
bp->b_addr);
234-
child_fsb = be32_to_cpu(phdr.btree[i + 1].before);
235-
xfs_trans_brelse(*trans, bp);
236-
bp = NULL;
237246
}
238-
/*
239-
* Atomically commit the whole invalidate stuff.
240-
*/
241-
error = xfs_trans_roll_inode(trans, dp);
242-
if (error)
243-
return error;
244247
}
245248

246249
return 0;
@@ -257,10 +260,8 @@ xfs_attr3_root_inactive(
257260
struct xfs_trans **trans,
258261
struct xfs_inode *dp)
259262
{
260-
struct xfs_mount *mp = dp->i_mount;
261263
struct xfs_da_blkinfo *info;
262264
struct xfs_buf *bp;
263-
xfs_daddr_t blkno;
264265
int error;
265266

266267
/*
@@ -272,7 +273,6 @@ xfs_attr3_root_inactive(
272273
error = xfs_da3_node_read(*trans, dp, 0, &bp, XFS_ATTR_FORK);
273274
if (error)
274275
return error;
275-
blkno = xfs_buf_daddr(bp);
276276

277277
/*
278278
* Invalidate the tree, even if the "tree" is only a single leaf block.
@@ -283,10 +283,26 @@ xfs_attr3_root_inactive(
283283
case cpu_to_be16(XFS_DA_NODE_MAGIC):
284284
case cpu_to_be16(XFS_DA3_NODE_MAGIC):
285285
error = xfs_attr3_node_inactive(trans, dp, bp, 1);
286+
/*
287+
* Empty root node block are not allowed, convert it to leaf.
288+
*/
289+
if (!error)
290+
error = xfs_attr3_leaf_init(*trans, dp, 0);
291+
if (!error)
292+
error = xfs_trans_roll_inode(trans, dp);
286293
break;
287294
case cpu_to_be16(XFS_ATTR_LEAF_MAGIC):
288295
case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
289296
error = xfs_attr3_leaf_inactive(trans, dp, bp);
297+
/*
298+
* Reinit the leaf before truncating extents so that a crash
299+
* mid-truncation leaves an empty leaf rather than one with
300+
* entries that may reference freed remote value blocks.
301+
*/
302+
if (!error)
303+
error = xfs_attr3_leaf_init(*trans, dp, 0);
304+
if (!error)
305+
error = xfs_trans_roll_inode(trans, dp);
290306
break;
291307
default:
292308
xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);
@@ -295,21 +311,6 @@ xfs_attr3_root_inactive(
295311
xfs_trans_brelse(*trans, bp);
296312
break;
297313
}
298-
if (error)
299-
return error;
300-
301-
/*
302-
* Invalidate the incore copy of the root block.
303-
*/
304-
error = xfs_trans_get_buf(*trans, mp->m_ddev_targp, blkno,
305-
XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0, &bp);
306-
if (error)
307-
return error;
308-
xfs_trans_binval(*trans, bp); /* remove from cache */
309-
/*
310-
* Commit the invalidate and start the next transaction.
311-
*/
312-
error = xfs_trans_roll_inode(trans, dp);
313314

314315
return error;
315316
}
@@ -328,6 +329,7 @@ xfs_attr_inactive(
328329
{
329330
struct xfs_trans *trans;
330331
struct xfs_mount *mp;
332+
struct xfs_buf *bp;
331333
int lock_mode = XFS_ILOCK_SHARED;
332334
int error = 0;
333335

@@ -363,10 +365,27 @@ xfs_attr_inactive(
363365
* removal below.
364366
*/
365367
if (dp->i_af.if_nextents > 0) {
368+
/*
369+
* Invalidate and truncate all blocks but leave the root block.
370+
*/
366371
error = xfs_attr3_root_inactive(&trans, dp);
367372
if (error)
368373
goto out_cancel;
369374

375+
error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK,
376+
XFS_FSB_TO_B(mp, mp->m_attr_geo->fsbcount));
377+
if (error)
378+
goto out_cancel;
379+
380+
/*
381+
* Invalidate and truncate the root block and ensure that the
382+
* operation is completed within a single transaction.
383+
*/
384+
error = xfs_da_get_buf(trans, dp, 0, &bp, XFS_ATTR_FORK);
385+
if (error)
386+
goto out_cancel;
387+
388+
xfs_trans_binval(trans, bp);
370389
error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0);
371390
if (error)
372391
goto out_cancel;

fs/xfs/xfs_attr_item.c

Lines changed: 2 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,8 +1047,8 @@ xlog_recover_attri_commit_pass2(
10471047
break;
10481048
case XFS_ATTRI_OP_FLAGS_SET:
10491049
case XFS_ATTRI_OP_FLAGS_REPLACE:
1050-
/* Log item, attr name, attr value */
1051-
if (item->ri_total != 3) {
1050+
/* Log item, attr name, optional attr value */
1051+
if (item->ri_total != 2 + !!attri_formatp->alfi_value_len) {
10521052
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
10531053
attri_formatp, len);
10541054
return -EFSCORRUPTED;
@@ -1132,52 +1132,6 @@ xlog_recover_attri_commit_pass2(
11321132
return -EFSCORRUPTED;
11331133
}
11341134

1135-
switch (op) {
1136-
case XFS_ATTRI_OP_FLAGS_REMOVE:
1137-
/* Regular remove operations operate only on names. */
1138-
if (attr_value != NULL || value_len != 0) {
1139-
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
1140-
attri_formatp, len);
1141-
return -EFSCORRUPTED;
1142-
}
1143-
fallthrough;
1144-
case XFS_ATTRI_OP_FLAGS_PPTR_REMOVE:
1145-
case XFS_ATTRI_OP_FLAGS_PPTR_SET:
1146-
case XFS_ATTRI_OP_FLAGS_SET:
1147-
case XFS_ATTRI_OP_FLAGS_REPLACE:
1148-
/*
1149-
* Regular xattr set/remove/replace operations require a name
1150-
* and do not take a newname. Values are optional for set and
1151-
* replace.
1152-
*
1153-
* Name-value set/remove operations must have a name, do not
1154-
* take a newname, and can take a value.
1155-
*/
1156-
if (attr_name == NULL || name_len == 0) {
1157-
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
1158-
attri_formatp, len);
1159-
return -EFSCORRUPTED;
1160-
}
1161-
break;
1162-
case XFS_ATTRI_OP_FLAGS_PPTR_REPLACE:
1163-
/*
1164-
* Name-value replace operations require the caller to
1165-
* specify the old and new names and values explicitly.
1166-
* Values are optional.
1167-
*/
1168-
if (attr_name == NULL || name_len == 0) {
1169-
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
1170-
attri_formatp, len);
1171-
return -EFSCORRUPTED;
1172-
}
1173-
if (attr_new_name == NULL || new_name_len == 0) {
1174-
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
1175-
attri_formatp, len);
1176-
return -EFSCORRUPTED;
1177-
}
1178-
break;
1179-
}
1180-
11811135
/*
11821136
* Memory alloc failure will cause replay to abort. We attach the
11831137
* name/value buffer to the recovered incore log item and drop our

fs/xfs/xfs_inode.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,8 @@ xfs_itruncate_extents_flags(
10481048
xfs_assert_ilocked(ip, XFS_ILOCK_EXCL);
10491049
if (icount_read(VFS_I(ip)))
10501050
xfs_assert_ilocked(ip, XFS_IOLOCK_EXCL);
1051-
ASSERT(new_size <= XFS_ISIZE(ip));
1051+
if (whichfork == XFS_DATA_FORK)
1052+
ASSERT(new_size <= XFS_ISIZE(ip));
10521053
ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
10531054
ASSERT(ip->i_itemp != NULL);
10541055
ASSERT(ip->i_itemp->ili_lock_flags == 0);

0 commit comments

Comments
 (0)