Skip to content

Commit

Permalink
ubifs: Fix journal replay wrt. xattr nodes
Browse files Browse the repository at this point in the history
When replaying the journal it can happen that a journal entry points to
a garbage collected node.
This is the case when a power-cut occurred between a garbage collect run
and a commit. In such a case nodes have to be read using the failable
read functions to detect whether the found node matches what we expect.

One corner case was forgotten, when the journal contains an entry to
remove an inode all xattrs have to be removed too. UBIFS models xattr
like directory entries, so the TNC code iterates over
all xattrs of the inode and removes them too. This code re-uses the
functions for walking directories and calls ubifs_tnc_next_ent().
ubifs_tnc_next_ent() expects to be used only after the journal and
aborts when a node does not match the expected result. This behavior can
render an UBIFS volume unmountable after a power-cut when xattrs are
used.

Fix this issue by using failable read functions in ubifs_tnc_next_ent()
too when replaying the journal.
Cc: [email protected]
Fixes: 1e51764 ("UBIFS: add new flash file system")
Reported-by: Rock Lee <[email protected]>
Reviewed-by: David Gstir <[email protected]>
Signed-off-by: Richard Weinberger <[email protected]>
  • Loading branch information
richardweinberger committed Jan 17, 2017
1 parent 3d4b2fc commit 1cb51a1
Showing 1 changed file with 23 additions and 2 deletions.
25 changes: 23 additions & 2 deletions fs/ubifs/tnc.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
#include <linux/slab.h>
#include "ubifs.h"

static int try_read_node(const struct ubifs_info *c, void *buf, int type,
int len, int lnum, int offs);
static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_zbranch *zbr, void *node);

/*
* Returned codes of 'matches_name()' and 'fallible_matches_name()' functions.
* @NAME_LESS: name corresponding to the first argument is less than second
Expand Down Expand Up @@ -402,7 +407,19 @@ static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
return 0;
}

err = ubifs_tnc_read_node(c, zbr, node);
if (c->replaying) {
err = fallible_read_node(c, &zbr->key, zbr, node);
/*
* When the node was not found, return -ENOENT, 0 otherwise.
* Negative return codes stay as-is.
*/
if (err == 0)
err = -ENOENT;
else if (err == 1)
err = 0;
} else {
err = ubifs_tnc_read_node(c, zbr, node);
}
if (err)
return err;

Expand Down Expand Up @@ -2857,7 +2874,11 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
if (fname_len(nm) > 0) {
if (err) {
/* Handle collisions */
err = resolve_collision(c, key, &znode, &n, nm);
if (c->replaying)
err = fallible_resolve_collision(c, key, &znode, &n,
nm, 0);
else
err = resolve_collision(c, key, &znode, &n, nm);
dbg_tnc("rc returned %d, znode %p, n %d",
err, znode, n);
if (unlikely(err < 0))
Expand Down

0 comments on commit 1cb51a1

Please sign in to comment.