From 34a057334c16d7ca85a4628881051fe6187560da Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 22 Sep 2014 11:19:49 -0600 Subject: [PATCH] Update SMART FS procfs support. From Ken Pettit --- drivers/mtd/smart.c | 44 ++- fs/smartfs/smartfs.h | 10 +- fs/smartfs/smartfs_procfs.c | 588 ++++++++++++++++++++++++++++++++---- fs/smartfs/smartfs_utils.c | 44 ++- include/nuttx/fs/ioctl.h | 9 +- include/nuttx/mtd/smart.h | 104 +++++++ 6 files changed, 729 insertions(+), 70 deletions(-) create mode 100644 include/nuttx/mtd/smart.h diff --git a/drivers/mtd/smart.c b/drivers/mtd/smart.c index 156bbae1f9..cab0ecdf33 100644 --- a/drivers/mtd/smart.c +++ b/drivers/mtd/smart.c @@ -3,7 +3,7 @@ * * Sector Mapped Allocation for Really Tiny (SMART) Flash block driver. * - * Copyright (C) 2013 Ken Pettit. All rights reserved. + * Copyright (C) 2013-2014 Ken Pettit. All rights reserved. * Author: Ken Pettit * * Redistribution and use in source and binary forms, with or without @@ -56,6 +56,7 @@ #include #include #include +#include #include /**************************************************************************** @@ -1976,6 +1977,8 @@ static int smart_ioctl(FAR struct inode *inode, int cmd, unsigned long arg) { struct smart_struct_s *dev ; int ret; + uint32_t sector; + struct mtd_smart_procfs_data_s * procfs_data; fvdbg("Entry\n"); DEBUGASSERT(inode && inode->i_private); @@ -2059,9 +2062,46 @@ static int smart_ioctl(FAR struct inode *inode, int cmd, unsigned long arg) goto ok_out; #endif /* CONFIG_FS_WRITABLE */ +#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS) + case BIOC_GETPROCFSD: + + /* Get ProcFS data */ + + procfs_data = (FAR struct mtd_smart_procfs_data_s *) arg; + procfs_data->totalsectors = dev->totalsectors; + procfs_data->sectorsize = dev->sectorsize; + procfs_data->freesectors = dev->freesectors; + procfs_data->releasesectors = 0; + for (sector = 0; sector < dev->neraseblocks; sector++) + { + procfs_data->releasesectors += dev->releasecount[sector]; + } + + procfs_data->namelen = dev->namesize; + procfs_data->formatversion = dev->formatversion; + procfs_data->unusedsectors = 0; + procfs_data->blockerases = 0; + procfs_data->sectorsperblk = dev->sectorsPerBlk; + +#ifndef CONFIG_MTD_SMART_MINIMIZE_RAM + procfs_data->formatsector = dev->sMap[0]; + procfs_data->dirsector = dev->sMap[3]; +#endif + +#ifdef CONFIG_MTD_SMART_SECTOR_ERASE_DEBUG + procfs_data->neraseblocks = dev->geo.neraseblocks; + procfs_data->erasecounts = dev->erasecounts; +#endif +#ifdef CONFIG_MTD_SMART_ALLOC_DEBUG + procfs_data->allocs = dev->alloc; + procfs_data->alloccount = SMART_MAX_ALLOCS; +#endif + ret = OK; + goto ok_out; +#endif } - /* No other block driver ioctl commmands are not recognized by this + /* No other block driver ioctl commands are not recognized by this * driver. Other possible MTD driver ioctl commands are passed through * to the MTD driver (unchanged). */ diff --git a/fs/smartfs/smartfs.h b/fs/smartfs/smartfs.h index 22b08501dd..eb90b8c7db 100644 --- a/fs/smartfs/smartfs.h +++ b/fs/smartfs/smartfs.h @@ -1,11 +1,9 @@ /**************************************************************************** * fs/smartfs/smartfs.h * - * Copyright (C) 2013 Ken Pettit. All rights reserved. + * Copyright (C) 2013-2014 Ken Pettit. All rights reserved. * Author: Ken Pettit * - * References: Linux/Documentation/filesystems/romfs.txt - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -289,7 +287,7 @@ struct smartfs_ofile_s struct smartfs_mountpt_s { -#ifdef CONFIG_SMARTFS_MULTI_ROOT_DIRS +#if defined(CONFIG_SMARTFS_MULTI_ROOT_DIRS) || defined(CONFIG_FS_PROCFS) struct smartfs_mountpt_s *fs_next; /* Pointer to next SMART filesystem */ #endif FAR struct inode *fs_blkdriver; /* Our underlying block device */ @@ -344,6 +342,10 @@ int smartfs_countdirentries(struct smartfs_mountpt_s *fs, int smartfs_truncatefile(struct smartfs_mountpt_s *fs, struct smartfs_entry_s *entry); +#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS) +struct smartfs_mountpt_s* smartfs_get_first_mount(void); +#endif + struct file; /* Forward references */ struct inode; struct fs_dirent_s; diff --git a/fs/smartfs/smartfs_procfs.c b/fs/smartfs/smartfs_procfs.c index a0950bc19e..bc02042905 100644 --- a/fs/smartfs/smartfs_procfs.c +++ b/fs/smartfs/smartfs_procfs.c @@ -1,7 +1,7 @@ /**************************************************************************** * fs/smartfs/smartfs_procfs.c * - * Copyright (C) 2013 Ken Pettit. All rights reserved. + * Copyright (C) 2013-2014 Ken Pettit. All rights reserved. * Author: Ken Pettit * * Redistribution and use in source and binary forms, with or without @@ -59,8 +59,11 @@ #include #include #include +#include +#include #include +#include "smartfs.h" #if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_EXCLUDE_SMARTFS) @@ -75,15 +78,6 @@ * accessed via the procfs file system. */ -/* This structure describes one open "file" */ - -struct smartfs_file_s -{ - struct procfs_file_s base; /* Base open file structure */ - - /* Add context specific data types for managing an open file here */ -}; - /* Level 1 is the directory of attributes */ struct smartfs_level1_s @@ -94,6 +88,27 @@ struct smartfs_level1_s * open / read / stat, etc. */ + struct smartfs_mountpt_s* mount; + uint8_t direntry; +}; + +/* This structure describes one open "file" */ + +struct smartfs_file_s +{ + struct procfs_file_s base; /* Base open file structure */ + + /* Add context specific data types for managing an open file here */ + + struct smartfs_level1_s level1; /* Reference to item being accessed */ + uint16_t offset; +}; + +struct smartfs_procfs_entry_s +{ + const char *name; /* Name of the directory entry */ + size_t (*read)(FAR struct file *filep, FAR char *buffer, size_t buflen); + uint8_t type; }; /**************************************************************************** @@ -101,26 +116,55 @@ struct smartfs_level1_s ****************************************************************************/ /* File system methods */ -static int smartfs_open(FAR struct file *filep, FAR const char *relpath, - int oflags, mode_t mode); -static int smartfs_close(FAR struct file *filep); -static ssize_t smartfs_read(FAR struct file *filep, FAR char *buffer, - size_t buflen); +static int smartfs_open(FAR struct file *filep, FAR const char *relpath, + int oflags, mode_t mode); +static int smartfs_close(FAR struct file *filep); +static ssize_t smartfs_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); -static int smartfs_dup(FAR const struct file *oldp, +static int smartfs_dup(FAR const struct file *oldp, FAR struct file *newp); -static int smartfs_opendir(const char *relpath, FAR struct fs_dirent_s *dir); -static int smartfs_closedir(FAR struct fs_dirent_s *dir); -static int smartfs_readdir(FAR struct fs_dirent_s *dir); -static int smartfs_rewinddir(FAR struct fs_dirent_s *dir); +static int smartfs_opendir(const char *relpath, FAR struct fs_dirent_s *dir); +static int smartfs_closedir(FAR struct fs_dirent_s *dir); +static int smartfs_readdir(FAR struct fs_dirent_s *dir); +static int smartfs_rewinddir(FAR struct fs_dirent_s *dir); -static int smartfs_stat(FAR const char *relpath, FAR struct stat *buf); +static int smartfs_stat(FAR const char *relpath, FAR struct stat *buf); + +static size_t smartfs_status_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +#ifdef CONFIG_MTD_SMART_ALLOC_DEBUG +static size_t smartfs_mem_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +#endif +#ifdef CONFIG_MTD_SMART_SECTOR_ERASE_DEBUG +static size_t smartfs_erasemap_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +#endif +#ifdef CONFIG_SMARTFS_FILE_SECTOR_DEBUG +static size_t smartfs_files_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +#endif /**************************************************************************** * Private Variables ****************************************************************************/ +static const struct smartfs_procfs_entry_s g_direntry[] = +{ +#ifdef CONFIG_MTD_SMART_SECTOR_ERASE_DEBUG + { "erasemap", smartfs_erasemap_read, DTYPE_FILE }, +#endif +#ifdef CONFIG_MTD_SMART_ALLOC_DEBUG + { "mem", smartfs_mem_read, DTYPE_FILE }, +#endif + { "status", smartfs_status_read, DTYPE_FILE } +}; + +static const uint8_t g_direntrycount = sizeof(g_direntry) / + sizeof(struct smartfs_procfs_entry_s); + /**************************************************************************** * Public Variables ****************************************************************************/ @@ -136,8 +180,8 @@ const struct procfs_operations smartfs_procfsoperations = smartfs_close, /* close */ smartfs_read, /* read */ - /* TODO: Decide if this deiver supports write */ - NULL, /* write */ + /* No write supported */ + NULL, /* write */ smartfs_dup, /* dup */ @@ -153,6 +197,141 @@ const struct procfs_operations smartfs_procfsoperations = * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: smartfs_find_dirref + * + * Description: + * Analyse relpath to find the directory reference entry it represents, + * if any. + * + ****************************************************************************/ + +static int smartfs_find_dirref(FAR const char *relpath, + FAR struct smartfs_level1_s *level1) +{ + int ret = -ENOENT; + FAR struct smartfs_mountpt_s* mount; + uint16_t x; + FAR char * str; + + mount = smartfs_get_first_mount(); + + /* Skip the "fs/smartfs" portion of relpath */ + + if (strncmp(relpath, "fs/smartfs", 10) == 0) + { + relpath += 10; + } + + if (relpath[0] == '/') + { + relpath++; + } + + /* Now test if doing a full dir listing of fs/smartfs */ + + if (relpath[0] == '\0') + { + /* Save the mount as the first one to display */ + + level1->mount = mount; + level1->base.level = 1; + level1->base.nentries = 0; + while (mount != NULL) + { + level1->base.nentries++; + mount = mount->fs_next; + } + + level1->base.index = 0; + ret = OK; + } + else + { + /* Search for the requested entry */ + + str = strchr(relpath, '/'); + if (str) + { + x = str - relpath; + } + else + { + x = strlen(relpath); + } + + while (mount) + { + if (strncmp(mount->fs_blkdriver->i_name, relpath, x) == 0) + { + /* Found the mount point. Just break */ + + break; + } + + /* Try the next mount */ + + mount = mount->fs_next; + } + + if (mount) + { + /* Save the mount and skip it in the relpath */ + + ret = OK; + level1->mount = mount; + relpath += strlen(mount->fs_blkdriver->i_name); + if (relpath[0] == '/') + { + relpath++; + } + + /* Test if a level 3 directory entry being requested or not */ + + if (relpath[0] == '\0') + { + /* Requesting directory listing of a specific SMARTFS mount or entry */ + + level1->base.level = 2; + level1->base.nentries = g_direntrycount; + level1->base.index = 0; + } + else + { + /* Find the level 3 directory entry */ + + level1->base.level = 3; + level1->base.nentries = 1; + level1->base.index = 0; + level1->direntry = 0; + + while (level1->direntry < g_direntrycount) + { + /* Test if this entry matches */ + + if (strcmp(relpath, g_direntry[level1->direntry].name) == 0) + { + break; + } + + /* Advance to next entry */ + + level1->direntry++; + } + + /* Test if entry found or not */ + + if (level1->direntry == g_direntrycount) + { + ret = -ENOENT; + } + } + } + } + + return ret; +} + /**************************************************************************** * Name: smartfs_open ****************************************************************************/ @@ -161,6 +340,7 @@ static int smartfs_open(FAR struct file *filep, FAR const char *relpath, int oflags, mode_t mode) { FAR struct smartfs_file_s *priv; + int ret; fvdbg("Open '%s'\n", relpath); @@ -179,15 +359,25 @@ static int smartfs_open(FAR struct file *filep, FAR const char *relpath, /* Allocate a container to hold the task and attribute selection */ - priv = (FAR struct smartfs_file_s *)kmm_zalloc(sizeof(struct smartfs_file_s)); + priv = (FAR struct smartfs_file_s *)kmm_malloc(sizeof(struct smartfs_file_s)); if (!priv) { fdbg("ERROR: Failed to allocate file attributes\n"); return -ENOMEM; } - /* TODO: Initialize the context specific data here */ + /* Find the directory entry being opened */ + ret = smartfs_find_dirref(relpath, &priv->level1); + if (ret == -ENOENT) + { + /* Entry not found */ + + kmm_free(priv); + return ret; + } + + priv->offset = 0; /* Save the index as the open-specific state in filep->f_priv */ @@ -232,10 +422,18 @@ static ssize_t smartfs_read(FAR struct file *filep, FAR char *buffer, priv = (FAR struct smartfs_file_s *)filep->f_priv; DEBUGASSERT(priv); - /* TODO: Provide the requested data */ + /* Perform the read based on the directory entry */ ret = 0; + if (priv->level1.base.level == 3) + { + if (priv->level1.direntry < g_direntrycount) + { + ret = g_direntry[priv->level1.direntry].read(filep, buffer, buflen); + } + } + /* Update the file offset */ if (ret > 0) @@ -268,7 +466,7 @@ static int smartfs_dup(FAR const struct file *oldp, FAR struct file *newp) /* Allocate a new container to hold the task and attribute selection */ - newpriv = (FAR struct smartfs_file_s *)kmm_zalloc(sizeof(struct smartfs_file_s)); + newpriv = (FAR struct smartfs_file_s *)kmm_malloc(sizeof(struct smartfs_file_s)); if (!newpriv) { fdbg("ERROR: Failed to allocate file attributes\n"); @@ -296,16 +494,17 @@ static int smartfs_dup(FAR const struct file *oldp, FAR struct file *newp) static int smartfs_opendir(FAR const char *relpath, FAR struct fs_dirent_s *dir) { FAR struct smartfs_level1_s *level1; + int ret; fvdbg("relpath: \"%s\"\n", relpath ? relpath : "NULL"); DEBUGASSERT(relpath && dir && !dir->u.procfs); - /* The path refers to the 1st level sbdirectory. Allocate the level1 + /* The path refers to the 1st level subdirectory. Allocate the level1 * dirent structure. */ level1 = (FAR struct smartfs_level1_s *) - kmm_zalloc(sizeof(struct smartfs_level1_s)); + kmm_malloc(sizeof(struct smartfs_level1_s)); if (!level1) { @@ -313,17 +512,20 @@ static int smartfs_opendir(FAR const char *relpath, FAR struct fs_dirent_s *dir) return -ENOMEM; } - /* TODO: Initialze context specific data */ + /* Initialize base structure components */ + ret = smartfs_find_dirref(relpath, level1); - /* Initialze base structure components */ + if (ret == OK) + { + dir->u.procfs = (FAR void *) level1; + } + else + { + kmm_free(level1); + } - level1->base.level = 1; - level1->base.nentries = 0; - level1->base.index = 0; - - dir->u.procfs = (FAR void *) level1; - return OK; + return ret; } /**************************************************************************** @@ -359,17 +561,11 @@ static int smartfs_closedir(FAR struct fs_dirent_s *dir) static int smartfs_readdir(struct fs_dirent_s *dir) { FAR struct smartfs_level1_s *level1; - char filename[16]; int ret, index; DEBUGASSERT(dir && dir->u.procfs); level1 = dir->u.procfs; - /* TODO: Perform device specific readdir function here. This may - * or may not involve validating the nentries variable - * in the base depending on the implementation. - */ - /* Have we reached the end of the directory */ index = level1->base.index; @@ -383,20 +579,46 @@ static int smartfs_readdir(struct fs_dirent_s *dir) ret = -ENOENT; } - /* We are tranversing a subdirectory of task attributes */ + /* We are traversing a subdirectory of task attributes */ else { - DEBUGASSERT(level1->base.level == 1); + DEBUGASSERT(level1->base.level >= 1); - /* TODO: Add device specific entries */ + /* Test the type of directory listing */ - strcpy(filename, "dummy"); + if (level1->base.level == 1) + { + /* Listing the top level (mounted smartfs volumes) */ - /* TODO: Specify the type of entry */ + if (!level1->mount) + { + return -ENOENT; + } - dir->fd_dir.d_type = DTYPE_FILE; - strncpy(dir->fd_dir.d_name, filename, NAME_MAX+1); + dir->fd_dir.d_type = DTYPE_DIRECTORY; + strncpy(dir->fd_dir.d_name, level1->mount->fs_blkdriver->i_name, NAME_MAX+1); + + /* Advance to next entry */ + + level1->base.index++; + level1->mount = level1->mount->fs_next; + } + else if (level1->base.level == 2) + { + /* Listing the contents of a specific mount */ + + dir->fd_dir.d_type = g_direntry[level1->base.index].type; + strncpy(dir->fd_dir.d_name, g_direntry[level1->base.index++].name, NAME_MAX+1); + } + else if (level1->base.level == 3) + { + /* Listing the contents of a specific entry */ + + dir->fd_dir.d_type = g_direntry[level1->base.index].type; + strncpy(dir->fd_dir.d_name, g_direntry[level1->direntry].name, NAME_MAX+1); + level1->base.index++; + } /* Set up the next directory entry offset. NOTE that we could use the * standard f_pos instead of our own private index. @@ -435,11 +657,34 @@ static int smartfs_rewinddir(struct fs_dirent_s *dir) static int smartfs_stat(const char *relpath, struct stat *buf) { - /* TODO: Decide if the relpath is valid and if it is a file + int ret; + struct smartfs_level1_s level1; + + /* Decide if the relpath is valid and if it is a file * or a directory and set it's permissions. */ - buf->st_mode = S_IFDIR|S_IROTH|S_IRGRP|S_IRUSR; + ret = smartfs_find_dirref(relpath, &level1); + + buf->st_mode = S_IROTH|S_IRGRP|S_IRUSR; + if (ret == OK) + { + if (level1.base.level < 3) + { + buf->st_mode |= S_IFDIR; + } + else + { + if (g_direntry[level1.direntry].type == DTYPE_DIRECTORY) + { + buf->st_mode |= S_IFDIR; + } + else + { + buf->st_mode |= S_IFREG; + } + } + } /* File/directory size, access block size */ @@ -447,9 +692,246 @@ static int smartfs_stat(const char *relpath, struct stat *buf) buf->st_blksize = 0; buf->st_blocks = 0; - return OK; + return ret; } +/**************************************************************************** + * Name: smartfs_status_read + * + * Description: Performs the read operation for the "status" dir entry. + * + ****************************************************************************/ + +static size_t smartfs_status_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + struct mtd_smart_procfs_data_s procfs_data; + FAR struct smartfs_file_s *priv; + int ret; + size_t len; + int utilization; + + priv = (FAR struct smartfs_file_s *) filep->f_priv; + + + /* Initialize the read length to zero and test if we are at the + * end of the file (i.e. already read the data. + */ + + len = 0; + if (priv->offset == 0) + { + /* Get the ProcFS data from the block driver */ + + ret = priv->level1.mount->fs_blkdriver->u.i_bops->ioctl( + priv->level1.mount->fs_blkdriver, BIOC_GETPROCFSD, + (unsigned long) &procfs_data); + + if (ret == OK) + { + /* Calculate the sector utilization percentage */ + + if (procfs_data.blockerases == 0) + { + utilization = 100; + else + { + utilization = 100 * (procfs_data.blockerases * procfs_data.sectorsperblk - + procfs_data.unusedsectors) / (procfs_data.blockerases * + procfs_data.sectorsperblk); + } + + /* Format and return data in the buffer */ + + len = snprintf(buffer, buflen, "Format version: %d\nName Len: %d\n" + "Total Sectors: %d\nSector Size: %d\n" + "Format Sector: %d\nDir Sector: %d\n" + "Free Sectors: %d\nReleased Sectors: %d\n" + "Sectors Per Block: %d\n", + //"Unused Sectors: %d\nBlock Erases: %d\n" + //"Sectors Per Block: %d\nSector Utilization:%d%%\n", + procfs_data.formatversion, procfs_data.namelen, + procfs_data.totalsectors, procfs_data.sectorsize, + procfs_data.formatsector, procfs_data.dirsector, + procfs_data.freesectors, procfs_data.releasesectors, + procfs_data.sectorsperblk); + //procfs_data.unusedsectors, procfs_data.blockerases, + //procfs_data.sectorsperblk, utilization); + } + + /* Indicate we have already provided all the data */ + + priv->offset = 0xFF; + } + + return len; +} + +/**************************************************************************** + * Name: smartfs_mem_read + * + * Description: Performs the read operation for the "mem" dir entry. + * + ****************************************************************************/ + +#ifdef CONFIG_MTD_SMART_ALLOC_DEBUG +static size_t smartfs_mem_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + struct mtd_smart_procfs_data_s procfs_data; + FAR struct smartfs_file_s *priv; + int ret; + uint16_t x; + size_t len, total; + + priv = (FAR struct smartfs_file_s *) filep->f_priv; + + + /* Initialize the read length to zero and test if we are at the + * end of the file (i.e. already read the data. + */ + + len = 0; + if (priv->offset == 0) + { + /* Get the ProcFS data from the block driver */ + + ret = priv->level1.mount->fs_blkdriver->u.i_bops->ioctl( + priv->level1.mount->fs_blkdriver, BIOC_GETPROCFSD, + (unsigned long) &procfs_data); + + if (ret == OK) + { + /* Print the allocations to the buffer */ + + total = 0; + len = snprintf(buffer, buflen, "Allocations:\n"); + buflen -= len; + for (x = 0; x < procfs_data.alloccount; x++) + { + /* Only print allocations with a non-NULL pointer */ + + if (procfs_data.allocs[x].ptr != NULL) + { + len += snprintf(&buffer[len], buflen-len, " %s: %d\n", + procfs_data.allocs[x].name, procfs_data.allocs[x].size); + total += procfs_data.allocs[x].size; + } + } + + /* Add the total allocation amount to the buffer */ + + len += snprintf(&buffer[len], buflen-len, "\nTotal: %d\n", total); + } + + /* Indicate we have done the read */ + + priv->offset = 0xFF; + } + + return len; +} +#endif + +/**************************************************************************** + * Name: smartfs_erasemap_read + * + * Description: Performs the read operation for the "erase" dir entry. + * + ****************************************************************************/ + +#ifdef CONFIG_MTD_SMART_SECTOR_ERASE_DEBUG +static size_t smartfs_erasemap_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + struct mtd_smart_procfs_data_s procfs_data; + FAR struct smartfs_file_s *priv; + int ret, rows, cols; + size_t x, y; + size_t len, copylen; + + priv = (FAR struct smartfs_file_s *) filep->f_priv; + + /* Get the ProcFS data from the block driver */ + + ret = priv->level1.mount->fs_blkdriver->u.i_bops->ioctl( + priv->level1.mount->fs_blkdriver, BIOC_GETPROCFSD, + (unsigned long) &procfs_data); + if (ret != OK) + { + return 0; + } + + /* Initialize the read length to zero and test if we are at the + * end of the file (i.e. already read the data). + */ + + len = 0; + rows = 32; + cols = procfs_data.neraseblocks / rows; + while (rows >= 4 && (cols < 64 || cols > 128)) + { + rows >>= 1; + cols = procfs_data.neraseblocks / rows; + } + + /* Continue sending data until everything sent. We add 'rows' below to + * account for the \n at the end of each line. + */ + + if (priv->offset < procfs_data.neraseblocks + rows) + { + /* copylen keeps track of the current length. When it is + * equal to or greater than the offset, we start sending data + * again. Basically we are starting at the beginning each time + * and only sending where we left off and discarding the rest. + */ + + copylen = 0; + for (y = 0; y < rows; y++) + { + //for (x = 0; x < 128; x++) + for (x = 0; x < cols; x++) + { + /* Copy data to the buffer */ + + if (copylen >= priv->offset) + { + buffer[len++] = procfs_data.erasecounts[y*cols+x] + 'A'; + priv->offset++; + + if (len >= buflen) + return len; + } + copylen++; + } + + /* Add a trailing \n */ + + if (copylen >= priv->offset) + { + buffer[len++] = '\n'; + priv->offset++; + if (len >= buflen) + return len; + } + + /* Terminate the string */ + + if (copylen >= priv->offset) + { + buffer[len++] = '\0'; + priv->offset++; + } + + copylen++; + } + } + + return len; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/fs/smartfs/smartfs_utils.c b/fs/smartfs/smartfs_utils.c index d14f9d9fae..6bbd953bd7 100644 --- a/fs/smartfs/smartfs_utils.c +++ b/fs/smartfs/smartfs_utils.c @@ -1,7 +1,7 @@ /**************************************************************************** * fs/smartfs/smartfs_utils.c * - * Copyright (C) 2013 Ken Pettit. All rights reserved. + * Copyright (C) 2013-2014 Ken Pettit. All rights reserved. * Author: Ken Pettit * * Redistribution and use in source and binary forms, with or without @@ -72,7 +72,8 @@ * Private Variables ****************************************************************************/ -#ifdef CONFIG_SMARTFS_MULTI_ROOT_DIRS +#if defined(CONFIG_SMARTFS_MULTI_ROOT_DIRS) || \ + (defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS)) static struct smartfs_mountpt_s* g_mounthead = NULL; #endif @@ -226,11 +227,18 @@ int smartfs_mount(struct smartfs_mountpt_s *fs, bool writeable) fs->fs_rootsector = SMARTFS_ROOT_DIR_SECTOR + fs->fs_llformat.rootdirnum; -#else +#else /* CONFIG_SMARTFS_MULTI_ROOT_DIRS */ +#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS) + /* Now add ourselves to the linked list of SMART mounts */ + + fs->fs_next = g_mounthead; + g_mounthead = fs; +#endif + fs->fs_rwbuffer = (char *) kmm_malloc(fs->fs_llformat.availbytes); fs->fs_workbuffer = (char *) kmm_malloc(256); fs->fs_rootsector = SMARTFS_ROOT_DIR_SECTOR; -#endif +#endif /* CONFIG_SMARTFS_MULTI_ROOT_DIRS */ /* We did it! */ @@ -267,14 +275,16 @@ int smartfs_unmount(struct smartfs_mountpt_s *fs) { int ret = OK; struct inode *inode; -#ifdef CONFIG_SMARTFS_MULTI_ROOT_DIRS +#if defined(CONFIG_SMARTFS_MULTI_ROOT_DIRS) || \ + (defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS)) struct smartfs_mountpt_s *nextfs; struct smartfs_mountpt_s *prevfs; int count = 0; int found = FALSE; #endif -#ifdef CONFIG_SMARTFS_MULTI_ROOT_DIRS +#if defined(CONFIG_SMARTFS_MULTI_ROOT_DIRS) || \ + (defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS)) /* Start at the head of the mounts and search for our entry. Also * count the number of entries that match our blkdriver. */ @@ -392,7 +402,7 @@ int smartfs_unmount(struct smartfs_mountpt_s *fs) * If found, the direntry will be populated with information * for accessing the entry. * - * If the final directory segement of relpath just before the + * If the final directory segment of relpath just before the * last segment (the target file/dir) is valid, then the * parentdirsector will indicate the logical sector number of * the parent directory where a new entry should be created, @@ -582,7 +592,7 @@ int smartfs_finddirentry(struct smartfs_mountpt_s *fs, direntry->datlen = 0; /* Scan the file's sectors to calculate the length and perform - * a rudamentary check. + * a rudimentary check. */ if ((entry->flags & SMARTFS_DIRENT_TYPE) == SMARTFS_DIRENT_TYPE_FILE) @@ -954,8 +964,8 @@ int smartfs_deleteentry(struct smartfs_mountpt_s *fs, * TODO: We really should walk the list backward to avoid lost * sectors in the event we lose power. However this requires - * allocting a buffer to build the sector list since we don't - * store a doubly-linked list of sectors on the deivce. We + * allocating a buffer to build the sector list since we don't + * store a doubly-linked list of sectors on the device. We * could test if the sector data buffer is big enough and * just use that, and only allocate a new buffer if the * sector buffer isn't big enough. Do do this, however, we @@ -1294,3 +1304,17 @@ int smartfs_truncatefile(struct smartfs_mountpt_s *fs, errout: return ret; } + +/**************************************************************************** + * Name: smartfs_get_first_mount + * + * Description: Returns a pointer to the first mounted smartfs volume. + * + ****************************************************************************/ + +#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_SMARTFS) +struct smartfs_mountpt_s* smartfs_get_first_mount(void) +{ + return g_mounthead; +} +#endif diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h index 1d8e32920c..0d9f594a1c 100644 --- a/include/nuttx/fs/ioctl.h +++ b/include/nuttx/fs/ioctl.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/fs/ioctl.h * - * Copyright (C) 2008, 2009, 2011-2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2008, 2009, 2011-2014 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -196,6 +196,13 @@ * buffer address * OUT: None (ioctl return value provides * success/failure indication). */ +#define BIOC_GETPROCFSD _BIOC(0x000A) /* Get ProcFS data specific to the + * block device. + * IN: Pointer to a struct defined for + * the block to load with it's + * ProcFS data. + * OUT: None (ioctl return value provides + * success/failure indication). */ /* NuttX MTD driver ioctl definitions ***************************************/ diff --git a/include/nuttx/mtd/smart.h b/include/nuttx/mtd/smart.h new file mode 100644 index 0000000000..b2239b99e8 --- /dev/null +++ b/include/nuttx/mtd/smart.h @@ -0,0 +1,104 @@ +/**************************************************************************** + * include/nuttx/mtd/smart.h + * Memory Technology Device (MTD) SMART specific interfaces + * + * Copyright (C) 2014 Ken Pettit. All rights reserved. + * Author: Ken Pettit + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_MTD_SMART_H +#define __INCLUDE_NUTTX_MTD_SMART_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Structure to track SMART allocations for debugging */ + +#ifdef CONFIG_MTD_SMART_ALLOC_DEBUG +struct smart_alloc_s +{ + size_t size; /* Size of the allocation */ + void* ptr; /* Pointer to the data */ + const char* name; /* Name of the allocation */ +}; +#endif + +/* The following defines the procfs data passed from the SMART MTD layer + * from a BIOC_GETPROCFSD ioctl command. + */ + +struct mtd_smart_procfs_data_s +{ + uint16_t totalsectors; /* Total number of sectors on device */ + uint16_t sectorsize; /* Size of each sector */ + uint16_t freesectors; /* Number of free sectors */ + uint16_t releasesectors; /* Number of released sectors */ + uint16_t sectorsperblk; /* Number of sectors per erase block */ + uint16_t formatsector; /* Physical sector number for sector 0 */ + uint16_t dirsector; /* Physical sector number for sector 1 */ + uint8_t namelen; /* Length of names on the volume */ + uint8_t formatversion; /* Version of the volume format */ + uint32_t unusedsectors; /* Number of unused sectors (free when erased) */ + uint32_t blockerases; /* Number block erase operations */ + +#ifdef CONFIG_MTD_SMART_SECTOR_ERASE_DEBUG + FAR const uint8_t* erasecounts; /* Array of erase counts per erase block */ + size_t neraseblocks; /* Number of erase blocks */ +#endif +#ifdef CONFIG_MTD_SMART_ALLOC_DEBUG + FAR const struct smart_alloc_s *allocs; /* Array of allocations */ + uint16_t alloccount; /* Number of items in the array */ +#endif +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#endif /* __INCLUDE_NUTTX_MTD_SMART_H */