aboutsummaryrefslogtreecommitdiff
path: root/libflash
diff options
context:
space:
mode:
Diffstat (limited to 'libflash')
-rw-r--r--libflash/file.c60
1 files changed, 35 insertions, 25 deletions
diff --git a/libflash/file.c b/libflash/file.c
index 5cea3fc..7065eb4 100644
--- a/libflash/file.c
+++ b/libflash/file.c
@@ -143,34 +143,44 @@ static int mtd_erase(struct blocklevel_device *bl, uint64_t dst, uint64_t len)
* then lets just hope the kernel knows how to deal with it. If it
* is unsupported the ioctl() will fail and we'll report that -
* there is no other option.
+ *
+ * Furthermore, even very recent MTD layers and drivers aren't
+ * particularly good at not blocking in the kernel. This creates
+ * unexpected behaviour in userspace tools using these functions.
+ * In the absence of significant work inside the kernel, we'll just
+ * split stuff up here for convenience.
+ * We can assume everything is aligned here.
*/
- if (dst > UINT_MAX || len > UINT_MAX) {
- struct erase_info_user64 erase_info = {
- .start = dst,
- .length = len
- };
-
- if (ioctl(file_data->fd, MEMERASE64, &erase_info) == -1) {
- err = errno;
- if (err == 25) /* Kernel doesn't do 64bit MTD erase ioctl() */
- FL_DBG("Attempted a 64bit erase on a kernel which doesn't support it\n");
- FL_ERR("%s: IOCTL to kernel failed! %s\n", __func__, strerror(err));
- errno = err;
- return FLASH_ERR_PARM_ERROR;
- }
- } else {
- struct erase_info_user erase_info = {
- .start = dst,
- .length = len
- };
- if (ioctl(file_data->fd, MEMERASE, &erase_info) == -1) {
- err = errno;
- FL_ERR("%s: IOCTL to kernel failed! %s\n", __func__, strerror(err));
- errno = err;
- return FLASH_ERR_PARM_ERROR;
+ while (len) {
+ if (dst > UINT_MAX || len > UINT_MAX) {
+ struct erase_info_user64 erase_info = {
+ .start = dst,
+ .length = file_data->bl.erase_mask + 1
+ };
+
+ if (ioctl(file_data->fd, MEMERASE64, &erase_info) == -1) {
+ err = errno;
+ if (err == 25) /* Kernel doesn't do 64bit MTD erase ioctl() */
+ FL_DBG("Attempted a 64bit erase on a kernel which doesn't support it\n");
+ FL_ERR("%s: IOCTL to kernel failed! %s\n", __func__, strerror(err));
+ errno = err;
+ return FLASH_ERR_PARM_ERROR;
+ }
+ } else {
+ struct erase_info_user erase_info = {
+ .start = dst,
+ .length = file_data->bl.erase_mask + 1
+ };
+ if (ioctl(file_data->fd, MEMERASE, &erase_info) == -1) {
+ err = errno;
+ FL_ERR("%s: IOCTL to kernel failed! %s\n", __func__, strerror(err));
+ errno = err;
+ return FLASH_ERR_PARM_ERROR;
+ }
}
+ dst += file_data->bl.erase_mask + 1;
+ len -= file_data->bl.erase_mask + 1;
}
-
return 0;
}