diff --git a/common/block.c b/common/block.c index 97cf5dc..02be80d 100644 --- a/common/block.c +++ b/common/block.c @@ -36,7 +36,7 @@ struct list_head list; }; -#define BUFSIZE (PAGE_SIZE * 4) +#define BUFSIZE (PAGE_SIZE * 16) static int writebuffer_io_len(struct block_device *blk, struct chunk *chunk) { @@ -161,6 +161,14 @@ 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 @@ { 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 @@ #endif .close = block_op_close, .flush = block_op_flush, + .discard_range = block_op_discard_range, }; int blockdevice_register(struct block_device *blk) @@ -370,7 +391,7 @@ dev_dbg(blk->dev, "rdbufsize: %d blockbits: %d blkmask: 0x%08x\n", blk->rdbufsize, blk->blockbits, blk->blkmask); - for (i = 0; i < 32; i++) { + for (i = 0; i < 8; i++) { struct chunk *chunk = xzalloc(sizeof(*chunk)); chunk->data = dma_alloc(BUFSIZE); chunk->num = i; diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 0a3aff3..426ee9d 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -957,6 +957,8 @@ if (ret) goto out; } else { + discard_range(fd, retlen, pos); + pos = lseek(fd, pos, SEEK_SET); if (pos == -1) { ret = -errno; diff --git a/fs/devfs.c b/fs/devfs.c index d088c1a..e1893d1 100644 --- a/fs/devfs.c +++ b/fs/devfs.c @@ -94,6 +94,26 @@ 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 @@ .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/fs/fs.c b/fs/fs.c index 12faaeb..e00bbcd 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -497,6 +497,31 @@ } 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/block.h b/include/block.h index bd87efd..a1de266 100644 --- a/include/block.h +++ b/include/block.h @@ -24,6 +24,9 @@ int rdbufsize; int blkmask; + loff_t discard_start; + loff_t discard_size; + struct list_head buffered_blocks; struct list_head idle_blocks; diff --git a/include/driver.h b/include/driver.h index 6176e6a..fac3953 100644 --- a/include/driver.h +++ b/include/driver.h @@ -431,6 +431,7 @@ 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); }; diff --git a/include/fs.h b/include/fs.h index 04ec132..5811199 100644 --- a/include/fs.h +++ b/include/fs.h @@ -61,6 +61,8 @@ 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); @@ -128,6 +130,7 @@ #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); diff --git a/lib/libfile.c b/lib/libfile.c index 5a1817e..dbeed12 100644 --- a/lib/libfile.c +++ b/lib/libfile.c @@ -367,6 +367,8 @@ goto out; } + discard_range(dstfd, srcstat.st_size, 0); + if (verbose) { if (stat(src, &srcstat) < 0) srcstat.st_size = 0;