recovery_test.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /*
  2. * Copyright (C) 2014 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless requied by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. /*
  18. * These file system recovery tests ensure the ability to recover from
  19. * filesystem crashes in key blocks (e.g. superblock).
  20. */
  21. #include <assert.h>
  22. #include <errno.h>
  23. #include <fcntl.h>
  24. #include <fs_mgr.h>
  25. #include <gtest/gtest.h>
  26. #include <logwrap/logwrap.h>
  27. #include <sys/types.h>
  28. #include <unistd.h>
  29. #include <string>
  30. #include "cutils/properties.h"
  31. #include <ext4_utils/ext4.h>
  32. #include <ext4_utils/ext4_utils.h>
  33. #define LOG_TAG "fsRecoveryTest"
  34. #include <utils/Log.h>
  35. #include <testUtil.h>
  36. #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
  37. #define SB_OFFSET 1024
  38. static char UMOUNT_BIN[] = "/system/bin/umount";
  39. static char VDC_BIN[] = "/system/bin/vdc";
  40. enum Fs_Type { FS_UNKNOWN, FS_EXT4, FS_F2FS };
  41. namespace android {
  42. class DataFileVerifier {
  43. public:
  44. explicit DataFileVerifier(const char* file_name) {
  45. strncpy(test_file_, file_name, FILENAME_MAX);
  46. }
  47. void verify_write() {
  48. int write_fd = open(test_file_, O_CREAT | O_WRONLY, 0666);
  49. ASSERT_TRUE(write_fd);
  50. ASSERT_EQ(write(write_fd, "TEST", 4), 4);
  51. close(write_fd);
  52. }
  53. void verify_read() {
  54. char read_buff[4];
  55. int read_fd = open(test_file_, O_RDONLY);
  56. ASSERT_TRUE(read_fd);
  57. ASSERT_EQ(read(read_fd, read_buff, sizeof(read_buff)), 4);
  58. ASSERT_FALSE(strncmp(read_buff, "TEST", 4));
  59. close(read_fd);
  60. }
  61. ~DataFileVerifier() {
  62. unlink(test_file_);
  63. }
  64. private:
  65. char test_file_[FILENAME_MAX];
  66. };
  67. namespace ext4 {
  68. bool getSuperBlock(const int blk_fd, struct ext4_super_block* sb) {
  69. if (lseek(blk_fd, SB_OFFSET, SEEK_SET) == -1) {
  70. testPrintE("Cannot lseek to ext4 superblock to read");
  71. return false;
  72. }
  73. if (read(blk_fd, sb, sizeof(*sb)) != sizeof(*sb)) {
  74. testPrintE("Cannot read ext4 superblock");
  75. return false;
  76. }
  77. if (sb->s_magic != 0xEF53) {
  78. testPrintE("Invalid ext4 superblock magic");
  79. return false;
  80. }
  81. return true;
  82. }
  83. bool setSbErrorBit(const int blk_fd) {
  84. // Read super block.
  85. struct ext4_super_block sb;
  86. if (!getSuperBlock(blk_fd, &sb)) {
  87. return false;
  88. }
  89. // Check that the detected errors bit is not set.
  90. if (sb.s_state & 0x2) {
  91. testPrintE("Ext4 superblock already corrupted");
  92. return false;
  93. }
  94. // Set the detected errors bit.
  95. sb.s_state |= 0x2;
  96. // Write superblock.
  97. if (lseek(blk_fd, SB_OFFSET, SEEK_SET) == -1) {
  98. testPrintE("Cannot lseek to superblock to write\n");
  99. return false;
  100. }
  101. if (write(blk_fd, &sb, sizeof(sb)) != sizeof(sb)) {
  102. testPrintE("Cannot write superblock\n");
  103. return false;
  104. }
  105. return true;
  106. }
  107. bool corruptGdtFreeBlock(const int blk_fd) {
  108. // Read super block.
  109. struct ext4_super_block sb;
  110. if (!getSuperBlock(blk_fd, &sb)) {
  111. return false;
  112. }
  113. // Make sure the block size is 2K or 4K.
  114. if ((sb.s_log_block_size != 1) && (sb.s_log_block_size != 2)) {
  115. testPrintE("Ext4 block size not 2K or 4K\n");
  116. return false;
  117. }
  118. int block_size = 1 << (10 + sb.s_log_block_size);
  119. int num_bgs = DIV_ROUND_UP(sb.s_blocks_count_lo, sb.s_blocks_per_group);
  120. if (sb.s_desc_size != sizeof(struct ext2_group_desc)) {
  121. testPrintE("Can't handle ext4 block group descriptor size of %d",
  122. sb.s_desc_size);
  123. return false;
  124. }
  125. // Read first block group descriptor, decrement free block count, and
  126. // write it back out.
  127. if (lseek(blk_fd, block_size, SEEK_SET) == -1) {
  128. testPrintE("Cannot lseek to ext4 block group descriptor table to read");
  129. return false;
  130. }
  131. // Read in block group descriptors till we read one that has at least one free
  132. // block.
  133. struct ext2_group_desc gd;
  134. for (int i = 0; i < num_bgs; i++) {
  135. if (read(blk_fd, &gd, sizeof(gd)) != sizeof(gd)) {
  136. testPrintE("Cannot read ext4 group descriptor %d", i);
  137. return false;
  138. }
  139. if (gd.bg_free_blocks_count) {
  140. break;
  141. }
  142. }
  143. gd.bg_free_blocks_count--;
  144. if (lseek(blk_fd, -sizeof(gd), SEEK_CUR) == -1) {
  145. testPrintE("Cannot lseek to ext4 block group descriptor table to write");
  146. return false;
  147. }
  148. if (write(blk_fd, &gd, sizeof(gd)) != sizeof(gd)) {
  149. testPrintE("Cannot write modified ext4 group descriptor");
  150. return false;
  151. }
  152. return true;
  153. }
  154. } // namespace ext4
  155. class FsRecoveryTest : public ::testing::Test {
  156. protected:
  157. FsRecoveryTest() : fs_type(FS_UNKNOWN), blk_fd_(-1) {}
  158. bool setCacheInfoFromFstab() {
  159. fs_type = FS_UNKNOWN;
  160. android::fs_mgr::Fstab fstab;
  161. if (!android::fs_mgr::ReadDefaultFstab(&fstab)) {
  162. testPrintE("failed to open default fstab\n");
  163. } else {
  164. // Loop through entries looking for cache.
  165. for (const auto& entry : fstab) {
  166. if (entry.mount_point == "/cache") {
  167. blk_path_ = entry.blk_device;
  168. if (entry.fs_type == "ext4") {
  169. fs_type = FS_EXT4;
  170. break;
  171. } else if (entry.fs_type == "f2fs") {
  172. fs_type = FS_F2FS;
  173. break;
  174. }
  175. }
  176. }
  177. }
  178. return fs_type != FS_UNKNOWN;
  179. }
  180. bool unmountCache() {
  181. char cache_str[] = "/cache";
  182. char *umount_argv[] = {
  183. UMOUNT_BIN,
  184. cache_str,
  185. };
  186. return android_fork_execvp_ext(ARRAY_SIZE(umount_argv), umount_argv,
  187. NULL, true, LOG_KLOG, false, NULL,
  188. NULL, 0) >= 0;
  189. }
  190. bool mountAll() {
  191. char storage_str[] = "storage";
  192. char mountall_str[] = "mountall";
  193. char *mountall_argv[] = {
  194. VDC_BIN,
  195. storage_str,
  196. mountall_str,
  197. };
  198. return android_fork_execvp_ext(ARRAY_SIZE(mountall_argv), mountall_argv,
  199. NULL, true, LOG_KLOG, false, NULL,
  200. NULL, 0) >= 0;
  201. }
  202. int getCacheBlkFd() {
  203. if (blk_fd_ == -1) {
  204. blk_fd_ = open(blk_path_.c_str(), O_RDWR);
  205. }
  206. return blk_fd_;
  207. }
  208. void closeCacheBlkFd() {
  209. if (blk_fd_ > -1) {
  210. close(blk_fd_);
  211. }
  212. blk_fd_ = -1;
  213. }
  214. void assertCacheHealthy() {
  215. const char* test_file = "/cache/FsRecoveryTestGarbage.txt";
  216. DataFileVerifier file_verify(test_file);
  217. file_verify.verify_write();
  218. file_verify.verify_read();
  219. }
  220. virtual void SetUp() {
  221. assertCacheHealthy();
  222. ASSERT_TRUE(setCacheInfoFromFstab());
  223. }
  224. virtual void TearDown() {
  225. // Ensure /cache partition is accessible, mounted and healthy for other
  226. // tests.
  227. closeCacheBlkFd();
  228. ASSERT_TRUE(mountAll());
  229. assertCacheHealthy();
  230. }
  231. Fs_Type fs_type;
  232. private:
  233. std::string blk_path_;
  234. int blk_fd_;
  235. };
  236. TEST_F(FsRecoveryTest, EXT4_CorruptGdt) {
  237. if (fs_type != FS_EXT4) {
  238. return;
  239. }
  240. // Setup test file in /cache.
  241. const char* test_file = "/cache/CorruptGdtGarbage.txt";
  242. DataFileVerifier file_verify(test_file);
  243. file_verify.verify_write();
  244. // Unmount and corrupt /cache gdt.
  245. ASSERT_TRUE(unmountCache());
  246. ASSERT_TRUE(ext4::corruptGdtFreeBlock(getCacheBlkFd()));
  247. closeCacheBlkFd();
  248. ASSERT_TRUE(mountAll());
  249. // Verify results.
  250. file_verify.verify_read();
  251. }
  252. TEST_F(FsRecoveryTest, EXT4_SetErrorBit) {
  253. if (fs_type != FS_EXT4) {
  254. return;
  255. }
  256. // Setup test file in /cache.
  257. const char* test_file = "/cache/ErrorBitGarbagetxt";
  258. DataFileVerifier file_verify(test_file);
  259. file_verify.verify_write();
  260. // Unmount and set /cache super block error bit.
  261. ASSERT_TRUE(unmountCache());
  262. ASSERT_TRUE(ext4::setSbErrorBit(getCacheBlkFd()));
  263. closeCacheBlkFd();
  264. ASSERT_TRUE(mountAll());
  265. // Verify results.
  266. file_verify.verify_read();
  267. struct ext4_super_block sb;
  268. ASSERT_TRUE(ext4::getSuperBlock(getCacheBlkFd(), &sb));
  269. // Verify e2fsck has recovered the error bit of sb.
  270. ASSERT_FALSE(sb.s_state & 0x2);
  271. }
  272. } // namespace android