Storage.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #include "Storage.h"
  2. #include <assert.h>
  3. #include <errno.h>
  4. #include <fcntl.h>
  5. #include <stdio.h>
  6. #include <sys/stat.h>
  7. #include <sys/types.h>
  8. #include <unistd.h>
  9. #include <AP_HAL/AP_HAL.h>
  10. #include <AP_Vehicle/AP_Vehicle_Type.h>
  11. using namespace Linux;
  12. /*
  13. This stores 'eeprom' data on the SD card, with a 4k size, and a
  14. in-memory buffer. This keeps the latency down.
  15. */
  16. // name the storage file after the sketch so you can use the same board
  17. // card for ArduCopter and ArduPlane
  18. #define STORAGE_FILE SKETCHNAME ".stg"
  19. extern const AP_HAL::HAL& hal;
  20. static inline int is_dir(const char *path)
  21. {
  22. struct stat st;
  23. if (stat(path, &st) < 0) {
  24. return -errno;
  25. }
  26. return S_ISDIR(st.st_mode);
  27. }
  28. static int mkdir_p(const char *path, int len, mode_t mode)
  29. {
  30. char *start, *end;
  31. start = strndupa(path, len);
  32. end = start + len;
  33. /*
  34. * scan backwards, replacing '/' with '\0' while the component doesn't
  35. * exist
  36. */
  37. for (;;) {
  38. int r = is_dir(start);
  39. if (r > 0) {
  40. end += strlen(end);
  41. if (end == start + len) {
  42. return 0;
  43. }
  44. /* end != start, since it would be caught on the first
  45. * iteration */
  46. *end = '/';
  47. break;
  48. } else if (r == 0) {
  49. return -ENOTDIR;
  50. }
  51. if (end == start) {
  52. break;
  53. }
  54. *end = '\0';
  55. /* Find the next component, backwards, discarding extra '/'*/
  56. while (end > start && *end != '/') {
  57. end--;
  58. }
  59. while (end > start && *(end - 1) == '/') {
  60. end--;
  61. }
  62. }
  63. while (end < start + len) {
  64. if (mkdir(start, mode) < 0 && errno != EEXIST) {
  65. return -errno;
  66. }
  67. end += strlen(end);
  68. *end = '/';
  69. }
  70. return 0;
  71. }
  72. int Storage::_storage_create(const char *dpath)
  73. {
  74. int dfd = -1;
  75. mkdir_p(dpath, strlen(dpath), 0777);
  76. dfd = open(dpath, O_RDONLY|O_CLOEXEC);
  77. if (dfd == -1) {
  78. fprintf(stderr, "Failed to open storage directory: %s (%m)\n", dpath);
  79. return -1;
  80. }
  81. unlinkat(dfd, dpath, 0);
  82. int fd = openat(dfd, STORAGE_FILE, O_RDWR|O_CREAT|O_CLOEXEC, 0666);
  83. close(dfd);
  84. if (fd == -1) {
  85. fprintf(stderr, "Failed to create storage file %s/%s\n", dpath,
  86. STORAGE_FILE);
  87. goto fail;
  88. }
  89. // take up all needed space
  90. if (ftruncate(fd, sizeof(_buffer)) == -1) {
  91. fprintf(stderr, "Failed to set file size to %lu kB (%m)\n",
  92. sizeof(_buffer) / 1024);
  93. goto fail;
  94. }
  95. // ensure the directory is updated with the new size
  96. fsync(fd);
  97. fsync(dfd);
  98. close(dfd);
  99. return fd;
  100. fail:
  101. close(dfd);
  102. return -1;
  103. }
  104. void Storage::init()
  105. {
  106. const char *dpath;
  107. if (_initialised) {
  108. return;
  109. }
  110. _dirty_mask = 0;
  111. dpath = hal.util->get_custom_storage_directory();
  112. if (!dpath) {
  113. dpath = HAL_BOARD_STORAGE_DIRECTORY;
  114. }
  115. int fd = open(dpath, O_RDWR|O_CLOEXEC);
  116. if (fd == -1) {
  117. fd = _storage_create(dpath);
  118. if (fd == -1) {
  119. AP_HAL::panic("Cannot create storage %s (%m)", dpath);
  120. }
  121. }
  122. ssize_t ret = read(fd, _buffer, sizeof(_buffer));
  123. if (ret != sizeof(_buffer)) {
  124. close(fd);
  125. _storage_create(dpath);
  126. fd = open(dpath, O_RDONLY|O_CLOEXEC);
  127. if (fd == -1) {
  128. AP_HAL::panic("Failed to open %s (%m)", dpath);
  129. }
  130. if (read(fd, _buffer, sizeof(_buffer)) != sizeof(_buffer)) {
  131. AP_HAL::panic("Failed to read %s (%m)", dpath);
  132. }
  133. }
  134. _fd = fd;
  135. _initialised = true;
  136. }
  137. /*
  138. mark some lines as dirty. Note that there is no attempt to avoid
  139. the race condition between this code and the _timer_tick() code
  140. below, which both update _dirty_mask. If we lose the race then the
  141. result is that a line is written more than once, but it won't result
  142. in a line not being written.
  143. */
  144. void Storage::_mark_dirty(uint16_t loc, uint16_t length)
  145. {
  146. uint16_t end = loc + length;
  147. for (uint8_t line=loc>>LINUX_STORAGE_LINE_SHIFT;
  148. line <= end>>LINUX_STORAGE_LINE_SHIFT;
  149. line++) {
  150. _dirty_mask |= 1U << line;
  151. }
  152. }
  153. void Storage::read_block(void *dst, uint16_t loc, size_t n)
  154. {
  155. if (loc >= sizeof(_buffer)-(n-1)) {
  156. return;
  157. }
  158. init();
  159. memcpy(dst, &_buffer[loc], n);
  160. }
  161. void Storage::write_block(uint16_t loc, const void *src, size_t n)
  162. {
  163. if (loc >= sizeof(_buffer)-(n-1)) {
  164. return;
  165. }
  166. if (memcmp(src, &_buffer[loc], n) != 0) {
  167. init();
  168. memcpy(&_buffer[loc], src, n);
  169. _mark_dirty(loc, n);
  170. }
  171. }
  172. void Storage::_timer_tick(void)
  173. {
  174. if (!_initialised || _dirty_mask == 0 || _fd == -1) {
  175. return;
  176. }
  177. // write out the first dirty set of lines. We don't write more
  178. // than one to keep the latency of this call to a minimum
  179. uint8_t i, n;
  180. for (i=0; i<LINUX_STORAGE_NUM_LINES; i++) {
  181. if (_dirty_mask & (1<<i)) {
  182. break;
  183. }
  184. }
  185. if (i == LINUX_STORAGE_NUM_LINES) {
  186. // this shouldn't be possible
  187. return;
  188. }
  189. uint32_t write_mask = (1U<<i);
  190. // see how many lines to write
  191. for (n=1; (i+n) < LINUX_STORAGE_NUM_LINES &&
  192. n < (LINUX_STORAGE_MAX_WRITE>>LINUX_STORAGE_LINE_SHIFT); n++) {
  193. if (!(_dirty_mask & (1<<(n+i)))) {
  194. break;
  195. }
  196. // mark that line clean
  197. write_mask |= (1<<(n+i));
  198. }
  199. /*
  200. write the lines. This also updates _dirty_mask. Note that
  201. because this is a SCHED_FIFO thread it will not be preempted
  202. by the main task except during blocking calls. This means we
  203. don't need a semaphore around the _dirty_mask updates.
  204. */
  205. if (lseek(_fd, i<<LINUX_STORAGE_LINE_SHIFT, SEEK_SET) == (i<<LINUX_STORAGE_LINE_SHIFT)) {
  206. _dirty_mask &= ~write_mask;
  207. if (write(_fd, &_buffer[i<<LINUX_STORAGE_LINE_SHIFT], n<<LINUX_STORAGE_LINE_SHIFT) != n<<LINUX_STORAGE_LINE_SHIFT) {
  208. // write error - likely EINTR
  209. _dirty_mask |= write_mask;
  210. close(_fd);
  211. _fd = -1;
  212. }
  213. if (_dirty_mask == 0) {
  214. if (fsync(_fd) != 0) {
  215. close(_fd);
  216. _fd = -1;
  217. }
  218. }
  219. }
  220. }