500-ubifs-Handle-re-linking-of-inodes-correctly-while-re.patch 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. From: Richard Weinberger <[email protected]>
  2. Date: Wed, 7 Nov 2018 23:04:43 +0100
  3. Subject: [PATCH] ubifs: Handle re-linking of inodes correctly while recovery
  4. MIME-Version: 1.0
  5. Content-Type: text/plain; charset=UTF-8
  6. Content-Transfer-Encoding: 8bit
  7. UBIFS's recovery code strictly assumes that a deleted inode will never
  8. come back, therefore it removes all data which belongs to that inode
  9. as soon it faces an inode with link count 0 in the replay list.
  10. Before O_TMPFILE this assumption was perfectly fine. With O_TMPFILE
  11. it can lead to data loss upon a power-cut.
  12. Consider a journal with entries like:
  13. 0: inode X (nlink = 0) /* O_TMPFILE was created */
  14. 1: data for inode X /* Someone writes to the temp file */
  15. 2: inode X (nlink = 0) /* inode was changed, xattr, chmod, … */
  16. 3: inode X (nlink = 1) /* inode was re-linked via linkat() */
  17. Upon replay of entry #2 UBIFS will drop all data that belongs to inode X,
  18. this will lead to an empty file after mounting.
  19. As solution for this problem, scan the replay list for a re-link entry
  20. before dropping data.
  21. Fixes: 474b93704f32 ("ubifs: Implement O_TMPFILE")
  22. Cc: [email protected]
  23. Cc: Russell Senior <[email protected]>
  24. Cc: Rafał Miłecki <[email protected]>
  25. Reported-by: Russell Senior <[email protected]>
  26. Reported-by: Rafał Miłecki <[email protected]>
  27. Signed-off-by: Richard Weinberger <[email protected]>
  28. ---
  29. fs/ubifs/replay.c | 37 +++++++++++++++++++++++++++++++++++++
  30. 1 file changed, 37 insertions(+)
  31. --- a/fs/ubifs/replay.c
  32. +++ b/fs/ubifs/replay.c
  33. @@ -210,6 +210,38 @@ static int trun_remove_range(struct ubif
  34. }
  35. /**
  36. + * inode_still_linked - check whether inode in question will be re-linked.
  37. + * @c: UBIFS file-system description object
  38. + * @rino: replay entry to test
  39. + *
  40. + * O_TMPFILE files can be re-linked, this means link count goes from 0 to 1.
  41. + * This case needs special care, otherwise all references to the inode will
  42. + * be removed upon the first replay entry of an inode with link count 0
  43. + * is found.
  44. + */
  45. +static bool inode_still_linked(struct ubifs_info *c, struct replay_entry *rino)
  46. +{
  47. + struct replay_entry *r;
  48. +
  49. + ubifs_assert(rino->deletion);
  50. + ubifs_assert(key_type(c, &rino->key) == UBIFS_INO_KEY);
  51. +
  52. + /*
  53. + * Find the most recent entry for the inode behind @rino and check
  54. + * whether it is a deletion.
  55. + */
  56. + list_for_each_entry_reverse(r, &c->replay_list, list) {
  57. + ubifs_assert(r->sqnum >= rino->sqnum);
  58. + if (key_inum(c, &r->key) == key_inum(c, &rino->key))
  59. + return r->deletion == 0;
  60. +
  61. + }
  62. +
  63. + ubifs_assert(0);
  64. + return false;
  65. +}
  66. +
  67. +/**
  68. * apply_replay_entry - apply a replay entry to the TNC.
  69. * @c: UBIFS file-system description object
  70. * @r: replay entry to apply
  71. @@ -239,6 +271,11 @@ static int apply_replay_entry(struct ubi
  72. {
  73. ino_t inum = key_inum(c, &r->key);
  74. + if (inode_still_linked(c, r)) {
  75. + err = 0;
  76. + break;
  77. + }
  78. +
  79. err = ubifs_tnc_remove_ino(c, inum);
  80. break;
  81. }