diff options
author | Adam Thomas <adamthomas1111@gmail.com> | 2013-02-02 17:32:31 -0500 |
---|---|---|
committer | Artem Bityutskiy <artem.bityutskiy@linux.intel.com> | 2013-02-04 05:31:00 -0500 |
commit | 2928f0d0c5ebd6c9605c0d98207a44376387c298 (patch) | |
tree | e15d676a7c9f493853c0fbbab1ed2e71cf5fc0c6 | |
parent | 3d251a5b9e2f09edcf25bbffe1fa308d0f648bf1 (diff) |
UBIFS: fix use of freed ubifs_orphan objects
The last orphan in the cnext list has its cnext set to NULL. Because
of that, ubifs_delete_orphan assumes that it is not on the cnext list
and frees it immediately instead of adding it to the dnext list. The
freed orphan is later modified by write_orph_node.
This can cause various inconsistencies including directory entries
that cannot be removed and this error:
UBIFS error (pid 20685): layout_cnodes: LPT out of space at LEB 14:129009 needing 17, done_ltab 1, done_lsave 1
This is a regression introduced by
"7074e5eb UBIFS: remove invalid reference to list iterator variable".
This change adds an explicit flag to ubifs_orphan indicating whether
it is pending commit.
Signed-off-by: Adam Thomas <adamthomas1111@gmail.com>
Reviewed-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: stable@vger.kernel.org # v3.6+
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
-rw-r--r-- | fs/ubifs/orphan.c | 7 | ||||
-rw-r--r-- | fs/ubifs/ubifs.h | 4 |
2 files changed, 9 insertions, 2 deletions
diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c index 769701ccb5c9..8534d9c6492f 100644 --- a/fs/ubifs/orphan.c +++ b/fs/ubifs/orphan.c | |||
@@ -132,7 +132,7 @@ void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum) | |||
132 | (unsigned long)inum); | 132 | (unsigned long)inum); |
133 | return; | 133 | return; |
134 | } | 134 | } |
135 | if (o->cnext) { | 135 | if (o->cmt) { |
136 | o->dnext = c->orph_dnext; | 136 | o->dnext = c->orph_dnext; |
137 | c->orph_dnext = o; | 137 | c->orph_dnext = o; |
138 | spin_unlock(&c->orphan_lock); | 138 | spin_unlock(&c->orphan_lock); |
@@ -172,7 +172,9 @@ int ubifs_orphan_start_commit(struct ubifs_info *c) | |||
172 | last = &c->orph_cnext; | 172 | last = &c->orph_cnext; |
173 | list_for_each_entry(orphan, &c->orph_new, new_list) { | 173 | list_for_each_entry(orphan, &c->orph_new, new_list) { |
174 | ubifs_assert(orphan->new); | 174 | ubifs_assert(orphan->new); |
175 | ubifs_assert(!orphan->cmt); | ||
175 | orphan->new = 0; | 176 | orphan->new = 0; |
177 | orphan->cmt = 1; | ||
176 | *last = orphan; | 178 | *last = orphan; |
177 | last = &orphan->cnext; | 179 | last = &orphan->cnext; |
178 | } | 180 | } |
@@ -299,7 +301,9 @@ static int write_orph_node(struct ubifs_info *c, int atomic) | |||
299 | cnext = c->orph_cnext; | 301 | cnext = c->orph_cnext; |
300 | for (i = 0; i < cnt; i++) { | 302 | for (i = 0; i < cnt; i++) { |
301 | orphan = cnext; | 303 | orphan = cnext; |
304 | ubifs_assert(orphan->cmt); | ||
302 | orph->inos[i] = cpu_to_le64(orphan->inum); | 305 | orph->inos[i] = cpu_to_le64(orphan->inum); |
306 | orphan->cmt = 0; | ||
303 | cnext = orphan->cnext; | 307 | cnext = orphan->cnext; |
304 | orphan->cnext = NULL; | 308 | orphan->cnext = NULL; |
305 | } | 309 | } |
@@ -378,6 +382,7 @@ static int consolidate(struct ubifs_info *c) | |||
378 | list_for_each_entry(orphan, &c->orph_list, list) { | 382 | list_for_each_entry(orphan, &c->orph_list, list) { |
379 | if (orphan->new) | 383 | if (orphan->new) |
380 | continue; | 384 | continue; |
385 | orphan->cmt = 1; | ||
381 | *last = orphan; | 386 | *last = orphan; |
382 | last = &orphan->cnext; | 387 | last = &orphan->cnext; |
383 | cnt += 1; | 388 | cnt += 1; |
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index d133c276fe05..c16fff7271d3 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h | |||
@@ -904,6 +904,7 @@ struct ubifs_budget_req { | |||
904 | * @dnext: next orphan to delete | 904 | * @dnext: next orphan to delete |
905 | * @inum: inode number | 905 | * @inum: inode number |
906 | * @new: %1 => added since the last commit, otherwise %0 | 906 | * @new: %1 => added since the last commit, otherwise %0 |
907 | * @cmt: %1 => commit pending, otherwise %0 | ||
907 | */ | 908 | */ |
908 | struct ubifs_orphan { | 909 | struct ubifs_orphan { |
909 | struct rb_node rb; | 910 | struct rb_node rb; |
@@ -912,7 +913,8 @@ struct ubifs_orphan { | |||
912 | struct ubifs_orphan *cnext; | 913 | struct ubifs_orphan *cnext; |
913 | struct ubifs_orphan *dnext; | 914 | struct ubifs_orphan *dnext; |
914 | ino_t inum; | 915 | ino_t inum; |
915 | int new; | 916 | unsigned new:1; |
917 | unsigned cmt:1; | ||
916 | }; | 918 | }; |
917 | 919 | ||
918 | /** | 920 | /** |