fs_procfsmeminfo.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. /****************************************************************************
  2. * fs/procfs/fs_procfsmeminfo.c
  3. *
  4. * Copyright (C) 2016-2017 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/stat.h>
  41. #include <stdint.h>
  42. #include <stdbool.h>
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <fcntl.h>
  47. #include <assert.h>
  48. #include <errno.h>
  49. #include <debug.h>
  50. #include <nuttx/kmalloc.h>
  51. #include <nuttx/pgalloc.h>
  52. #include <nuttx/progmem.h>
  53. #include <nuttx/mm/mm.h>
  54. #include <nuttx/fs/fs.h>
  55. #include <nuttx/fs/procfs.h>
  56. #ifndef CONFIG_FS_PROCFS_EXCLUDE_MEMINFO
  57. /****************************************************************************
  58. * Pre-processor Definitions
  59. ****************************************************************************/
  60. /* Determines the size of an intermediate buffer that must be large enough
  61. * to handle the longest line generated by this logic.
  62. */
  63. #define MEMINFO_LINELEN 54
  64. /****************************************************************************
  65. * Private Types
  66. ****************************************************************************/
  67. /* This structure describes one open "file" */
  68. struct meminfo_file_s
  69. {
  70. struct procfs_file_s base; /* Base open file structure */
  71. unsigned int linesize; /* Number of valid characters in line[] */
  72. char line[MEMINFO_LINELEN]; /* Pre-allocated buffer for formatted lines */
  73. };
  74. #if defined(CONFIG_ARCH_HAVE_PROGMEM) && defined(CONFIG_FS_PROCFS_INCLUDE_PROGMEM)
  75. struct progmem_info_s
  76. {
  77. int arena; /* Total size of available progmem. */
  78. int ordblks; /* This is the number of free chunks */
  79. int mxordblk; /* Size of the largest free chunk */
  80. int uordblks; /* Total size of memory for allocated chunks */
  81. int fordblks; /* Total size of memory for free chunks. */
  82. };
  83. #endif
  84. /****************************************************************************
  85. * Private Function Prototypes
  86. ****************************************************************************/
  87. #if defined(CONFIG_ARCH_HAVE_PROGMEM) && defined(CONFIG_FS_PROCFS_INCLUDE_PROGMEM)
  88. static void meminfo_progmem(FAR struct progmem_info_s *progmem);
  89. #endif
  90. /* File system methods */
  91. static int meminfo_open(FAR struct file *filep, FAR const char *relpath,
  92. int oflags, mode_t mode);
  93. static int meminfo_close(FAR struct file *filep);
  94. static ssize_t meminfo_read(FAR struct file *filep, FAR char *buffer,
  95. size_t buflen);
  96. static int meminfo_dup(FAR const struct file *oldp,
  97. FAR struct file *newp);
  98. static int meminfo_stat(FAR const char *relpath, FAR struct stat *buf);
  99. /****************************************************************************
  100. * Public Data
  101. ****************************************************************************/
  102. /* See fs_mount.c -- this structure is explicitly externed there.
  103. * We use the old-fashioned kind of initializers so that this will compile
  104. * with any compiler.
  105. */
  106. const struct procfs_operations meminfo_operations =
  107. {
  108. meminfo_open, /* open */
  109. meminfo_close, /* close */
  110. meminfo_read, /* read */
  111. NULL, /* write */
  112. meminfo_dup, /* dup */
  113. NULL, /* opendir */
  114. NULL, /* closedir */
  115. NULL, /* readdir */
  116. NULL, /* rewinddir */
  117. meminfo_stat /* stat */
  118. };
  119. /****************************************************************************
  120. * Private Functions
  121. ****************************************************************************/
  122. /****************************************************************************
  123. * Name: meminfo_progmem
  124. *
  125. * Description:
  126. * The moral equivalent of mallinfo() for prog mem
  127. *
  128. * TODO Max block size only works on uniform prog mem
  129. *
  130. ****************************************************************************/
  131. #if defined(CONFIG_ARCH_HAVE_PROGMEM) && defined(CONFIG_FS_PROCFS_INCLUDE_PROGMEM)
  132. static void meminfo_progmem(FAR struct progmem_info_s *progmem)
  133. {
  134. size_t page = 0;
  135. size_t stpage = 0xffff;
  136. size_t pagesize = 0;
  137. ssize_t status;
  138. progmem->arena = 0;
  139. progmem->fordblks = 0;
  140. progmem->uordblks = 0;
  141. progmem->mxordblk = 0;
  142. for (status = 0, page = 0; status >= 0; page++)
  143. {
  144. status = up_progmem_ispageerased(page);
  145. pagesize = up_progmem_pagesize(page);
  146. progmem->arena += pagesize;
  147. /* Is this beginning of new free space section */
  148. if (status == 0)
  149. {
  150. if (stpage == 0xffff)
  151. {
  152. stpage = page;
  153. }
  154. progmem->fordblks += pagesize;
  155. }
  156. else if (status != 0)
  157. {
  158. progmem->uordblks += pagesize;
  159. if (stpage != 0xffff && up_progmem_isuniform())
  160. {
  161. stpage = page - stpage;
  162. if (stpage > progmem->mxordblk)
  163. {
  164. progmem->mxordblk = stpage;
  165. }
  166. stpage = 0xffff;
  167. }
  168. }
  169. }
  170. progmem->mxordblk *= pagesize;
  171. }
  172. #endif
  173. /****************************************************************************
  174. * Name: meminfo_open
  175. ****************************************************************************/
  176. static int meminfo_open(FAR struct file *filep, FAR const char *relpath,
  177. int oflags, mode_t mode)
  178. {
  179. FAR struct meminfo_file_s *procfile;
  180. finfo("Open '%s'\n", relpath);
  181. /* PROCFS is read-only. Any attempt to open with any kind of write
  182. * access is not permitted.
  183. *
  184. * REVISIT: Write-able proc files could be quite useful.
  185. */
  186. if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0)
  187. {
  188. ferr("ERROR: Only O_RDONLY supported\n");
  189. return -EACCES;
  190. }
  191. /* "meminfo" is the only acceptable value for the relpath */
  192. if (strcmp(relpath, "meminfo") != 0)
  193. {
  194. ferr("ERROR: relpath is '%s'\n", relpath);
  195. return -ENOENT;
  196. }
  197. /* Allocate a container to hold the file attributes */
  198. procfile = (FAR struct meminfo_file_s *)
  199. kmm_zalloc(sizeof(struct meminfo_file_s));
  200. if (!procfile)
  201. {
  202. ferr("ERROR: Failed to allocate file attributes\n");
  203. return -ENOMEM;
  204. }
  205. /* Save the attributes as the open-specific state in filep->f_priv */
  206. filep->f_priv = (FAR void *)procfile;
  207. return OK;
  208. }
  209. /****************************************************************************
  210. * Name: meminfo_close
  211. ****************************************************************************/
  212. static int meminfo_close(FAR struct file *filep)
  213. {
  214. FAR struct meminfo_file_s *procfile;
  215. /* Recover our private data from the struct file instance */
  216. procfile = (FAR struct meminfo_file_s *)filep->f_priv;
  217. DEBUGASSERT(procfile);
  218. /* Release the file attributes structure */
  219. kmm_free(procfile);
  220. filep->f_priv = NULL;
  221. return OK;
  222. }
  223. /****************************************************************************
  224. * Name: meminfo_read
  225. ****************************************************************************/
  226. static ssize_t meminfo_read(FAR struct file *filep, FAR char *buffer,
  227. size_t buflen)
  228. {
  229. FAR struct meminfo_file_s *procfile;
  230. struct mallinfo mem;
  231. size_t linesize;
  232. size_t copysize;
  233. size_t totalsize;
  234. off_t offset;
  235. finfo("buffer=%p buflen=%d\n", buffer, (int)buflen);
  236. DEBUGASSERT(filep != NULL && buffer != NULL && buflen > 0);
  237. offset = filep->f_pos;
  238. /* Recover our private data from the struct file instance */
  239. procfile = (FAR struct meminfo_file_s *)filep->f_priv;
  240. DEBUGASSERT(procfile);
  241. /* The first line is the headers */
  242. linesize = snprintf(procfile->line, MEMINFO_LINELEN,
  243. " total used free largest\n");
  244. copysize = procfs_memcpy(procfile->line, linesize, buffer, buflen,
  245. &offset);
  246. totalsize = copysize;
  247. /* Followed by information about the memory resources */
  248. #ifdef CONFIG_MM_KERNEL_HEAP
  249. if (totalsize < buflen)
  250. {
  251. buffer += copysize;
  252. buflen -= copysize;
  253. /* Show kernel heap information */
  254. #ifdef CONFIG_CAN_PASS_STRUCTS
  255. mem = kmm_mallinfo();
  256. #else
  257. (void)kmm_mallinfo(&mem);
  258. #endif
  259. linesize = snprintf(procfile->line, MEMINFO_LINELEN,
  260. "Kmem: %11lu%11lu%11lu%11lu\n",
  261. (unsigned long)mem.arena,
  262. (unsigned long)mem.uordblks,
  263. (unsigned long)mem.fordblks,
  264. (unsigned long)mem.mxordblk);
  265. copysize = procfs_memcpy(procfile->line, linesize, buffer, buflen,
  266. &offset);
  267. totalsize += copysize;
  268. }
  269. #endif
  270. #if !defined(CONFIG_BUILD_KERNEL)
  271. if (totalsize < buflen)
  272. {
  273. buffer += copysize;
  274. buflen -= copysize;
  275. /* Show user heap information */
  276. #ifdef CONFIG_CAN_PASS_STRUCTS
  277. mem = kumm_mallinfo();
  278. #else
  279. (void)kumm_mallinfo(&mem);
  280. #endif
  281. linesize = snprintf(procfile->line, MEMINFO_LINELEN,
  282. "Umem: %11lu%11lu%11lu%11lu\n",
  283. (unsigned long)mem.arena,
  284. (unsigned long)mem.uordblks,
  285. (unsigned long)mem.fordblks,
  286. (unsigned long)mem.mxordblk);
  287. copysize = procfs_memcpy(procfile->line, linesize, buffer, buflen,
  288. &offset);
  289. totalsize += copysize;
  290. }
  291. #endif
  292. #ifdef CONFIG_MM_PGALLOC
  293. if (totalsize < buflen)
  294. {
  295. struct pginfo_s pginfo;
  296. unsigned long total;
  297. unsigned long available;
  298. unsigned long allocated;
  299. unsigned long max;
  300. buffer += copysize;
  301. buflen -= copysize;
  302. /* Show page allocator information */
  303. mm_pginfo(&pginfo);
  304. total = (unsigned long)pginfo.ntotal << MM_PGSHIFT;
  305. available = (unsigned long)pginfo.nfree << MM_PGSHIFT;
  306. allocated = total - available;
  307. max = (unsigned long)pginfo.mxfree << MM_PGSHIFT;
  308. linesize = snprintf(procfile->line, MEMINFO_LINELEN,
  309. "Page: %11lu%11lu%11lu%11lu\n",
  310. total, allocated, available, max);
  311. copysize = procfs_memcpy(procfile->line, linesize, buffer, buflen,
  312. &offset);
  313. totalsize += copysize;
  314. }
  315. #endif
  316. #if defined(CONFIG_ARCH_HAVE_PROGMEM) && defined(CONFIG_FS_PROCFS_INCLUDE_PROGMEM)
  317. if (totalsize < buflen)
  318. {
  319. struct progmem_info_s progmem;
  320. buffer += copysize;
  321. buflen -= copysize;
  322. /* The second line is the memory data */
  323. meminfo_progmem(&progmem);
  324. linesize = snprintf(procfile->line, MEMINFO_LINELEN,
  325. "Prog: %11lu%11lu%11lu%11lu\n",
  326. (unsigned long)progmem.arena,
  327. (unsigned long)progmem.uordblks,
  328. (unsigned long)progmem.fordblks,
  329. (unsigned long)progmem.mxordblk);
  330. copysize = procfs_memcpy(procfile->line, linesize, buffer, buflen,
  331. &offset);
  332. totalsize += copysize;
  333. }
  334. #endif
  335. /* Update the file offset */
  336. filep->f_pos += totalsize;
  337. return totalsize;
  338. }
  339. /****************************************************************************
  340. * Name: meminfo_dup
  341. *
  342. * Description:
  343. * Duplicate open file data in the new file structure.
  344. *
  345. ****************************************************************************/
  346. static int meminfo_dup(FAR const struct file *oldp, FAR struct file *newp)
  347. {
  348. FAR struct meminfo_file_s *oldattr;
  349. FAR struct meminfo_file_s *newattr;
  350. finfo("Dup %p->%p\n", oldp, newp);
  351. /* Recover our private data from the old struct file instance */
  352. oldattr = (FAR struct meminfo_file_s *)oldp->f_priv;
  353. DEBUGASSERT(oldattr);
  354. /* Allocate a new container to hold the task and attribute selection */
  355. newattr = (FAR struct meminfo_file_s *)
  356. kmm_malloc(sizeof(struct meminfo_file_s));
  357. if (!newattr)
  358. {
  359. ferr("ERROR: Failed to allocate file attributes\n");
  360. return -ENOMEM;
  361. }
  362. /* The copy the file attributes from the old attributes to the new */
  363. memcpy(newattr, oldattr, sizeof(struct meminfo_file_s));
  364. /* Save the new attributes in the new file structure */
  365. newp->f_priv = (FAR void *)newattr;
  366. return OK;
  367. }
  368. /****************************************************************************
  369. * Name: meminfo_stat
  370. *
  371. * Description: Return information about a file or directory
  372. *
  373. ****************************************************************************/
  374. static int meminfo_stat(FAR const char *relpath, FAR struct stat *buf)
  375. {
  376. /* "meminfo" is the only acceptable value for the relpath */
  377. if (strcmp(relpath, "meminfo") != 0)
  378. {
  379. ferr("ERROR: relpath is '%s'\n", relpath);
  380. return -ENOENT;
  381. }
  382. /* "meminfo" is the name for a read-only file */
  383. memset(buf, 0, sizeof(struct stat));
  384. buf->st_mode = S_IFREG | S_IROTH | S_IRGRP | S_IRUSR;
  385. return OK;
  386. }
  387. /****************************************************************************
  388. * Public Functions
  389. ****************************************************************************/
  390. #endif /* !CONFIG_FS_PROCFS_EXCLUDE_MEMINFO */