diff --git a/drivers/bch/bchdev_register.c b/drivers/bch/bchdev_register.c index 849f0e47577..5e9390273bb 100644 --- a/drivers/bch/bchdev_register.c +++ b/drivers/bch/bchdev_register.c @@ -50,17 +50,17 @@ ****************************************************************************/ int bchdev_register(FAR const char *blkdev, FAR const char *chardev, - bool readonly) + int oflags) { FAR void *handle; int ret; - finfo("blkdev=\"%s\" chardev=\"%s\" readonly=%c\n", - blkdev, chardev, readonly ? 'T' : 'F'); + finfo("blkdev=\"%s\" chardev=\"%s\" oflags=0x%x\n", + blkdev, chardev, oflags); /* Setup the BCH lib functions */ - ret = bchlib_setup(blkdev, readonly, &handle); + ret = bchlib_setup(blkdev, oflags, &handle); if (ret < 0) { ferr("ERROR: bchlib_setup failed: %d\n", -ret); diff --git a/drivers/bch/bchlib_setup.c b/drivers/bch/bchlib_setup.c index a78f2329ec5..7030699db24 100644 --- a/drivers/bch/bchlib_setup.c +++ b/drivers/bch/bchlib_setup.c @@ -55,10 +55,11 @@ * ****************************************************************************/ -int bchlib_setup(FAR const char *blkdev, bool readonly, FAR void **handle) +int bchlib_setup(FAR const char *blkdev, int oflags, FAR void **handle) { FAR struct bchlib_s *bch; struct geometry geo; + bool readonly = (oflags & O_WROK) == 0; int ret; DEBUGASSERT(blkdev); @@ -74,7 +75,7 @@ int bchlib_setup(FAR const char *blkdev, bool readonly, FAR void **handle) /* Open the block driver */ - ret = open_blockdriver(blkdev, readonly ? MS_RDONLY : 0, &bch->inode); + ret = open_blockdriver(blkdev, oflags, &bch->inode); if (ret < 0) { ferr("ERROR: Failed to open driver %s: %d\n", blkdev, -ret); diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 51c0f63736c..ace0eeb2c53 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -77,6 +78,7 @@ struct ftl_struct_s uint16_t refs; /* Number of references */ bool unlinked; /* The driver has been unlinked */ FAR uint8_t *eblock; /* One, in-memory erase block */ + int oflags; /* The nand block map between logic block and physical block */ @@ -96,6 +98,9 @@ static ssize_t ftl_read(FAR struct inode *inode, FAR unsigned char *buffer, blkcnt_t start_sector, unsigned int nsectors); static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t *buffer, off_t startblock, size_t nblocks); +static ssize_t ftl_flush_direct(FAR struct ftl_struct_s *dev, + FAR const uint8_t *buffer, + off_t startblock, size_t nblocks); static ssize_t ftl_write(FAR struct inode *inode, FAR const unsigned char *buffer, blkcnt_t start_sector, unsigned int nsectors); @@ -474,6 +479,74 @@ static int ftl_alloc_eblock(FAR struct ftl_struct_s *dev) return dev->eblock != NULL ? OK : -ENOMEM; } +/**************************************************************************** + * Name: ftl_flush_direct + * + * Description: Write the specified number of sectors without cache + * + ****************************************************************************/ + +static ssize_t ftl_flush_direct(FAR struct ftl_struct_s *dev, + FAR const uint8_t *buffer, + off_t startblock, size_t nblocks) +{ + size_t blocksize = dev->geo.blocksize; + off_t starteraseblock; + off_t offset; + ssize_t ret; + size_t count; + + while (nblocks) + { + starteraseblock = startblock / dev->blkper; + offset = startblock & (dev->blkper - 1); + count = MIN(dev->blkper - offset, nblocks); + + if (offset == 0 && dev->mtd->erase != NULL && !(dev->oflags & O_SYNC)) + { + ret = ftl_mtd_erase(dev, starteraseblock); + if (ret < 0) + { + return ret; + } + } + + if (dev->lptable == NULL) + { + ret = MTD_BWRITE(dev->mtd, startblock, count, buffer); + if (ret != count) + { + ferr("ERROR: Write block %"PRIdOFF" failed: %zd\n", + startblock, ret); + return ret; + } + } + else + { + if (starteraseblock >= dev->lpcount) + { + return -ENOSPC; + } + + ret = MTD_BWRITE(dev->mtd, + dev->lptable[starteraseblock] * dev->blkper + + offset, count, buffer); + if (ret != count) + { + MTD_MARKBAD(dev->mtd, dev->lptable[starteraseblock]); + ftl_update_map(dev, starteraseblock); + continue; + } + } + + nblocks -= count; + startblock += count; + buffer += count * blocksize; + } + + return nblocks; +} + static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t *buffer, off_t startblock, size_t nblocks) { @@ -488,6 +561,13 @@ static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t *buffer, int nbytes; int ret; + if (dev->oflags & O_DIRECT) + { + /* Direct write mode */ + + return ftl_flush_direct(dev, buffer, startblock, nblocks); + } + /* Get the aligned block. Here is is assumed: (1) The number of R/W blocks * per erase block is a power of 2, and (2) the erase begins with that same * alignment. @@ -803,7 +883,8 @@ static int ftl_unlink(FAR struct inode *inode) * ****************************************************************************/ -int ftl_initialize_by_path(FAR const char *path, FAR struct mtd_dev_s *mtd) +int ftl_initialize_by_path(FAR const char *path, FAR struct mtd_dev_s *mtd, + int oflags) { struct ftl_struct_s *dev; int ret = -ENOMEM; @@ -825,6 +906,7 @@ int ftl_initialize_by_path(FAR const char *path, FAR struct mtd_dev_s *mtd) /* Initialize the FTL device structure */ dev->mtd = mtd; + dev->oflags = oflags; /* Get the device geometry. (casting to uintptr_t first eliminates * complaints on some architectures where the sizeof long is different @@ -928,5 +1010,5 @@ int ftl_initialize(int minor, FAR struct mtd_dev_s *mtd) /* Do the real work by ftl_initialize_by_path */ snprintf(path, DEV_NAME_MAX, "/dev/mtdblock%d", minor); - return ftl_initialize_by_path(path, mtd); + return ftl_initialize_by_path(path, mtd, O_RDWR); } diff --git a/fs/driver/fs_blockproxy.c b/fs/driver/fs_blockproxy.c index 77eae6476a3..5e2858a1155 100644 --- a/fs/driver/fs_blockproxy.c +++ b/fs/driver/fs_blockproxy.c @@ -149,7 +149,6 @@ int block_proxy(FAR struct file *filep, FAR const char *blkdev, int oflags) { struct file temp; FAR char *chardev; - bool readonly; int ret; DEBUGASSERT(blkdev); @@ -163,13 +162,9 @@ int block_proxy(FAR struct file *filep, FAR const char *blkdev, int oflags) return -ENOMEM; } - /* Should this character driver be read-only? */ - - readonly = ((oflags & O_WROK) == 0); - /* Wrap the block driver with an instance of the BCH driver */ - ret = bchdev_register(blkdev, chardev, readonly); + ret = bchdev_register(blkdev, chardev, oflags); if (ret < 0) { ferr("ERROR: bchdev_register(%s, %s) failed: %d\n", diff --git a/fs/driver/fs_mtdproxy.c b/fs/driver/fs_mtdproxy.c index 659cbb6c403..44f9bc84e51 100644 --- a/fs/driver/fs_mtdproxy.c +++ b/fs/driver/fs_mtdproxy.c @@ -165,7 +165,7 @@ int mtd_proxy(FAR const char *mtddev, int mountflags, goto out_with_blkdev; } - ret = ftl_initialize_by_path(blkdev, mtd->u.i_mtd); + ret = ftl_initialize_by_path(blkdev, mtd->u.i_mtd, mountflags); inode_release(mtd); if (ret < 0) { diff --git a/fs/vfs/fs_open.c b/fs/vfs/fs_open.c index 8cf86b964d6..84fd3f251bc 100644 --- a/fs/vfs/fs_open.c +++ b/fs/vfs/fs_open.c @@ -202,10 +202,11 @@ static int file_vopen(FAR struct file *filep, FAR const char *path, /* Get the file structure of the opened character driver proxy */ #ifdef CONFIG_BCH_DEVICE_READONLY - ret = block_proxy(filep, path, O_RDOK); -#else - ret = block_proxy(filep, path, oflags); + oflags &= ~O_RDWR; + oflags |= O_RDOK; #endif + + ret = block_proxy(filep, path, oflags); #ifdef CONFIG_FS_NOTIFY if (ret >= 0) { diff --git a/include/fcntl.h b/include/fcntl.h index 4acbb64efba..5be8390ecec 100644 --- a/include/fcntl.h +++ b/include/fcntl.h @@ -38,26 +38,32 @@ /* open flag settings for open() (and related APIs) */ -#define O_RDONLY (1 << 0) /* Open for read access (only) */ -#define O_RDOK O_RDONLY /* Read access is permitted (non-standard) */ -#define O_WRONLY (1 << 1) /* Open for write access (only) */ -#define O_WROK O_WRONLY /* Write access is permitted (non-standard) */ -#define O_RDWR (O_RDOK|O_WROK) /* Open for both read & write access */ -#define O_CREAT (1 << 2) /* Create file/sem/mq object */ -#define O_EXCL (1 << 3) /* Name must not exist when opened */ -#define O_APPEND (1 << 4) /* Keep contents, append to end */ -#define O_TRUNC (1 << 5) /* Delete contents */ -#define O_NONBLOCK (1 << 6) /* Don't wait for data */ -#define O_NDELAY O_NONBLOCK /* Synonym for O_NONBLOCK */ -#define O_SYNC (1 << 7) /* Synchronize output on write */ -#define O_DSYNC O_SYNC /* Equivalent to OSYNC in NuttX */ -#define O_TEXT (1 << 8) /* Open the file in text (translated) mode. */ -#define O_DIRECT (1 << 9) /* Avoid caching, write directly to hardware */ -#define O_CLOEXEC (1 << 10) /* Close on execute */ -#define O_DIRECTORY (1 << 11) /* Must be a directory */ -#define O_NOFOLLOW (1 << 12) /* Don't follow links */ -#define O_LARGEFILE (1 << 13) /* Large File */ -#define O_NOATIME (1 << 18) /* Don't update the file last access time */ +#define O_RDONLY (1 << 0) /* Open for read access (only) */ +#define O_RDOK O_RDONLY /* Read access is permitted (non-standard) */ +#define O_WRONLY (1 << 1) /* Open for write access (only) */ +#define O_WROK O_WRONLY /* Write access is permitted (non-standard) */ +#define O_RDWR (O_RDOK|O_WROK) /* Open for both read & write access */ +#define O_CREAT (1 << 2) /* Create file/sem/mq object */ +#define O_EXCL (1 << 3) /* Name must not exist when opened */ +#define O_APPEND (1 << 4) /* Keep contents, append to end */ +#define O_TRUNC (1 << 5) /* Delete contents */ +#define O_NONBLOCK (1 << 6) /* Don't wait for data */ +#define O_NDELAY O_NONBLOCK /* Synonym for O_NONBLOCK */ +#define O_SYNC (1 << 7) /* Synchronize output on write */ +#define O_DSYNC O_SYNC /* Equivalent to OSYNC in NuttX */ +#define O_TEXT (1 << 8) /* Open the file in text (translated) mode. */ +#define O_DIRECT (1 << 9) /* Avoid caching, write directly to hardware */ +#define O_CLOEXEC (1 << 10) /* Close on execute */ +#define O_DIRECTORY (1 << 11) /* Must be a directory */ +#define O_NOFOLLOW (1 << 12) /* Don't follow links */ +#define O_LARGEFILE (1 << 13) /* Large File */ +#define O_RESERVE14 (1 << 14) /* reserved and used by mount flag : MS_NOSUID in mount.h */ +#define O_RESERVE15 (1 << 15) /* reserved and used by mount flag : MS_NODEV in mount.h */ +#define O_RESERVE16 (1 << 16) /* reserved and used by mount flag : MS_DIRSYNC in mount.h */ +#define O_RESERVE17 (1 << 17) /* reserved and used by mount flag : MS_REMOUNT in mount.h */ +#define O_NOATIME (1 << 18) /* Don't update the file last access time */ +#define O_RESERVE19 (1 << 19) /* reserved and used by mount flag : MS_MANDLOCK in mount.h */ +#define O_RESERVE20 (1 << 20) /* reserved and used by mount flag : MS_NOEXEC in mount.h */ /* Unsupported, but required open flags */ diff --git a/include/nuttx/drivers/drivers.h b/include/nuttx/drivers/drivers.h index 672242691bd..07c9b005030 100644 --- a/include/nuttx/drivers/drivers.h +++ b/include/nuttx/drivers/drivers.h @@ -184,7 +184,7 @@ void devzero_register(void); ****************************************************************************/ int bchdev_register(FAR const char *blkdev, FAR const char *chardev, - bool readonly); + int oflags); /**************************************************************************** * Name: bchdev_unregister @@ -211,7 +211,7 @@ int bchdev_unregister(FAR const char *chardev); * ****************************************************************************/ -int bchlib_setup(FAR const char *blkdev, bool readonly, FAR void **handle); +int bchlib_setup(FAR const char *blkdev, int oflags, FAR void **handle); /**************************************************************************** * Name: bchlib_teardown diff --git a/include/nuttx/mtd/mtd.h b/include/nuttx/mtd/mtd.h index 171f2e583bf..a1c791dbf50 100644 --- a/include/nuttx/mtd/mtd.h +++ b/include/nuttx/mtd/mtd.h @@ -298,10 +298,25 @@ FAR struct mtd_dev_s *mtd_rwb_initialize(FAR struct mtd_dev_s *mtd); * Input Parameters: * path - The block device path. * mtd - The MTD device that supports the FLASH interface. + * oflags - oflags passed to the ftl layer. Currently, the ftl is affected + * by two oflags: + * 1. O_DIRECT when this flag is passed in, ftl internally uses + * the direct write strategy and no read cache is used in ftl; + * otherwise, each write will be executed with the minimum + * granularity of flash erase sector size which means a + * "sector read back - erase sector - write sector" operation + * is performed by using a read cache buffer in heap. + * + * 2. O_SYNC, when this flag is passed in, we assume that the + * flash has been erased in advance and no erase operation + * will be performed internally within ftl. O_SYNC will take + * effect only when both O_DIRECT and O_SYNC are passed in + * simultaneously * ****************************************************************************/ -int ftl_initialize_by_path(FAR const char *path, FAR struct mtd_dev_s *mtd); +int ftl_initialize_by_path(FAR const char *path, FAR struct mtd_dev_s *mtd, + int oflags); /**************************************************************************** * Name: ftl_initialize @@ -313,7 +328,6 @@ int ftl_initialize_by_path(FAR const char *path, FAR struct mtd_dev_s *mtd); * 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. - * ****************************************************************************/ int ftl_initialize(int minor, FAR struct mtd_dev_s *mtd); diff --git a/include/sys/mount.h b/include/sys/mount.h index 9a1bb82874d..a4e6712aad5 100644 --- a/include/sys/mount.h +++ b/include/sys/mount.h @@ -29,6 +29,7 @@ #include #include +#include /**************************************************************************** * Pre-processor Definitions @@ -39,16 +40,16 @@ /* Mount flags */ -#define MS_RDONLY 1 /* Mount file system read-only */ -#define MS_NOSUID 2 /* Ignore suid and sgid bits */ -#define MS_NODEV 4 /* Disallow access to device special files */ -#define MS_NOEXEC 8 /* Disallow program execution */ -#define MS_SYNCHRONOUS 16 /* Writes are synced at once */ -#define MS_REMOUNT 32 /* Alter flags of a mounted FS */ -#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */ -#define MS_DIRSYNC 128 /* Directory modifications are synchronous */ -#define MS_NOSYMFOLLOW 256 /* Do not follow symlinks */ -#define MS_NOATIME 1024 /* Do not update access times. */ +#define MS_RDONLY O_RDONLY /* Mount file system read-only */ +#define MS_SYNCHRONOUS O_SYNC /* Writes are synced at once */ +#define MS_NOSYMFOLLOW O_NOFOLLOW /* Do not follow symlinks */ +#define MS_NOATIME O_NOATIME /* Do not update access times. */ +#define MS_NOSUID O_RESERVE14 /* Ignore suid and sgid bits */ +#define MS_NODEV O_RESERVE15 /* Disallow access to device special files */ +#define MS_DIRSYNC O_RESERVE16 /* Directory modifications are synchronous */ +#define MS_REMOUNT O_RESERVE17 /* Alter flags of a mounted FS */ +#define MS_MANDLOCK O_RESERVE19 /* Allow mandatory locks on an FS */ +#define MS_NOEXEC O_RESERVE20 /* Disallow program execution */ /* Un-mount flags *