fs_rammap.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /****************************************************************************
  2. * fs/mmap/fs_rammmap.c
  3. *
  4. * Copyright (C) 2011 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <sys/types.h>
  40. #include <sys/mman.h>
  41. #include <string.h>
  42. #include <unistd.h>
  43. #include <errno.h>
  44. #include <debug.h>
  45. #include <nuttx/kmalloc.h>
  46. #include "inode/inode.h"
  47. #include "fs_rammap.h"
  48. #ifdef CONFIG_FS_RAMMAP
  49. /****************************************************************************
  50. * Public Data
  51. ****************************************************************************/
  52. /* This is the list of all mapped files */
  53. struct fs_allmaps_s g_rammaps;
  54. /****************************************************************************
  55. * Public Functions
  56. ****************************************************************************/
  57. /****************************************************************************
  58. * Name: rammap_initialize
  59. *
  60. * Description:
  61. * Verified that this capability has been initialized.
  62. *
  63. * Input Parameters:
  64. * None
  65. *
  66. * Returned Value:
  67. * None
  68. *
  69. ****************************************************************************/
  70. void rammap_initialize(void)
  71. {
  72. if (!g_rammaps.initialized)
  73. {
  74. sem_init(&g_rammaps.exclsem, 0, 1);
  75. g_rammaps.initialized = true;
  76. }
  77. }
  78. /****************************************************************************
  79. * Name: rammmap
  80. *
  81. * Description:
  82. * Support simulation of memory mapped files by copying files into RAM.
  83. *
  84. * Parameters:
  85. * fd file descriptor of the backing file -- required.
  86. * length The length of the mapping. For exception #1 above, this length
  87. * ignored: The entire underlying media is always accessible.
  88. * offset The offset into the file to map
  89. *
  90. * Returned Value:
  91. * On success, rammmap() returns a pointer to the mapped area. On error, the
  92. * value MAP_FAILED is returned, and errno is set appropriately.
  93. *
  94. * EBADF
  95. * 'fd' is not a valid file descriptor.
  96. * EINVAL
  97. * 'length' or 'offset' are invalid
  98. * ENOMEM
  99. * Insufficient memory is available to map the file.
  100. *
  101. ****************************************************************************/
  102. FAR void *rammap(int fd, size_t length, off_t offset)
  103. {
  104. FAR struct fs_rammap_s *map;
  105. FAR uint8_t *alloc;
  106. FAR uint8_t *rdbuffer;
  107. ssize_t nread;
  108. off_t fpos;
  109. int errcode;
  110. int ret;
  111. /* There is a major design flaw that I have not yet thought of fix for:
  112. * The goal is to have a single region of memory that represents a single
  113. * file and can be shared by many threads. That is, given a filename a
  114. * thread should be able to open the file, get a file descriptor, and
  115. * call mmap() to get a memory region. Different file descriptors opened
  116. * with the same file path should get the same memory region when mapped.
  117. *
  118. * The design flaw is that I don't have sufficient knowledge to know that
  119. * these different file descriptors map to the same file. So, for the time
  120. * being, a new memory region is created each time that rammap() is called.
  121. * Not very useful!
  122. */
  123. /* Allocate a region of memory of the specified size */
  124. alloc = (FAR uint8_t *)kumm_malloc(sizeof(struct fs_rammap_s) + length);
  125. if (!alloc)
  126. {
  127. ferr("ERROR: Region allocation failed, length: %d\n", (int)length);
  128. errcode = ENOMEM;
  129. goto errout;
  130. }
  131. /* Initialize the region */
  132. map = (FAR struct fs_rammap_s *)alloc;
  133. memset(map, 0, sizeof(struct fs_rammap_s));
  134. map->addr = alloc + sizeof(struct fs_rammap_s);
  135. map->length = length;
  136. map->offset = offset;
  137. /* Seek to the specified file offset */
  138. fpos = lseek(fd, offset, SEEK_SET);
  139. if (fpos == (off_t)-1)
  140. {
  141. /* Seek failed... errno has already been set, but EINVAL is probably
  142. * the correct response.
  143. */
  144. ferr("ERROR: Seek to position %d failed\n", (int)offset);
  145. errcode = EINVAL;
  146. goto errout_with_region;
  147. }
  148. /* Read the file data into the memory region */
  149. rdbuffer = map->addr;
  150. while (length > 0)
  151. {
  152. nread = read(fd, rdbuffer, length);
  153. if (nread < 0)
  154. {
  155. /* Handle the special case where the read was interrupted by a
  156. * signal.
  157. */
  158. errcode = get_errno();
  159. if (errcode != EINTR)
  160. {
  161. /* All other read errors are bad. errno is already set.
  162. * (but maybe should be forced to EINVAL?). NOTE that if
  163. * FS DEBUG is enabled, then the following ferr() macro will
  164. * destroy the errno value.
  165. */
  166. ferr("ERROR: Read failed: offset=%d errno=%d\n",
  167. (int)offset, errcode);
  168. #ifdef CONFIG_DEBUG_FS
  169. goto errout_with_region;
  170. #else
  171. goto errout_with_errno;
  172. #endif
  173. }
  174. }
  175. /* Check for end of file. */
  176. if (nread == 0)
  177. {
  178. break;
  179. }
  180. /* Increment number of bytes read */
  181. rdbuffer += nread;
  182. length -= nread;
  183. }
  184. /* Zero any memory beyond the amount read from the file */
  185. memset(rdbuffer, 0, length);
  186. /* Add the buffer to the list of regions */
  187. rammap_initialize();
  188. ret = sem_wait(&g_rammaps.exclsem);
  189. if (ret < 0)
  190. {
  191. goto errout_with_errno;
  192. }
  193. map->flink = g_rammaps.head;
  194. g_rammaps.head = map;
  195. sem_post(&g_rammaps.exclsem);
  196. return map->addr;
  197. errout_with_region:
  198. kumm_free(alloc);
  199. errout:
  200. set_errno(errcode);
  201. return MAP_FAILED;
  202. errout_with_errno:
  203. kumm_free(alloc);
  204. return MAP_FAILED;
  205. }
  206. #endif /* CONFIG_FS_RAMMAP */