diff --git a/apps/system/utils/fscmd.c b/apps/system/utils/fscmd.c index 8255fb40b5..cc4d2a23a1 100644 --- a/apps/system/utils/fscmd.c +++ b/apps/system/utils/fscmd.c @@ -65,6 +65,8 @@ #include #include #include +#include +#include #ifdef CONFIG_TASH #include #endif @@ -994,6 +996,155 @@ static int tash_umount(int argc, char **args) #endif #endif /* END OF CONFIG_DISABLE_MOUNTPOINT */ +/**************************************************************************** + * Name: tash_smartfs_dump + * + * Description: + * Unmount specific file system. + * + * Usage: + * umount + ****************************************************************************/ +#ifdef CONFIG_SMARTFS_DEBUG +#ifndef CONFIG_DISABLE_ENVIRON +static int tash_smartfs_dump(int argc, char **args) +{ + int fd; + int ret; + char device_path[32]; + struct mtd_geometry_s mtd_geo; + uint8_t *buffer; + ssize_t nbytes; + off_t seekpos; + size_t sector_size = 1024; /* SMARTFS sector size = 1024 bytes */ + uint16_t BlkperSect; + uint16_t SectperEraseBlk; + uint16_t total_sectors; + uint16_t sector_idx; + uint16_t erase_block; + uint16_t sector_in_block; + uint16_t njournaleraseblocks; + + int i, j; + + bool found = false; + + printf("Searching for MTD BLOCK device managed smartfs...\n"); + for (int minor = 0; minor < 2; minor++) { + for (int part = 0; part < 32; part++) { + snprintf(device_path, sizeof(device_path), "/dev/mtdblock%dp%d", minor, part); + + fd = open(device_path, O_RDONLY); + if (fd >= 0) { + printf("Found MTD BLOCK device managed smartfs: %s\n", device_path); + found = true; + break; + } + } + if (found) { + break; + } + } + + if (!found) { + printf("Can Not Find MTD BLOCK device managed smartfs\n"); + return ERROR; + } + + ret = ioctl(fd, MTDIOC_GEOMETRY, (unsigned long)&mtd_geo); + if (ret < 0) { + printf("Failed to get MTD geometry, errno: %d\n", errno); + close(fd); + return ERROR; + } + + printf("\n=== MTD Geometry ===\n"); + printf(" Block size: %u bytes\n", mtd_geo.blocksize); + printf(" Erase Blocksize: %u bytes\n", mtd_geo.erasesize); + printf(" Num Erase Blocks: %u\n", mtd_geo.neraseblocks); + + BlkperSect = sector_size / mtd_geo.blocksize; + SectperEraseBlk = mtd_geo.erasesize / sector_size; + total_sectors = mtd_geo.neraseblocks * SectperEraseBlk; + + printf(" Sector size: %u bytes\n", sector_size); + printf(" Sectors per Erase Block: %u\n", SectperEraseBlk); + printf(" Total sectors: %u\n", total_sectors); + + + uint16_t nsector = (mtd_geo.neraseblocks * SectperEraseBlk * 13) / (sector_size + 13); + njournaleraseblocks = nsector / SectperEraseBlk; + if (nsector % SectperEraseBlk != 0) { + njournaleraseblocks++; + } + if (njournaleraseblocks % 2 != 0) { + njournaleraseblocks++; + } + njournaleraseblocks *= 3; + + printf(" njournaleraseblocks: %u\n", njournaleraseblocks); + + buffer = (uint8_t *)malloc(sector_size); + if (!buffer) { + printf("Failed to allocate buffer\n"); + close(fd); + return ERROR; + } + + printf("\n=== Dumping All Sectors (Block 0 ~ %u) ===\n", mtd_geo.neraseblocks - 1); + + sector_idx = 0; + for (erase_block = 0; erase_block < mtd_geo.neraseblocks; erase_block++) { + for (sector_in_block = 0; sector_in_block < SectperEraseBlk; sector_in_block++) { + unsigned int mtd_block = sector_idx * BlkperSect; + + printf("\n=== Sector %u (block %u) ===\n", sector_idx, erase_block); + + seekpos = (off_t)mtd_block * mtd_geo.blocksize; + ret = lseek(fd, seekpos, SEEK_SET); + if (ret != seekpos) { + printf("Failed to seek to sector %u (offset %ld), errno: %d\n", + sector_idx, (long)seekpos, errno); + sector_idx++; + continue; + } + + nbytes = read(fd, buffer, sector_size); + if (nbytes < 0) { + printf("Read failed, errno: %d\n", errno); + sector_idx++; + continue; + } else if (nbytes != (ssize_t)sector_size) { + printf("Short read: got %ld bytes, expected %u\n", (long)nbytes, sector_size); + } + + int dump_size = nbytes; + for (i = 0; i < dump_size; i += 16) { + printf("%04X: ", i); + + for (j = 0; j < 16; j++) { + if (i + j < dump_size) { + printf("%02X ", buffer[i + j]); + } else { + printf(" "); + } + } + printf("\n"); + } + + sector_idx++; + } + } + + free(buffer); + close(fd); + + printf("\n=== Dump Complete ===\n"); + return OK; +} +#endif +#endif + #ifndef CONFIG_DISABLE_ENVIRON /**************************************************************************** * Name: tash_pwd @@ -1557,6 +1708,12 @@ const static tash_cmdlist_t fs_utilcmds[] = { {"rmdir", tash_rmdir, TASH_EXECMD_SYNC}, #endif +#ifdef CONFIG_SMARTFS_DEBUG +#ifndef CONFIG_DISABLE_ENVIRON + {"smartfs_dump", tash_smartfs_dump, TASH_EXECMD_SYNC}, +#endif +#endif + {NULL, NULL, 0} }; diff --git a/build/configs/rtl8730e/flat_dev_ddr/defconfig b/build/configs/rtl8730e/flat_dev_ddr/defconfig index a5360a64a8..e8559df262 100644 --- a/build/configs/rtl8730e/flat_dev_ddr/defconfig +++ b/build/configs/rtl8730e/flat_dev_ddr/defconfig @@ -1121,6 +1121,7 @@ CONFIG_SMARTFS_MAXNAMLEN=32 CONFIG_SMARTFS_ALIGNED_ACCESS=y # CONFIG_SMARTFS_DYNAMIC_HEADER is not set CONFIG_SMARTFS_ENTRY_TIMESTAMP=y +CONFIG_SMARTFS_DEBUG=y CONFIG_FS_PROCFS=y CONFIG_FS_AUTOMOUNT_PROCFS=y diff --git a/os/board/common/partitions.c b/os/board/common/partitions.c index 182e1ebc81..b50ec7d79d 100644 --- a/os/board/common/partitions.c +++ b/os/board/common/partitions.c @@ -195,6 +195,12 @@ static int type_specific_initialize(int minor, FAR struct mtd_dev_s *mtd_part, c char partref[4]; snprintf(partref, sizeof(partref), "p%d", g_partno); +#ifdef CONFIG_SMARTFS_DEBUG + if (ftl_initialize_ext(minor, mtd_part, partref)) { + printf("ERROR: failed to initialise mtd ftl errno :%d\n", errno); + return ERROR; + } +#endif smart_initialize(minor, mtd_part, partref); partinfo->smartfs_partno = g_partno; mtd_setpartitiontagno(mtd_part, MTD_FS); diff --git a/os/fs/driver/mtd/ftl.c b/os/fs/driver/mtd/ftl.c index 33330c4215..6b31f71586 100644 --- a/os/fs/driver/mtd/ftl.c +++ b/os/fs/driver/mtd/ftl.c @@ -582,3 +582,110 @@ int ftl_initialize(int minor, FAR struct mtd_dev_s *mtd) return ret; } + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ftl_initialize_ext + * + * Description: + * Initialize to provide a block driver wrapper around an MTD interface + * + * Input Parameters: + * minor - The minor device number. The MTD block device will be + * registered as as /dev/mtdblockN where N is the minor number. + * mtd - The MTD device that supports the FLASH interface. + * partname - Optional partition name to append to dev entry, NULL if + * not supplied. + ****************************************************************************/ + +#ifdef CONFIG_SMARTFS_DEBUG +int ftl_initialize_ext(int minor, FAR struct mtd_dev_s *mtd, FAR const char *partname) +{ + struct ftl_struct_s *dev; + char devname[22]; + int ret = -ENOMEM; + + /* Sanity check */ + + if (minor < 0 || minor > 255 || !mtd) { + return -EINVAL; + } + + /* Allocate a FTL device structure */ + + dev = (struct ftl_struct_s *)kmm_malloc(sizeof(struct ftl_struct_s)); + if (dev) { + /* Initialize the FTL device structure */ + + dev->mtd = mtd; + + /* Get the device geometry. (casting to uintptr_t first eliminates + * complaints on some architectures where the sizeof long is different + * from the size of a pointer). + */ + + ret = MTD_IOCTL(mtd, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&dev->geo)); + if (ret < 0) { + dbg("ERROR: MTD ioctl(MTDIOC_GEOMETRY) failed: %d\n", ret); + kmm_free(dev); + return ret; + } + + /* Allocate one, in-memory erase block buffer */ + +#ifdef CONFIG_FS_WRITABLE + dev->eblock = (FAR uint8_t *)kmm_malloc(dev->geo.erasesize); + if (!dev->eblock) { + dbg("ERROR: Failed to allocate an erase block buffer\n"); + kmm_free(dev); + return -ENOMEM; + } +#endif + + /* Get the number of R/W blocks per erase block */ + + dev->blkper = dev->geo.erasesize / dev->geo.blocksize; + DEBUGASSERT(dev->blkper * dev->geo.blocksize == dev->geo.erasesize); + + /* Configure read-ahead/write buffering */ + +#ifdef FTL_HAVE_RWBUFFER + dev->rwb.blocksize = dev->geo.blocksize; + dev->rwb.nblocks = dev->geo.neraseblocks * dev->blkper; + dev->rwb.dev = (FAR void *)dev; + +#if defined(CONFIG_FS_WRITABLE) && defined(CONFIG_FTL_WRITEBUFFER) + dev->rwb.wrmaxblocks = dev->blkper; + dev->rwb.wrflush = ftl_flush; +#endif + +#ifdef CONFIG_FTL_READAHEAD + dev->rwb.rhmaxblocks = dev->blkper; + dev->rwb.rhreload = ftl_reload; +#endif + + ret = rwb_initialize(&dev->rwb); + if (ret < 0) { + dbg("ERROR: rwb_initialize failed: %d\n", ret); + kmm_free(dev); + return ret; + } +#endif + + /* Create a MTD block device name */ + snprintf(devname, 22, "/dev/mtdblock%d%s", minor, partname); + /* Inode private data is a reference to the FTL device structure */ + + ret = register_blockdriver(devname, &g_bops, 0, dev); + if (ret < 0) { + dbg("ERROR: register_blockdriver failed: %d\n", -ret); + kmm_free(dev); + } + } + + return ret; +} +#endif