aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRichard Weinberger <richard@nod.at>2017-01-10 05:49:40 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-01-26 02:24:40 -0500
commitce5c52f039cf886ac1f2a2535bb4e02ebcefe043 (patch)
treeb962427ad0659841cad1f4e038fb56598a7db6e9 /fs
parentbab10a549fd64e36f06c995d6adf22c0413e9379 (diff)
ubifs: Fix journal replay wrt. xattr nodes
commit 1cb51a15b576ee325d527726afff40947218fd5e upstream. 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. Fixes: 1e51764a3c2ac05a ("UBIFS: add new flash file system") Reported-by: Rock Lee <rockdotlee@gmail.com> Reviewed-by: David Gstir <david@sigma-star.at> Signed-off-by: Richard Weinberger <richard@nod.at> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/ubifs/tnc.c25
1 files changed, 23 insertions, 2 deletions
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index fa9a20cc60d6..fe5e8d4970ae 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -34,6 +34,11 @@
34#include <linux/slab.h> 34#include <linux/slab.h>
35#include "ubifs.h" 35#include "ubifs.h"
36 36
37static int try_read_node(const struct ubifs_info *c, void *buf, int type,
38 int len, int lnum, int offs);
39static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
40 struct ubifs_zbranch *zbr, void *node);
41
37/* 42/*
38 * Returned codes of 'matches_name()' and 'fallible_matches_name()' functions. 43 * Returned codes of 'matches_name()' and 'fallible_matches_name()' functions.
39 * @NAME_LESS: name corresponding to the first argument is less than second 44 * @NAME_LESS: name corresponding to the first argument is less than second
@@ -402,7 +407,19 @@ static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
402 return 0; 407 return 0;
403 } 408 }
404 409
405 err = ubifs_tnc_read_node(c, zbr, node); 410 if (c->replaying) {
411 err = fallible_read_node(c, &zbr->key, zbr, node);
412 /*
413 * When the node was not found, return -ENOENT, 0 otherwise.
414 * Negative return codes stay as-is.
415 */
416 if (err == 0)
417 err = -ENOENT;
418 else if (err == 1)
419 err = 0;
420 } else {
421 err = ubifs_tnc_read_node(c, zbr, node);
422 }
406 if (err) 423 if (err)
407 return err; 424 return err;
408 425
@@ -2766,7 +2783,11 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
2766 if (nm->name) { 2783 if (nm->name) {
2767 if (err) { 2784 if (err) {
2768 /* Handle collisions */ 2785 /* Handle collisions */
2769 err = resolve_collision(c, key, &znode, &n, nm); 2786 if (c->replaying)
2787 err = fallible_resolve_collision(c, key, &znode, &n,
2788 nm, 0);
2789 else
2790 err = resolve_collision(c, key, &znode, &n, nm);
2770 dbg_tnc("rc returned %d, znode %p, n %d", 2791 dbg_tnc("rc returned %d, znode %p, n %d",
2771 err, znode, n); 2792 err, znode, n);
2772 if (unlikely(err < 0)) 2793 if (unlikely(err < 0))