You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by GitBox <gi...@apache.org> on 2022/11/22 14:17:29 UTC

[GitHub] [incubator-nuttx] XinStellaris opened a new pull request, #7659: driver/syslog:add stream as syslog backend, let crash dump into stream.

XinStellaris opened a new pull request, #7659:
URL: https://github.com/apache/incubator-nuttx/pull/7659

   Signed-off-by: 田昕 <ti...@xiaomi.com>
   
   ## Summary
   This patch aims at saving crash sysloging into a mtd device.
   To do so, a new lib_mtdoutstream is added, which can be used in interrupt context.
   Then a new syslog channel utilizing the lib_mtdoutstream is added. The channel is enabled for syslog output only when asserting.
   
   This is useful when only a rather small flash can be used to save crash information. 
   
   ## Impact
   syslog output when crashing.
   
   ## Testing
   Tested on ESP32C3.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx] xiaoxiang781216 commented on a diff in pull request #7659: driver/syslog:add stream as syslog backend, let crash dump into stream.

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on code in PR #7659:
URL: https://github.com/apache/incubator-nuttx/pull/7659#discussion_r1030130080


##########
libs/libc/stream/lib_mtdoutstream.c:
##########
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * libs/libc/stream/lib_mtdoutstream.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <unistd.h>
+#include <nuttx/streams.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mtd/mtd.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mtdoutstream_flush
+ ****************************************************************************/
+
+static int mtdoutstream_flush(FAR struct lib_outstream_s *this)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+                                 (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  int ret = OK;
+
+  if (this->nput % erasesize > 0)
+    {
+#ifdef CONFIG_MTD_BYTE_WRITE
+      /* if byte write, flush won't be needed */
+
+      if (stream->inode->u.i_mtd->write == NULL)
+#endif
+        {
+          ret = MTD_ERASE(stream->inode->u.i_mtd, this->nput / erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+
+          ret = MTD_BWRITE(stream->inode->u.i_mtd,
+                           this->nput / erasesize * nblock_in_erasesize,
+                           nblock_in_erasesize, stream->cache);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: mtdoutstream_puts
+ ****************************************************************************/
+
+static int mtdoutstream_puts(FAR struct lib_outstream_s *this,
+                             FAR const void *buf, int len)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+    (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  FAR struct inode *inode = stream->inode;
+  FAR const unsigned char *ptr = buf;
+  size_t remain = len;
+  int ret;
+
+  if (this->nput + len > erasesize * stream->geo.neraseblocks)
+    {
+      return -ENOSPC;
+    }
+
+#ifdef CONFIG_MTD_BYTE_WRITE
+  if (stream->inode->u.i_mtd->write != NULL)
+    {
+      if (this->nput % stream->geo.erasesize == 0)
+        {
+          ret = MTD_ERASE(inode->u.i_mtd,
+                          this->nput / stream->geo.erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+        }
+
+      ret = MTD_WRITE(inode->u.i_mtd, this->nput, len, buf);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      this->nput += len;
+    }
+  else
+#endif
+    {
+      while (remain > 0)
+        {
+          size_t sblock = this->nput / erasesize;
+          size_t offset = this->nput % erasesize;
+
+          if (offset > 0)
+            {
+              size_t copyin = offset + remain > erasesize ?
+                              erasesize - offset : remain;
+
+              memcpy(stream->cache + offset, ptr, copyin);
+
+              ptr        += copyin;
+              offset     += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+
+              if (offset == erasesize)
+                {
+                  ret = MTD_ERASE(inode->u.i_mtd, sblock, 1);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+
+                  ret = MTD_BWRITE(inode->u.i_mtd,
+                                   sblock * nblock_in_erasesize,
+                                   nblock_in_erasesize, stream->cache);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+                }
+            }
+          else if (remain < erasesize)
+            {
+              /* erase content to all 0 before caching,
+               * so no random content will be flushed
+               */
+
+              memset(stream->cache, 0, stream->geo.erasesize);
+              memcpy(stream->cache, ptr, remain);
+              this->nput += remain;
+              remain      = 0;
+            }
+          else if (remain >= erasesize)
+            {
+              size_t copyin = (remain / erasesize) * erasesize;
+
+              ret = MTD_ERASE(inode->u.i_mtd, sblock,
+                              remain / erasesize);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ret = MTD_BWRITE(inode->u.i_mtd, sblock * nblock_in_erasesize,
+                               remain / erasesize * nblock_in_erasesize,
+                               ptr);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ptr        += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+            }
+        }
+    }
+
+  return len;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_close
+ *
+ * Description:
+ *  close mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream  - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *
+ * Returned Value:
+ *   None (User allocated instance initialized).
+ *
+ ****************************************************************************/
+
+void lib_mtdoutstream_close(FAR struct lib_mtdoutstream_s *stream)
+{
+  if (stream != NULL)
+    {
+      if (stream->inode != NULL)
+        {
+          stream->inode = NULL;
+        }
+
+      if (stream->cache != NULL)
+        {
+          lib_free(stream->cache);
+          stream->cache = NULL;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_open
+ *
+ * Description:
+ *  mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream   - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *   name     - The full path of mtd device.
+ *
+ * Returned Value:
+ *   Returns zero on success or a negated errno on failure
+ *
+ ****************************************************************************/
+
+int lib_mtdoutstream_open(FAR struct lib_mtdoutstream_s *stream,
+                          FAR const char *name)
+{
+  FAR struct inode *sys_node = NULL;
+
+  if (stream == NULL || name == NULL)
+    {
+      return -EINVAL;
+    }
+
+  if (find_mtddriver(name, &sys_node) < 0)
+    {
+      return -ENODEV;
+    }
+
+  memset(stream, 0, sizeof(*stream));
+
+  if (sys_node->u.i_mtd->ioctl == NULL ||
+      sys_node->u.i_mtd->erase == NULL ||
+      sys_node->u.i_mtd->bwrite == NULL ||
+      sys_node->u.i_mtd->ioctl(sys_node->u.i_mtd, MTDIOC_GEOMETRY,
+                               (unsigned long)&stream->geo) < 0 ||
+      stream->geo.blocksize <= 0 ||
+      stream->geo.erasesize <= 0 ||
+      stream->geo.neraseblocks <= 0)
+    {
+      return -EINVAL;

Review Comment:
   find_mtddriver will add the reference count of inode, you need release it before you lose the inode handle.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx] xiaoxiang781216 commented on a diff in pull request #7659: driver/syslog:add stream as syslog backend, let crash dump into stream.

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on code in PR #7659:
URL: https://github.com/apache/incubator-nuttx/pull/7659#discussion_r1029997126


##########
libs/libc/stream/Make.defs:
##########
@@ -25,7 +25,7 @@ CSRCS += lib_meminstream.c lib_memoutstream.c lib_memsistream.c
 CSRCS += lib_memsostream.c lib_lowoutstream.c lib_rawinstream.c
 CSRCS += lib_rawoutstream.c lib_rawsistream.c lib_rawsostream.c
 CSRCS += lib_zeroinstream.c lib_nullinstream.c lib_nulloutstream.c
-CSRCS += lib_libnoflush.c lib_libsnoflush.c
+CSRCS += lib_libnoflush.c lib_libsnoflush.c lib_mtdoutstream.c

Review Comment:
   CSRCS += lib_mtdoutstream.c lib_libnoflush.c lib_libsnoflush.c



##########
libs/libc/stream/lib_mtdoutstream.c:
##########
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * libs/libc/stream/lib_mtdoutstream.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <unistd.h>
+#include <nuttx/streams.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mtd/mtd.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mtdoutstream_flush
+ ****************************************************************************/
+
+static int mtdoutstream_flush(FAR struct lib_outstream_s *this)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+                                 (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  int ret = OK;
+
+  if (this->nput % erasesize > 0)
+    {
+#ifdef CONFIG_MTD_BYTE_WRITE
+      /* if byte write, flush won't be needed */
+
+      if (stream->inode->u.i_mtd->write == NULL)
+#endif
+        {
+          ret = MTD_ERASE(stream->inode->u.i_mtd, this->nput / erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+
+          ret = MTD_BWRITE(stream->inode->u.i_mtd,
+                           this->nput / erasesize * nblock_in_erasesize,
+                           nblock_in_erasesize, stream->cache);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: mtdoutstream_puts
+ ****************************************************************************/
+
+static int mtdoutstream_puts(FAR struct lib_outstream_s *this,
+                             FAR const void *buf, int len)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+    (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  FAR struct inode *inode = stream->inode;
+  FAR const unsigned char *ptr = buf;
+  size_t remain = len;
+  int ret;
+
+  if (this->nput + len > erasesize * stream->geo.neraseblocks)
+    {
+      return -ENOSPC;
+    }
+
+#ifdef CONFIG_MTD_BYTE_WRITE
+  if (stream->inode->u.i_mtd->write != NULL)
+    {
+      if (this->nput % stream->geo.erasesize == 0)
+        {
+          ret = MTD_ERASE(inode->u.i_mtd,
+                          this->nput / stream->geo.erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+        }
+
+      ret = MTD_WRITE(inode->u.i_mtd, this->nput, len, buf);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      this->nput += len;
+    }
+  else
+#endif
+    {
+      while (remain > 0)
+        {
+          size_t sblock = this->nput / erasesize;
+          size_t offset = this->nput % erasesize;
+
+          if (offset > 0)
+            {
+              size_t copyin = offset + remain > erasesize ?
+                              erasesize - offset : remain;
+
+              memcpy(stream->cache + offset, ptr, copyin);
+
+              ptr        += copyin;
+              offset     += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+
+              if (offset == erasesize)
+                {
+                  ret = MTD_ERASE(inode->u.i_mtd, sblock, 1);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+
+                  ret = MTD_BWRITE(inode->u.i_mtd,
+                                   sblock * nblock_in_erasesize,
+                                   nblock_in_erasesize, stream->cache);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+                }
+            }
+          else if (remain < erasesize)
+            {
+              /* erase content to all 0 before caching,
+               * so no random content will be flushed
+               */
+
+              memset(stream->cache, 0, stream->geo.erasesize);
+              memcpy(stream->cache, ptr, remain);
+              this->nput += remain;
+              remain      = 0;
+            }
+          else if (remain >= erasesize)
+            {
+              size_t copyin = (remain / erasesize) * erasesize;
+
+              ret = MTD_ERASE(inode->u.i_mtd, sblock,
+                              remain / erasesize);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ret = MTD_BWRITE(inode->u.i_mtd, sblock * nblock_in_erasesize,
+                               remain / erasesize * nblock_in_erasesize,
+                               ptr);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ptr        += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+            }
+        }
+    }
+
+  return len;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_close
+ *
+ * Description:
+ *  close mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream  - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *
+ * Returned Value:
+ *   None (User allocated instance initialized).
+ *
+ ****************************************************************************/
+
+void lib_mtdoutstream_close(FAR struct lib_mtdoutstream_s *stream)
+{
+  if (stream != NULL)
+    {
+      if (stream->inode != NULL)

Review Comment:
   close_mtddriver



##########
libs/libc/stream/lib_mtdoutstream.c:
##########
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * libs/libc/stream/lib_mtdoutstream.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <unistd.h>
+#include <nuttx/streams.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mtd/mtd.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mtdoutstream_flush
+ ****************************************************************************/
+
+static int mtdoutstream_flush(FAR struct lib_outstream_s *this)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+                                 (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;

Review Comment:
   stream->geo.erasesize to erasesize



##########
libs/libc/stream/lib_mtdoutstream.c:
##########
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * libs/libc/stream/lib_mtdoutstream.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <unistd.h>
+#include <nuttx/streams.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mtd/mtd.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mtdoutstream_flush
+ ****************************************************************************/
+
+static int mtdoutstream_flush(FAR struct lib_outstream_s *this)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+                                 (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  int ret = OK;
+
+  if (this->nput % erasesize > 0)
+    {
+#ifdef CONFIG_MTD_BYTE_WRITE
+      /* if byte write, flush won't be needed */
+
+      if (stream->inode->u.i_mtd->write == NULL)
+#endif
+        {
+          ret = MTD_ERASE(stream->inode->u.i_mtd, this->nput / erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+
+          ret = MTD_BWRITE(stream->inode->u.i_mtd,
+                           this->nput / erasesize * nblock_in_erasesize,
+                           nblock_in_erasesize, stream->cache);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: mtdoutstream_puts
+ ****************************************************************************/
+
+static int mtdoutstream_puts(FAR struct lib_outstream_s *this,
+                             FAR const void *buf, int len)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+    (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  FAR struct inode *inode = stream->inode;
+  FAR const unsigned char *ptr = buf;
+  size_t remain = len;
+  int ret;
+
+  if (this->nput + len > erasesize * stream->geo.neraseblocks)
+    {
+      return -ENOSPC;
+    }
+
+#ifdef CONFIG_MTD_BYTE_WRITE
+  if (stream->inode->u.i_mtd->write != NULL)
+    {
+      if (this->nput % stream->geo.erasesize == 0)
+        {
+          ret = MTD_ERASE(inode->u.i_mtd,
+                          this->nput / stream->geo.erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+        }
+
+      ret = MTD_WRITE(inode->u.i_mtd, this->nput, len, buf);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      this->nput += len;
+    }
+  else
+#endif
+    {
+      while (remain > 0)
+        {
+          size_t sblock = this->nput / erasesize;
+          size_t offset = this->nput % erasesize;
+
+          if (offset > 0)
+            {
+              size_t copyin = offset + remain > erasesize ?
+                              erasesize - offset : remain;
+
+              memcpy(stream->cache + offset, ptr, copyin);
+
+              ptr        += copyin;
+              offset     += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+
+              if (offset == erasesize)
+                {
+                  ret = MTD_ERASE(inode->u.i_mtd, sblock, 1);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+
+                  ret = MTD_BWRITE(inode->u.i_mtd,
+                                   sblock * nblock_in_erasesize,
+                                   nblock_in_erasesize, stream->cache);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+                }
+            }
+          else if (remain < erasesize)
+            {
+              /* erase content to all 0 before caching,
+               * so no random content will be flushed
+               */
+
+              memset(stream->cache, 0, stream->geo.erasesize);
+              memcpy(stream->cache, ptr, remain);
+              this->nput += remain;
+              remain      = 0;
+            }
+          else if (remain >= erasesize)
+            {
+              size_t copyin = (remain / erasesize) * erasesize;
+
+              ret = MTD_ERASE(inode->u.i_mtd, sblock,
+                              remain / erasesize);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ret = MTD_BWRITE(inode->u.i_mtd, sblock * nblock_in_erasesize,
+                               remain / erasesize * nblock_in_erasesize,
+                               ptr);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ptr        += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+            }
+        }
+    }
+
+  return len;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_close
+ *
+ * Description:
+ *  close mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream  - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *
+ * Returned Value:
+ *   None (User allocated instance initialized).
+ *
+ ****************************************************************************/
+
+void lib_mtdoutstream_close(FAR struct lib_mtdoutstream_s *stream)
+{
+  if (stream != NULL)
+    {
+      if (stream->inode != NULL)
+        {
+          stream->inode = NULL;
+        }
+
+      if (stream->cache != NULL)
+        {
+          lib_free(stream->cache);
+          stream->cache = NULL;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_open
+ *
+ * Description:
+ *  mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream   - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *   name     - The full path of mtd device.
+ *
+ * Returned Value:
+ *   Returns zero on success or a negated errno on failure
+ *
+ ****************************************************************************/
+
+int lib_mtdoutstream_open(FAR struct lib_mtdoutstream_s *stream,
+                          FAR const char *name)
+{
+  FAR struct inode *sys_node = NULL;
+
+  if (stream == NULL || name == NULL)
+    {
+      return -EINVAL;
+    }
+
+  if (find_mtddriver(name, &sys_node) < 0)
+    {
+      return -ENODEV;
+    }
+
+  memset(stream, 0, sizeof(*stream));
+
+  if (sys_node->u.i_mtd->ioctl == NULL ||
+      sys_node->u.i_mtd->erase == NULL ||
+      sys_node->u.i_mtd->bwrite == NULL ||
+      sys_node->u.i_mtd->ioctl(sys_node->u.i_mtd, MTDIOC_GEOMETRY,
+                               (unsigned long)&stream->geo) < 0 ||
+      stream->geo.blocksize <= 0 ||
+      stream->geo.erasesize <= 0 ||
+      stream->geo.neraseblocks <= 0)
+    {
+      return -EINVAL;
+    }
+
+#ifdef CONFIG_MTD_BYTE_WRITE
+  if (sys_node->u.i_mtd->write == NULL)
+#endif
+    {
+      stream->cache = lib_zalloc(stream->geo.erasesize);
+      if (stream->cache == NULL)
+        {
+          return -ENOMEM;

Review Comment:
   call close_mtddriver



##########
libs/libc/stream/lib_mtdoutstream.c:
##########
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * libs/libc/stream/lib_mtdoutstream.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <unistd.h>
+#include <nuttx/streams.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mtd/mtd.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mtdoutstream_flush
+ ****************************************************************************/
+
+static int mtdoutstream_flush(FAR struct lib_outstream_s *this)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+                                 (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;

Review Comment:
   nblock_in_erasesize -> nblkpererase?



##########
libs/libc/stream/lib_mtdoutstream.c:
##########
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * libs/libc/stream/lib_mtdoutstream.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <unistd.h>
+#include <nuttx/streams.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mtd/mtd.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mtdoutstream_flush
+ ****************************************************************************/
+
+static int mtdoutstream_flush(FAR struct lib_outstream_s *this)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+                                 (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  int ret = OK;
+
+  if (this->nput % erasesize > 0)
+    {
+#ifdef CONFIG_MTD_BYTE_WRITE
+      /* if byte write, flush won't be needed */
+
+      if (stream->inode->u.i_mtd->write == NULL)
+#endif
+        {
+          ret = MTD_ERASE(stream->inode->u.i_mtd, this->nput / erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+
+          ret = MTD_BWRITE(stream->inode->u.i_mtd,
+                           this->nput / erasesize * nblock_in_erasesize,
+                           nblock_in_erasesize, stream->cache);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: mtdoutstream_puts
+ ****************************************************************************/
+
+static int mtdoutstream_puts(FAR struct lib_outstream_s *this,
+                             FAR const void *buf, int len)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+    (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;

Review Comment:
   stream->geo.erasesize to erasesize



##########
libs/libc/stream/lib_mtdoutstream.c:
##########
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * libs/libc/stream/lib_mtdoutstream.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <unistd.h>
+#include <nuttx/streams.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mtd/mtd.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mtdoutstream_flush
+ ****************************************************************************/
+
+static int mtdoutstream_flush(FAR struct lib_outstream_s *this)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+                                 (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  int ret = OK;
+
+  if (this->nput % erasesize > 0)
+    {
+#ifdef CONFIG_MTD_BYTE_WRITE
+      /* if byte write, flush won't be needed */
+
+      if (stream->inode->u.i_mtd->write == NULL)
+#endif
+        {
+          ret = MTD_ERASE(stream->inode->u.i_mtd, this->nput / erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+
+          ret = MTD_BWRITE(stream->inode->u.i_mtd,
+                           this->nput / erasesize * nblock_in_erasesize,
+                           nblock_in_erasesize, stream->cache);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: mtdoutstream_puts
+ ****************************************************************************/
+
+static int mtdoutstream_puts(FAR struct lib_outstream_s *this,
+                             FAR const void *buf, int len)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+    (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  FAR struct inode *inode = stream->inode;
+  FAR const unsigned char *ptr = buf;
+  size_t remain = len;
+  int ret;
+
+  if (this->nput + len > erasesize * stream->geo.neraseblocks)
+    {
+      return -ENOSPC;
+    }
+
+#ifdef CONFIG_MTD_BYTE_WRITE
+  if (stream->inode->u.i_mtd->write != NULL)
+    {
+      if (this->nput % stream->geo.erasesize == 0)
+        {
+          ret = MTD_ERASE(inode->u.i_mtd,
+                          this->nput / stream->geo.erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+        }
+
+      ret = MTD_WRITE(inode->u.i_mtd, this->nput, len, buf);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      this->nput += len;
+    }
+  else
+#endif
+    {
+      while (remain > 0)
+        {
+          size_t sblock = this->nput / erasesize;
+          size_t offset = this->nput % erasesize;
+
+          if (offset > 0)
+            {
+              size_t copyin = offset + remain > erasesize ?
+                              erasesize - offset : remain;
+
+              memcpy(stream->cache + offset, ptr, copyin);
+
+              ptr        += copyin;
+              offset     += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+
+              if (offset == erasesize)
+                {
+                  ret = MTD_ERASE(inode->u.i_mtd, sblock, 1);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+
+                  ret = MTD_BWRITE(inode->u.i_mtd,
+                                   sblock * nblock_in_erasesize,
+                                   nblock_in_erasesize, stream->cache);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+                }
+            }
+          else if (remain < erasesize)
+            {
+              /* erase content to all 0 before caching,
+               * so no random content will be flushed
+               */
+
+              memset(stream->cache, 0, stream->geo.erasesize);
+              memcpy(stream->cache, ptr, remain);
+              this->nput += remain;
+              remain      = 0;
+            }
+          else if (remain >= erasesize)
+            {
+              size_t copyin = (remain / erasesize) * erasesize;
+
+              ret = MTD_ERASE(inode->u.i_mtd, sblock,
+                              remain / erasesize);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ret = MTD_BWRITE(inode->u.i_mtd, sblock * nblock_in_erasesize,
+                               remain / erasesize * nblock_in_erasesize,
+                               ptr);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ptr        += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+            }
+        }
+    }
+
+  return len;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_close
+ *
+ * Description:
+ *  close mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream  - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *
+ * Returned Value:
+ *   None (User allocated instance initialized).
+ *
+ ****************************************************************************/
+
+void lib_mtdoutstream_close(FAR struct lib_mtdoutstream_s *stream)
+{
+  if (stream != NULL)
+    {
+      if (stream->inode != NULL)
+        {
+          stream->inode = NULL;
+        }
+
+      if (stream->cache != NULL)
+        {
+          lib_free(stream->cache);
+          stream->cache = NULL;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_open
+ *
+ * Description:
+ *  mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream   - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *   name     - The full path of mtd device.
+ *
+ * Returned Value:
+ *   Returns zero on success or a negated errno on failure
+ *
+ ****************************************************************************/
+
+int lib_mtdoutstream_open(FAR struct lib_mtdoutstream_s *stream,
+                          FAR const char *name)
+{
+  FAR struct inode *sys_node = NULL;
+
+  if (stream == NULL || name == NULL)
+    {
+      return -EINVAL;
+    }
+
+  if (find_mtddriver(name, &sys_node) < 0)
+    {
+      return -ENODEV;

Review Comment:
   why eat find_mtddriver return value, there are many reason why find_mtddriver fail.



##########
libs/libc/stream/lib_mtdoutstream.c:
##########
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * libs/libc/stream/lib_mtdoutstream.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <unistd.h>
+#include <nuttx/streams.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mtd/mtd.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mtdoutstream_flush
+ ****************************************************************************/
+
+static int mtdoutstream_flush(FAR struct lib_outstream_s *this)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+                                 (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  int ret = OK;
+
+  if (this->nput % erasesize > 0)
+    {
+#ifdef CONFIG_MTD_BYTE_WRITE
+      /* if byte write, flush won't be needed */
+
+      if (stream->inode->u.i_mtd->write == NULL)
+#endif
+        {
+          ret = MTD_ERASE(stream->inode->u.i_mtd, this->nput / erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+
+          ret = MTD_BWRITE(stream->inode->u.i_mtd,
+                           this->nput / erasesize * nblock_in_erasesize,
+                           nblock_in_erasesize, stream->cache);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: mtdoutstream_puts
+ ****************************************************************************/
+
+static int mtdoutstream_puts(FAR struct lib_outstream_s *this,
+                             FAR const void *buf, int len)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+    (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;

Review Comment:
   nblock_in_erasesize -> nblkpererase?



##########
libs/libc/stream/lib_mtdoutstream.c:
##########
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * libs/libc/stream/lib_mtdoutstream.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <unistd.h>
+#include <nuttx/streams.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mtd/mtd.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mtdoutstream_flush
+ ****************************************************************************/
+
+static int mtdoutstream_flush(FAR struct lib_outstream_s *this)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+                                 (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  int ret = OK;
+
+  if (this->nput % erasesize > 0)
+    {
+#ifdef CONFIG_MTD_BYTE_WRITE
+      /* if byte write, flush won't be needed */
+
+      if (stream->inode->u.i_mtd->write == NULL)
+#endif
+        {
+          ret = MTD_ERASE(stream->inode->u.i_mtd, this->nput / erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+
+          ret = MTD_BWRITE(stream->inode->u.i_mtd,
+                           this->nput / erasesize * nblock_in_erasesize,
+                           nblock_in_erasesize, stream->cache);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: mtdoutstream_puts
+ ****************************************************************************/
+
+static int mtdoutstream_puts(FAR struct lib_outstream_s *this,
+                             FAR const void *buf, int len)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+    (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  FAR struct inode *inode = stream->inode;
+  FAR const unsigned char *ptr = buf;
+  size_t remain = len;
+  int ret;
+
+  if (this->nput + len > erasesize * stream->geo.neraseblocks)
+    {
+      return -ENOSPC;
+    }
+
+#ifdef CONFIG_MTD_BYTE_WRITE
+  if (stream->inode->u.i_mtd->write != NULL)
+    {
+      if (this->nput % stream->geo.erasesize == 0)
+        {
+          ret = MTD_ERASE(inode->u.i_mtd,
+                          this->nput / stream->geo.erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+        }
+
+      ret = MTD_WRITE(inode->u.i_mtd, this->nput, len, buf);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      this->nput += len;
+    }
+  else
+#endif
+    {
+      while (remain > 0)
+        {
+          size_t sblock = this->nput / erasesize;
+          size_t offset = this->nput % erasesize;
+
+          if (offset > 0)
+            {
+              size_t copyin = offset + remain > erasesize ?
+                              erasesize - offset : remain;
+
+              memcpy(stream->cache + offset, ptr, copyin);
+
+              ptr        += copyin;
+              offset     += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+
+              if (offset == erasesize)
+                {
+                  ret = MTD_ERASE(inode->u.i_mtd, sblock, 1);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+
+                  ret = MTD_BWRITE(inode->u.i_mtd,
+                                   sblock * nblock_in_erasesize,
+                                   nblock_in_erasesize, stream->cache);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+                }
+            }
+          else if (remain < erasesize)
+            {
+              /* erase content to all 0 before caching,
+               * so no random content will be flushed
+               */
+
+              memset(stream->cache, 0, stream->geo.erasesize);
+              memcpy(stream->cache, ptr, remain);
+              this->nput += remain;
+              remain      = 0;
+            }
+          else if (remain >= erasesize)
+            {
+              size_t copyin = (remain / erasesize) * erasesize;
+
+              ret = MTD_ERASE(inode->u.i_mtd, sblock,
+                              remain / erasesize);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ret = MTD_BWRITE(inode->u.i_mtd, sblock * nblock_in_erasesize,
+                               remain / erasesize * nblock_in_erasesize,
+                               ptr);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ptr        += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+            }
+        }
+    }
+
+  return len;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_close
+ *
+ * Description:
+ *  close mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream  - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *
+ * Returned Value:
+ *   None (User allocated instance initialized).
+ *
+ ****************************************************************************/
+
+void lib_mtdoutstream_close(FAR struct lib_mtdoutstream_s *stream)
+{
+  if (stream != NULL)
+    {
+      if (stream->inode != NULL)
+        {
+          stream->inode = NULL;
+        }
+
+      if (stream->cache != NULL)
+        {
+          lib_free(stream->cache);
+          stream->cache = NULL;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_open
+ *
+ * Description:
+ *  mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream   - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *   name     - The full path of mtd device.
+ *
+ * Returned Value:
+ *   Returns zero on success or a negated errno on failure
+ *
+ ****************************************************************************/
+
+int lib_mtdoutstream_open(FAR struct lib_mtdoutstream_s *stream,
+                          FAR const char *name)
+{
+  FAR struct inode *sys_node = NULL;
+
+  if (stream == NULL || name == NULL)
+    {
+      return -EINVAL;
+    }
+
+  if (find_mtddriver(name, &sys_node) < 0)
+    {
+      return -ENODEV;
+    }
+
+  memset(stream, 0, sizeof(*stream));
+
+  if (sys_node->u.i_mtd->ioctl == NULL ||
+      sys_node->u.i_mtd->erase == NULL ||
+      sys_node->u.i_mtd->bwrite == NULL ||
+      sys_node->u.i_mtd->ioctl(sys_node->u.i_mtd, MTDIOC_GEOMETRY,
+                               (unsigned long)&stream->geo) < 0 ||
+      stream->geo.blocksize <= 0 ||
+      stream->geo.erasesize <= 0 ||
+      stream->geo.neraseblocks <= 0)
+    {
+      return -EINVAL;

Review Comment:
   need close_mtddriver



##########
libs/libc/stream/lib_mtdoutstream.c:
##########
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * libs/libc/stream/lib_mtdoutstream.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <unistd.h>
+#include <nuttx/streams.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mtd/mtd.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mtdoutstream_flush
+ ****************************************************************************/
+
+static int mtdoutstream_flush(FAR struct lib_outstream_s *this)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+                                 (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  int ret = OK;
+
+  if (this->nput % erasesize > 0)
+    {
+#ifdef CONFIG_MTD_BYTE_WRITE
+      /* if byte write, flush won't be needed */
+
+      if (stream->inode->u.i_mtd->write == NULL)
+#endif
+        {
+          ret = MTD_ERASE(stream->inode->u.i_mtd, this->nput / erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+
+          ret = MTD_BWRITE(stream->inode->u.i_mtd,
+                           this->nput / erasesize * nblock_in_erasesize,
+                           nblock_in_erasesize, stream->cache);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: mtdoutstream_puts
+ ****************************************************************************/
+
+static int mtdoutstream_puts(FAR struct lib_outstream_s *this,
+                             FAR const void *buf, int len)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+    (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  FAR struct inode *inode = stream->inode;
+  FAR const unsigned char *ptr = buf;
+  size_t remain = len;
+  int ret;
+
+  if (this->nput + len > erasesize * stream->geo.neraseblocks)
+    {
+      return -ENOSPC;
+    }
+
+#ifdef CONFIG_MTD_BYTE_WRITE
+  if (stream->inode->u.i_mtd->write != NULL)
+    {
+      if (this->nput % stream->geo.erasesize == 0)
+        {
+          ret = MTD_ERASE(inode->u.i_mtd,
+                          this->nput / stream->geo.erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+        }
+
+      ret = MTD_WRITE(inode->u.i_mtd, this->nput, len, buf);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      this->nput += len;
+    }
+  else
+#endif
+    {
+      while (remain > 0)
+        {
+          size_t sblock = this->nput / erasesize;
+          size_t offset = this->nput % erasesize;
+
+          if (offset > 0)
+            {
+              size_t copyin = offset + remain > erasesize ?
+                              erasesize - offset : remain;
+
+              memcpy(stream->cache + offset, ptr, copyin);
+
+              ptr        += copyin;
+              offset     += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+
+              if (offset == erasesize)
+                {
+                  ret = MTD_ERASE(inode->u.i_mtd, sblock, 1);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+
+                  ret = MTD_BWRITE(inode->u.i_mtd,
+                                   sblock * nblock_in_erasesize,
+                                   nblock_in_erasesize, stream->cache);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+                }
+            }
+          else if (remain < erasesize)
+            {
+              /* erase content to all 0 before caching,
+               * so no random content will be flushed
+               */
+
+              memset(stream->cache, 0, stream->geo.erasesize);
+              memcpy(stream->cache, ptr, remain);
+              this->nput += remain;
+              remain      = 0;
+            }
+          else if (remain >= erasesize)
+            {
+              size_t copyin = (remain / erasesize) * erasesize;
+
+              ret = MTD_ERASE(inode->u.i_mtd, sblock,
+                              remain / erasesize);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ret = MTD_BWRITE(inode->u.i_mtd, sblock * nblock_in_erasesize,
+                               remain / erasesize * nblock_in_erasesize,
+                               ptr);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ptr        += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+            }
+        }
+    }
+
+  return len;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_close
+ *
+ * Description:
+ *  close mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream  - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *
+ * Returned Value:
+ *   None (User allocated instance initialized).
+ *
+ ****************************************************************************/
+
+void lib_mtdoutstream_close(FAR struct lib_mtdoutstream_s *stream)
+{
+  if (stream != NULL)
+    {
+      if (stream->inode != NULL)
+        {
+          stream->inode = NULL;
+        }
+
+      if (stream->cache != NULL)
+        {
+          lib_free(stream->cache);
+          stream->cache = NULL;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_open
+ *
+ * Description:
+ *  mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream   - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *   name     - The full path of mtd device.
+ *
+ * Returned Value:
+ *   Returns zero on success or a negated errno on failure
+ *
+ ****************************************************************************/
+
+int lib_mtdoutstream_open(FAR struct lib_mtdoutstream_s *stream,
+                          FAR const char *name)
+{
+  FAR struct inode *sys_node = NULL;

Review Comment:
   sys_node->node



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx] XinStellaris commented on a diff in pull request #7659: driver/syslog:add stream as syslog backend, let crash dump into stream.

Posted by GitBox <gi...@apache.org>.
XinStellaris commented on code in PR #7659:
URL: https://github.com/apache/incubator-nuttx/pull/7659#discussion_r1030089272


##########
libs/libc/stream/lib_mtdoutstream.c:
##########
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * libs/libc/stream/lib_mtdoutstream.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <unistd.h>
+#include <nuttx/streams.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mtd/mtd.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mtdoutstream_flush
+ ****************************************************************************/
+
+static int mtdoutstream_flush(FAR struct lib_outstream_s *this)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+                                 (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  int ret = OK;
+
+  if (this->nput % erasesize > 0)
+    {
+#ifdef CONFIG_MTD_BYTE_WRITE
+      /* if byte write, flush won't be needed */
+
+      if (stream->inode->u.i_mtd->write == NULL)
+#endif
+        {
+          ret = MTD_ERASE(stream->inode->u.i_mtd, this->nput / erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+
+          ret = MTD_BWRITE(stream->inode->u.i_mtd,
+                           this->nput / erasesize * nblock_in_erasesize,
+                           nblock_in_erasesize, stream->cache);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: mtdoutstream_puts
+ ****************************************************************************/
+
+static int mtdoutstream_puts(FAR struct lib_outstream_s *this,
+                             FAR const void *buf, int len)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+    (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  FAR struct inode *inode = stream->inode;
+  FAR const unsigned char *ptr = buf;
+  size_t remain = len;
+  int ret;
+
+  if (this->nput + len > erasesize * stream->geo.neraseblocks)
+    {
+      return -ENOSPC;
+    }
+
+#ifdef CONFIG_MTD_BYTE_WRITE
+  if (stream->inode->u.i_mtd->write != NULL)
+    {
+      if (this->nput % stream->geo.erasesize == 0)
+        {
+          ret = MTD_ERASE(inode->u.i_mtd,
+                          this->nput / stream->geo.erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+        }
+
+      ret = MTD_WRITE(inode->u.i_mtd, this->nput, len, buf);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      this->nput += len;
+    }
+  else
+#endif
+    {
+      while (remain > 0)
+        {
+          size_t sblock = this->nput / erasesize;
+          size_t offset = this->nput % erasesize;
+
+          if (offset > 0)
+            {
+              size_t copyin = offset + remain > erasesize ?
+                              erasesize - offset : remain;
+
+              memcpy(stream->cache + offset, ptr, copyin);
+
+              ptr        += copyin;
+              offset     += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+
+              if (offset == erasesize)
+                {
+                  ret = MTD_ERASE(inode->u.i_mtd, sblock, 1);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+
+                  ret = MTD_BWRITE(inode->u.i_mtd,
+                                   sblock * nblock_in_erasesize,
+                                   nblock_in_erasesize, stream->cache);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+                }
+            }
+          else if (remain < erasesize)
+            {
+              /* erase content to all 0 before caching,
+               * so no random content will be flushed
+               */
+
+              memset(stream->cache, 0, stream->geo.erasesize);
+              memcpy(stream->cache, ptr, remain);
+              this->nput += remain;
+              remain      = 0;
+            }
+          else if (remain >= erasesize)
+            {
+              size_t copyin = (remain / erasesize) * erasesize;
+
+              ret = MTD_ERASE(inode->u.i_mtd, sblock,
+                              remain / erasesize);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ret = MTD_BWRITE(inode->u.i_mtd, sblock * nblock_in_erasesize,
+                               remain / erasesize * nblock_in_erasesize,
+                               ptr);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ptr        += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+            }
+        }
+    }
+
+  return len;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_close
+ *
+ * Description:
+ *  close mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream  - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *
+ * Returned Value:
+ *   None (User allocated instance initialized).
+ *
+ ****************************************************************************/
+
+void lib_mtdoutstream_close(FAR struct lib_mtdoutstream_s *stream)
+{
+  if (stream != NULL)
+    {
+      if (stream->inode != NULL)
+        {
+          stream->inode = NULL;
+        }
+
+      if (stream->cache != NULL)
+        {
+          lib_free(stream->cache);
+          stream->cache = NULL;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_open
+ *
+ * Description:
+ *  mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream   - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *   name     - The full path of mtd device.
+ *
+ * Returned Value:
+ *   Returns zero on success or a negated errno on failure
+ *
+ ****************************************************************************/
+
+int lib_mtdoutstream_open(FAR struct lib_mtdoutstream_s *stream,
+                          FAR const char *name)
+{
+  FAR struct inode *sys_node = NULL;
+
+  if (stream == NULL || name == NULL)
+    {
+      return -EINVAL;
+    }
+
+  if (find_mtddriver(name, &sys_node) < 0)
+    {
+      return -ENODEV;
+    }
+
+  memset(stream, 0, sizeof(*stream));
+
+  if (sys_node->u.i_mtd->ioctl == NULL ||
+      sys_node->u.i_mtd->erase == NULL ||
+      sys_node->u.i_mtd->bwrite == NULL ||
+      sys_node->u.i_mtd->ioctl(sys_node->u.i_mtd, MTDIOC_GEOMETRY,
+                               (unsigned long)&stream->geo) < 0 ||
+      stream->geo.blocksize <= 0 ||
+      stream->geo.erasesize <= 0 ||
+      stream->geo.neraseblocks <= 0)
+    {
+      return -EINVAL;

Review Comment:
   mtd is not opened for mtd out stream. So is it right to  close mtd driver when mtd out stream open fails?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx] XinStellaris commented on a diff in pull request #7659: driver/syslog:add stream as syslog backend, let crash dump into stream.

Posted by GitBox <gi...@apache.org>.
XinStellaris commented on code in PR #7659:
URL: https://github.com/apache/incubator-nuttx/pull/7659#discussion_r1030089931


##########
libs/libc/stream/lib_mtdoutstream.c:
##########
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * libs/libc/stream/lib_mtdoutstream.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <unistd.h>
+#include <nuttx/streams.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mtd/mtd.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mtdoutstream_flush
+ ****************************************************************************/
+
+static int mtdoutstream_flush(FAR struct lib_outstream_s *this)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+                                 (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  int ret = OK;
+
+  if (this->nput % erasesize > 0)
+    {
+#ifdef CONFIG_MTD_BYTE_WRITE
+      /* if byte write, flush won't be needed */
+
+      if (stream->inode->u.i_mtd->write == NULL)
+#endif
+        {
+          ret = MTD_ERASE(stream->inode->u.i_mtd, this->nput / erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+
+          ret = MTD_BWRITE(stream->inode->u.i_mtd,
+                           this->nput / erasesize * nblock_in_erasesize,
+                           nblock_in_erasesize, stream->cache);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: mtdoutstream_puts
+ ****************************************************************************/
+
+static int mtdoutstream_puts(FAR struct lib_outstream_s *this,
+                             FAR const void *buf, int len)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+    (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  FAR struct inode *inode = stream->inode;
+  FAR const unsigned char *ptr = buf;
+  size_t remain = len;
+  int ret;
+
+  if (this->nput + len > erasesize * stream->geo.neraseblocks)
+    {
+      return -ENOSPC;
+    }
+
+#ifdef CONFIG_MTD_BYTE_WRITE
+  if (stream->inode->u.i_mtd->write != NULL)
+    {
+      if (this->nput % stream->geo.erasesize == 0)
+        {
+          ret = MTD_ERASE(inode->u.i_mtd,
+                          this->nput / stream->geo.erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+        }
+
+      ret = MTD_WRITE(inode->u.i_mtd, this->nput, len, buf);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      this->nput += len;
+    }
+  else
+#endif
+    {
+      while (remain > 0)
+        {
+          size_t sblock = this->nput / erasesize;
+          size_t offset = this->nput % erasesize;
+
+          if (offset > 0)
+            {
+              size_t copyin = offset + remain > erasesize ?
+                              erasesize - offset : remain;
+
+              memcpy(stream->cache + offset, ptr, copyin);
+
+              ptr        += copyin;
+              offset     += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+
+              if (offset == erasesize)
+                {
+                  ret = MTD_ERASE(inode->u.i_mtd, sblock, 1);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+
+                  ret = MTD_BWRITE(inode->u.i_mtd,
+                                   sblock * nblock_in_erasesize,
+                                   nblock_in_erasesize, stream->cache);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+                }
+            }
+          else if (remain < erasesize)
+            {
+              /* erase content to all 0 before caching,
+               * so no random content will be flushed
+               */
+
+              memset(stream->cache, 0, stream->geo.erasesize);
+              memcpy(stream->cache, ptr, remain);
+              this->nput += remain;
+              remain      = 0;
+            }
+          else if (remain >= erasesize)
+            {
+              size_t copyin = (remain / erasesize) * erasesize;
+
+              ret = MTD_ERASE(inode->u.i_mtd, sblock,
+                              remain / erasesize);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ret = MTD_BWRITE(inode->u.i_mtd, sblock * nblock_in_erasesize,
+                               remain / erasesize * nblock_in_erasesize,
+                               ptr);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ptr        += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+            }
+        }
+    }
+
+  return len;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_close
+ *
+ * Description:
+ *  close mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream  - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *
+ * Returned Value:
+ *   None (User allocated instance initialized).
+ *
+ ****************************************************************************/
+
+void lib_mtdoutstream_close(FAR struct lib_mtdoutstream_s *stream)
+{
+  if (stream != NULL)
+    {
+      if (stream->inode != NULL)
+        {
+          stream->inode = NULL;
+        }
+
+      if (stream->cache != NULL)
+        {
+          lib_free(stream->cache);
+          stream->cache = NULL;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_open
+ *
+ * Description:
+ *  mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream   - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *   name     - The full path of mtd device.
+ *
+ * Returned Value:
+ *   Returns zero on success or a negated errno on failure
+ *
+ ****************************************************************************/
+
+int lib_mtdoutstream_open(FAR struct lib_mtdoutstream_s *stream,
+                          FAR const char *name)
+{
+  FAR struct inode *sys_node = NULL;
+
+  if (stream == NULL || name == NULL)
+    {
+      return -EINVAL;
+    }
+
+  if (find_mtddriver(name, &sys_node) < 0)
+    {
+      return -ENODEV;
+    }
+
+  memset(stream, 0, sizeof(*stream));
+
+  if (sys_node->u.i_mtd->ioctl == NULL ||
+      sys_node->u.i_mtd->erase == NULL ||
+      sys_node->u.i_mtd->bwrite == NULL ||
+      sys_node->u.i_mtd->ioctl(sys_node->u.i_mtd, MTDIOC_GEOMETRY,
+                               (unsigned long)&stream->geo) < 0 ||
+      stream->geo.blocksize <= 0 ||
+      stream->geo.erasesize <= 0 ||
+      stream->geo.neraseblocks <= 0)
+    {
+      return -EINVAL;

Review Comment:
   For example, mtd partition are created after booted on ESP32C3 and BL602, and they are not supposed to be closed afterwards.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx] xiaoxiang781216 commented on a diff in pull request #7659: driver/syslog:add stream as syslog backend, let crash dump into stream.

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on code in PR #7659:
URL: https://github.com/apache/incubator-nuttx/pull/7659#discussion_r1030130080


##########
libs/libc/stream/lib_mtdoutstream.c:
##########
@@ -0,0 +1,297 @@
+/****************************************************************************
+ * libs/libc/stream/lib_mtdoutstream.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <unistd.h>
+#include <nuttx/streams.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mtd/mtd.h>
+
+#include "libc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_MTD)
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: mtdoutstream_flush
+ ****************************************************************************/
+
+static int mtdoutstream_flush(FAR struct lib_outstream_s *this)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+                                 (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  int ret = OK;
+
+  if (this->nput % erasesize > 0)
+    {
+#ifdef CONFIG_MTD_BYTE_WRITE
+      /* if byte write, flush won't be needed */
+
+      if (stream->inode->u.i_mtd->write == NULL)
+#endif
+        {
+          ret = MTD_ERASE(stream->inode->u.i_mtd, this->nput / erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+
+          ret = MTD_BWRITE(stream->inode->u.i_mtd,
+                           this->nput / erasesize * nblock_in_erasesize,
+                           nblock_in_erasesize, stream->cache);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: mtdoutstream_puts
+ ****************************************************************************/
+
+static int mtdoutstream_puts(FAR struct lib_outstream_s *this,
+                             FAR const void *buf, int len)
+{
+  FAR struct lib_mtdoutstream_s *stream =
+    (FAR struct lib_mtdoutstream_s *)this;
+  size_t erasesize = stream->geo.erasesize;
+  size_t nblock_in_erasesize = stream->geo.erasesize / stream->geo.blocksize;
+  FAR struct inode *inode = stream->inode;
+  FAR const unsigned char *ptr = buf;
+  size_t remain = len;
+  int ret;
+
+  if (this->nput + len > erasesize * stream->geo.neraseblocks)
+    {
+      return -ENOSPC;
+    }
+
+#ifdef CONFIG_MTD_BYTE_WRITE
+  if (stream->inode->u.i_mtd->write != NULL)
+    {
+      if (this->nput % stream->geo.erasesize == 0)
+        {
+          ret = MTD_ERASE(inode->u.i_mtd,
+                          this->nput / stream->geo.erasesize, 1);
+          if (ret < 0)
+            {
+              return ret;
+            }
+        }
+
+      ret = MTD_WRITE(inode->u.i_mtd, this->nput, len, buf);
+      if (ret < 0)
+        {
+          return ret;
+        }
+
+      this->nput += len;
+    }
+  else
+#endif
+    {
+      while (remain > 0)
+        {
+          size_t sblock = this->nput / erasesize;
+          size_t offset = this->nput % erasesize;
+
+          if (offset > 0)
+            {
+              size_t copyin = offset + remain > erasesize ?
+                              erasesize - offset : remain;
+
+              memcpy(stream->cache + offset, ptr, copyin);
+
+              ptr        += copyin;
+              offset     += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+
+              if (offset == erasesize)
+                {
+                  ret = MTD_ERASE(inode->u.i_mtd, sblock, 1);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+
+                  ret = MTD_BWRITE(inode->u.i_mtd,
+                                   sblock * nblock_in_erasesize,
+                                   nblock_in_erasesize, stream->cache);
+                  if (ret < 0)
+                    {
+                      return ret;
+                    }
+                }
+            }
+          else if (remain < erasesize)
+            {
+              /* erase content to all 0 before caching,
+               * so no random content will be flushed
+               */
+
+              memset(stream->cache, 0, stream->geo.erasesize);
+              memcpy(stream->cache, ptr, remain);
+              this->nput += remain;
+              remain      = 0;
+            }
+          else if (remain >= erasesize)
+            {
+              size_t copyin = (remain / erasesize) * erasesize;
+
+              ret = MTD_ERASE(inode->u.i_mtd, sblock,
+                              remain / erasesize);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ret = MTD_BWRITE(inode->u.i_mtd, sblock * nblock_in_erasesize,
+                               remain / erasesize * nblock_in_erasesize,
+                               ptr);
+              if (ret < 0)
+                {
+                  return ret;
+                }
+
+              ptr        += copyin;
+              this->nput += copyin;
+              remain     -= copyin;
+            }
+        }
+    }
+
+  return len;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_close
+ *
+ * Description:
+ *  close mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream  - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *
+ * Returned Value:
+ *   None (User allocated instance initialized).
+ *
+ ****************************************************************************/
+
+void lib_mtdoutstream_close(FAR struct lib_mtdoutstream_s *stream)
+{
+  if (stream != NULL)
+    {
+      if (stream->inode != NULL)
+        {
+          stream->inode = NULL;
+        }
+
+      if (stream->cache != NULL)
+        {
+          lib_free(stream->cache);
+          stream->cache = NULL;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: lib_mtdoutstream_open
+ *
+ * Description:
+ *  mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream   - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *   name     - The full path of mtd device.
+ *
+ * Returned Value:
+ *   Returns zero on success or a negated errno on failure
+ *
+ ****************************************************************************/
+
+int lib_mtdoutstream_open(FAR struct lib_mtdoutstream_s *stream,
+                          FAR const char *name)
+{
+  FAR struct inode *sys_node = NULL;
+
+  if (stream == NULL || name == NULL)
+    {
+      return -EINVAL;
+    }
+
+  if (find_mtddriver(name, &sys_node) < 0)
+    {
+      return -ENODEV;
+    }
+
+  memset(stream, 0, sizeof(*stream));
+
+  if (sys_node->u.i_mtd->ioctl == NULL ||
+      sys_node->u.i_mtd->erase == NULL ||
+      sys_node->u.i_mtd->bwrite == NULL ||
+      sys_node->u.i_mtd->ioctl(sys_node->u.i_mtd, MTDIOC_GEOMETRY,
+                               (unsigned long)&stream->geo) < 0 ||
+      stream->geo.blocksize <= 0 ||
+      stream->geo.erasesize <= 0 ||
+      stream->geo.neraseblocks <= 0)
+    {
+      return -EINVAL;

Review Comment:
   find_mtddriver will add the reference count of inode, you need release it before you lose the inode handle.
   BTW, don't assume how caller will use your library.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx] xiaoxiang781216 commented on a diff in pull request #7659: driver/syslog:add stream as syslog backend, let crash dump into stream.

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 commented on code in PR #7659:
URL: https://github.com/apache/incubator-nuttx/pull/7659#discussion_r1029438396


##########
libs/libc/stream/Kconfig:
##########
@@ -21,4 +21,15 @@ config STREAM_LZF_BLOG
 
 endif
 
+config STREAM_BACKEND_MTD

Review Comment:
   remove, let's check CONFIG_MTD



##########
libs/libc/stream/Make.defs:
##########
@@ -25,7 +25,7 @@ CSRCS += lib_meminstream.c lib_memoutstream.c lib_memsistream.c
 CSRCS += lib_memsostream.c lib_lowoutstream.c lib_rawinstream.c
 CSRCS += lib_rawoutstream.c lib_rawsistream.c lib_rawsostream.c
 CSRCS += lib_zeroinstream.c lib_nullinstream.c lib_nulloutstream.c
-CSRCS += lib_libnoflush.c lib_libsnoflush.c
+CSRCS += lib_libnoflush.c lib_libsnoflush.c lib_mtdoutstream.c

Review Comment:
   let's split mtdoutstream to the new patch



##########
include/nuttx/streams.h:
##########
@@ -427,6 +440,46 @@ int lib_blkoutstream_open(FAR struct lib_blkoutstream_s *stream,
 void lib_blkoutstream_close(FAR struct lib_blkoutstream_s *stream);
 #endif
 
+/****************************************************************************
+ * Name: lib_mtdoutstream_open
+ *
+ * Description:
+ *  mtd driver stream backend
+ *
+ * Input Parameters:
+ *   stream   - User allocated, uninitialized instance of struct
+ *                lib_mtdoutstream_s to be initialized.
+ *   sys_node - The inode of mtd device.
+ *
+ * Returned Value:
+ *   Returns zero on success or a negated errno on failure
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_STREAM_BACKEND_MTD
+int lib_mtdoutstream_open(FAR struct lib_mtdoutstream_s *stream,
+                          FAR struct inode *sys_node);

Review Comment:
   why not use pathname



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx] XinStellaris commented on pull request #7659: driver/syslog:add stream as syslog backend, let crash dump into stream.

Posted by GitBox <gi...@apache.org>.
XinStellaris commented on PR #7659:
URL: https://github.com/apache/incubator-nuttx/pull/7659#issuecomment-1325074221

   I will move the syslog backend to another pr


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [incubator-nuttx] xiaoxiang781216 merged pull request #7659: driver/syslog:add stream as syslog backend, let crash dump into stream.

Posted by GitBox <gi...@apache.org>.
xiaoxiang781216 merged PR #7659:
URL: https://github.com/apache/incubator-nuttx/pull/7659


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org