|
|
@@ -209,6 +209,38 @@ static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r)
|
|
|
return ubifs_tnc_remove_range(c, &min_key, &max_key);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * inode_still_linked - check whether inode in question will be re-linked.
|
|
|
+ * @c: UBIFS file-system description object
|
|
|
+ * @rino: replay entry to test
|
|
|
+ *
|
|
|
+ * O_TMPFILE files can be re-linked, this means link count goes from 0 to 1.
|
|
|
+ * This case needs special care, otherwise all references to the inode will
|
|
|
+ * be removed upon the first replay entry of an inode with link count 0
|
|
|
+ * is found.
|
|
|
+ */
|
|
|
+static bool inode_still_linked(struct ubifs_info *c, struct replay_entry *rino)
|
|
|
+{
|
|
|
+ struct replay_entry *r;
|
|
|
+
|
|
|
+ ubifs_assert(c, rino->deletion);
|
|
|
+ ubifs_assert(c, key_type(c, &rino->key) == UBIFS_INO_KEY);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Find the most recent entry for the inode behind @rino and check
|
|
|
+ * whether it is a deletion.
|
|
|
+ */
|
|
|
+ list_for_each_entry_reverse(r, &c->replay_list, list) {
|
|
|
+ ubifs_assert(c, r->sqnum >= rino->sqnum);
|
|
|
+ if (key_inum(c, &r->key) == key_inum(c, &rino->key))
|
|
|
+ return r->deletion == 0;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ ubifs_assert(c, 0);
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* apply_replay_entry - apply a replay entry to the TNC.
|
|
|
* @c: UBIFS file-system description object
|
|
|
@@ -236,6 +268,11 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
|
|
|
{
|
|
|
ino_t inum = key_inum(c, &r->key);
|
|
|
|
|
|
+ if (inode_still_linked(c, r)) {
|
|
|
+ err = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
err = ubifs_tnc_remove_ino(c, inum);
|
|
|
break;
|
|
|
}
|