fs_procfsmeminfo.c 14 KB

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