* [PATCH 1/4] fs: Introduce discard_range()
@ 2020-02-14 11:16 Sascha Hauer
2020-02-14 11:16 ` [PATCH 2/4] cdev: Add discard_range hook Sascha Hauer
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Sascha Hauer @ 2020-02-14 11:16 UTC (permalink / raw)
To: Barebox List
discard_range() is a way to tell the lower layers that we are no longer
interested in a data range of a file, so that the lower layers can
discard the underlying data if desired.
This is mainly designed to bypass the deficiencies of our block layer.
We cache the block data in chunks of multiple KiB (16 currently) if
we fall into the block layer with write requests smaller than that
we have to read/modify/write a chunk. With the help of discard_range()
code writing files to a raw block device can now discard the range the
file will be written to. The block layer then no longer has to read
the chunks first that are inside the discard range.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
fs/fs.c | 25 +++++++++++++++++++++++++
include/fs.h | 3 +++
2 files changed, 28 insertions(+)
diff --git a/fs/fs.c b/fs/fs.c
index 12faaebc27..e00bbcd223 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -497,6 +497,31 @@ int protect(int fd, size_t count, loff_t offset, int prot)
}
EXPORT_SYMBOL(protect);
+int discard_range(int fd, loff_t count, loff_t offset)
+{
+ struct fs_driver_d *fsdrv;
+ FILE *f = fd_to_file(fd);
+ int ret;
+
+ if (IS_ERR(f))
+ return -errno;
+ if (offset >= f->size)
+ return 0;
+ if (count > f->size - offset)
+ count = f->size - offset;
+
+ fsdrv = f->fsdev->driver;
+ if (fsdrv->discard_range)
+ ret = fsdrv->discard_range(&f->fsdev->dev, f, count, offset);
+ else
+ ret = -ENOSYS;
+
+ if (ret)
+ errno = -ret;
+
+ return ret;
+}
+
int protect_file(const char *file, int prot)
{
int fd, ret;
diff --git a/include/fs.h b/include/fs.h
index 38debfc41b..d9684c82b1 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -60,6 +60,8 @@ struct fs_driver_d {
loff_t offset);
int (*protect)(struct device_d *dev, FILE *f, size_t count,
loff_t offset, int prot);
+ int (*discard_range)(struct device_d *dev, FILE *f, loff_t count,
+ loff_t offset);
int (*memmap)(struct device_d *dev, FILE *f, void **map, int flags);
@@ -127,6 +129,7 @@ int umount_by_cdev(struct cdev *cdev);
#define ERASE_SIZE_ALL ((loff_t) - 1)
int erase(int fd, loff_t count, loff_t offset);
int protect(int fd, size_t count, loff_t offset, int prot);
+int discard_range(int fd, loff_t count, loff_t offset);
int protect_file(const char *file, int prot);
void *memmap(int fd, int flags);
--
2.25.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/4] cdev: Add discard_range hook
2020-02-14 11:16 [PATCH 1/4] fs: Introduce discard_range() Sascha Hauer
@ 2020-02-14 11:16 ` Sascha Hauer
2020-02-14 11:16 ` [PATCH 3/4] block: Implement discard_range Sascha Hauer
2020-02-14 11:16 ` [PATCH 4/4] copy_file: call discard_range on destination file Sascha Hauer
2 siblings, 0 replies; 5+ messages in thread
From: Sascha Hauer @ 2020-02-14 11:16 UTC (permalink / raw)
To: Barebox List
To pass though discard_range() to the underlying drivers add a
discard_range hook to struct cdev_operations.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
fs/devfs.c | 21 +++++++++++++++++++++
include/driver.h | 1 +
2 files changed, 22 insertions(+)
diff --git a/fs/devfs.c b/fs/devfs.c
index d088c1a66c..e1893d1bd0 100644
--- a/fs/devfs.c
+++ b/fs/devfs.c
@@ -94,6 +94,26 @@ static int devfs_protect(struct device_d *_dev, FILE *f, size_t count, loff_t of
return cdev->ops->protect(cdev, count, offset + cdev->offset, prot);
}
+static int devfs_discard_range(struct device_d *dev, FILE *f, loff_t count,
+ loff_t offset)
+{
+ struct cdev *cdev = f->priv;
+
+ if (!cdev->ops->discard_range)
+ return -ENOSYS;
+
+ if (cdev->flags & DEVFS_PARTITION_READONLY)
+ return -EPERM;
+
+ if (offset >= cdev->size)
+ return 0;
+
+ if (count + offset > cdev->size)
+ count = cdev->size - offset;
+
+ return cdev->ops->discard_range(cdev, count, offset + cdev->offset);
+}
+
static int devfs_memmap(struct device_d *_dev, FILE *f, void **map, int flags)
{
struct cdev *cdev = f->priv;
@@ -329,6 +349,7 @@ static struct fs_driver_d devfs_driver = {
.truncate = devfs_truncate,
.erase = devfs_erase,
.protect = devfs_protect,
+ .discard_range = devfs_discard_range,
.memmap = devfs_memmap,
.flags = FS_DRIVER_NO_DEV,
.drv = {
diff --git a/include/driver.h b/include/driver.h
index 74be1b3e8e..c9ad95fd40 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -441,6 +441,7 @@ struct cdev_operations {
int (*flush)(struct cdev*);
int (*erase)(struct cdev*, loff_t count, loff_t offset);
int (*protect)(struct cdev*, size_t count, loff_t offset, int prot);
+ int (*discard_range)(struct cdev*, loff_t count, loff_t offset);
int (*memmap)(struct cdev*, void **map, int flags);
int (*truncate)(struct cdev*, size_t size);
};
--
2.25.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 3/4] block: Implement discard_range
2020-02-14 11:16 [PATCH 1/4] fs: Introduce discard_range() Sascha Hauer
2020-02-14 11:16 ` [PATCH 2/4] cdev: Add discard_range hook Sascha Hauer
@ 2020-02-14 11:16 ` Sascha Hauer
2020-02-14 11:16 ` [PATCH 4/4] copy_file: call discard_range on destination file Sascha Hauer
2 siblings, 0 replies; 5+ messages in thread
From: Sascha Hauer @ 2020-02-14 11:16 UTC (permalink / raw)
To: Barebox List
This implements the discard_range hook. When a range of data is
discarded then we do not have to read it from the device and can
pass a zeroed buffer instead.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
common/block.c | 21 +++++++++++++++++++++
include/block.h | 3 +++
2 files changed, 24 insertions(+)
diff --git a/common/block.c b/common/block.c
index 97cf5dc4de..8b43c3c83a 100644
--- a/common/block.c
+++ b/common/block.c
@@ -161,6 +161,14 @@ static int block_cache(struct block_device *blk, int block)
dev_dbg(blk->dev, "%s: %d to %d\n", __func__, chunk->block_start,
chunk->num);
+ if (chunk->block_start * BLOCKSIZE(blk) >= blk->discard_start &&
+ chunk->block_start * BLOCKSIZE(blk) + writebuffer_io_len(blk, chunk)
+ <= blk->discard_start + blk->discard_size) {
+ memset(chunk->data, 0, writebuffer_io_len(blk, chunk));
+ list_add(&chunk->list, &blk->buffered_blocks);
+ return 0;
+ }
+
ret = blk->ops->read(blk, chunk->data, chunk->block_start,
writebuffer_io_len(blk, chunk));
if (ret) {
@@ -337,11 +345,23 @@ static int block_op_flush(struct cdev *cdev)
{
struct block_device *blk = cdev->priv;
+ blk->discard_start = blk->discard_size = 0;
+
return writebuffer_flush(blk);
}
static int block_op_close(struct cdev *cdev) __alias(block_op_flush);
+static int block_op_discard_range(struct cdev *cdev, loff_t count, loff_t offset)
+{
+ struct block_device *blk = cdev->priv;
+
+ blk->discard_start = offset;
+ blk->discard_size = count;
+
+ return 0;
+}
+
static struct cdev_operations block_ops = {
.read = block_op_read,
#ifdef CONFIG_BLOCK_WRITE
@@ -349,6 +369,7 @@ static struct cdev_operations block_ops = {
#endif
.close = block_op_close,
.flush = block_op_flush,
+ .discard_range = block_op_discard_range,
};
int blockdevice_register(struct block_device *blk)
diff --git a/include/block.h b/include/block.h
index 91377679b0..d35c4ecdf4 100644
--- a/include/block.h
+++ b/include/block.h
@@ -23,6 +23,9 @@ struct block_device {
int rdbufsize;
int blkmask;
+ loff_t discard_start;
+ loff_t discard_size;
+
struct list_head buffered_blocks;
struct list_head idle_blocks;
--
2.25.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 4/4] copy_file: call discard_range on destination file
2020-02-14 11:16 [PATCH 1/4] fs: Introduce discard_range() Sascha Hauer
2020-02-14 11:16 ` [PATCH 2/4] cdev: Add discard_range hook Sascha Hauer
2020-02-14 11:16 ` [PATCH 3/4] block: Implement discard_range Sascha Hauer
@ 2020-02-14 11:16 ` Sascha Hauer
2 siblings, 0 replies; 5+ messages in thread
From: Sascha Hauer @ 2020-02-14 11:16 UTC (permalink / raw)
To: Barebox List
discard the range in the output file we are going to overwrite anyway.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
lib/libfile.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/libfile.c b/lib/libfile.c
index 5a1817e32a..dbeed12ccd 100644
--- a/lib/libfile.c
+++ b/lib/libfile.c
@@ -367,6 +367,8 @@ int copy_file(const char *src, const char *dst, int verbose)
goto out;
}
+ discard_range(dstfd, srcstat.st_size, 0);
+
if (verbose) {
if (stat(src, &srcstat) < 0)
srcstat.st_size = 0;
--
2.25.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 0/4] add discard_range to improve write speed on block devices
@ 2019-12-13 13:20 Sascha Hauer
2019-12-13 13:20 ` [PATCH 1/4] fs: Introduce discard_range() Sascha Hauer
0 siblings, 1 reply; 5+ messages in thread
From: Sascha Hauer @ 2019-12-13 13:20 UTC (permalink / raw)
To: Barebox List
This implements an idea Lucas came up with: Our block layer is quite
stupid. It works on chunks from which one is currently 16KiB in size.
Whenever such a chunk is written to we must write the whole chunk which
also means we have to read it from the device first in order to keep
unaffected data. This series adds a discard_range() function which
can be used to tell the block layer that a certain range of the device
will be overwritten and the current content is no longer needed and
thus doesn't have to be read. With this I saw a speed gain of around
30% when writing to a SD card.
This series still needs a closer look before I want to merge it, but
it's already worth being looked at ;)
Sascha
Sascha Hauer (4):
fs: Introduce discard_range()
cdev: Add discard_range hook
block: Implement discard_range
copy_file: call discard_range on destination file
common/block.c | 21 +++++++++++++++++++++
fs/devfs.c | 21 +++++++++++++++++++++
fs/fs.c | 25 +++++++++++++++++++++++++
include/block.h | 3 +++
include/driver.h | 1 +
include/fs.h | 3 +++
lib/libfile.c | 2 ++
7 files changed, 76 insertions(+)
--
2.24.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/4] fs: Introduce discard_range()
2019-12-13 13:20 [PATCH 0/4] add discard_range to improve write speed on block devices Sascha Hauer
@ 2019-12-13 13:20 ` Sascha Hauer
0 siblings, 0 replies; 5+ messages in thread
From: Sascha Hauer @ 2019-12-13 13:20 UTC (permalink / raw)
To: Barebox List
discard_range() is a way to tell the lower layers that we are no longer
interested in a data range of a file, so that the lower layers can
discard the underlying data if desired.
This is mainly designed to bypass the deficiencies of our block layer.
We cache the block data in chunks of multiple KiB (16 currently) if
we fall into the block layer with write requests smaller than that
we have to read/modify/write a chunk. With the help of discard_range()
code writing files to a raw block device can now discard the range the
file will be written to. The block layer then no longer has to read
the chunks first that are inside the discard range.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
fs/fs.c | 25 +++++++++++++++++++++++++
include/fs.h | 3 +++
2 files changed, 28 insertions(+)
diff --git a/fs/fs.c b/fs/fs.c
index 12faaebc27..e00bbcd223 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -497,6 +497,31 @@ int protect(int fd, size_t count, loff_t offset, int prot)
}
EXPORT_SYMBOL(protect);
+int discard_range(int fd, loff_t count, loff_t offset)
+{
+ struct fs_driver_d *fsdrv;
+ FILE *f = fd_to_file(fd);
+ int ret;
+
+ if (IS_ERR(f))
+ return -errno;
+ if (offset >= f->size)
+ return 0;
+ if (count > f->size - offset)
+ count = f->size - offset;
+
+ fsdrv = f->fsdev->driver;
+ if (fsdrv->discard_range)
+ ret = fsdrv->discard_range(&f->fsdev->dev, f, count, offset);
+ else
+ ret = -ENOSYS;
+
+ if (ret)
+ errno = -ret;
+
+ return ret;
+}
+
int protect_file(const char *file, int prot)
{
int fd, ret;
diff --git a/include/fs.h b/include/fs.h
index 38debfc41b..d9684c82b1 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -60,6 +60,8 @@ struct fs_driver_d {
loff_t offset);
int (*protect)(struct device_d *dev, FILE *f, size_t count,
loff_t offset, int prot);
+ int (*discard_range)(struct device_d *dev, FILE *f, loff_t count,
+ loff_t offset);
int (*memmap)(struct device_d *dev, FILE *f, void **map, int flags);
@@ -127,6 +129,7 @@ int umount_by_cdev(struct cdev *cdev);
#define ERASE_SIZE_ALL ((loff_t) - 1)
int erase(int fd, loff_t count, loff_t offset);
int protect(int fd, size_t count, loff_t offset, int prot);
+int discard_range(int fd, loff_t count, loff_t offset);
int protect_file(const char *file, int prot);
void *memmap(int fd, int flags);
--
2.24.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2020-02-14 11:16 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-14 11:16 [PATCH 1/4] fs: Introduce discard_range() Sascha Hauer
2020-02-14 11:16 ` [PATCH 2/4] cdev: Add discard_range hook Sascha Hauer
2020-02-14 11:16 ` [PATCH 3/4] block: Implement discard_range Sascha Hauer
2020-02-14 11:16 ` [PATCH 4/4] copy_file: call discard_range on destination file Sascha Hauer
-- strict thread matches above, loose matches on Subject: below --
2019-12-13 13:20 [PATCH 0/4] add discard_range to improve write speed on block devices Sascha Hauer
2019-12-13 13:20 ` [PATCH 1/4] fs: Introduce discard_range() Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox