android_mtdutils: Add mtd_write_descriptor This CL adds "mtd_write_descriptor" to create a write context from a file descriptor. It also refactors the code, especially mtd_write_partition and write_block to alleviate the need of an MtdPartition. BUG=chromium:426742 TEST=emerge android_mtdutils Change-Id: I450f21ab6ae3dd774cb531f9b166dd1864b83d05 Reviewed-on: https://chromium-review.googlesource.com/234457 Reviewed-by: Mike Frysinger <vapier@chromium.org> Commit-Queue: Nam Nguyen <namnguyen@chromium.org> Trybot-Ready: Nam Nguyen <namnguyen@chromium.org> Tested-by: Nam Nguyen <namnguyen@chromium.org>
diff --git a/mtdutils/mtdutils.c b/mtdutils/mtdutils.c index 9598c35..4e0463b 100644 --- a/mtdutils/mtdutils.c +++ b/mtdutils/mtdutils.c
@@ -48,10 +48,13 @@ }; struct MtdWriteContext { - const MtdPartition *partition; + uint64_t size; + uint32_t erase_size; char *buffer; size_t stored; int fd; + /* true if |fd| was opened by write_partition, and should be closed. */ + bool owned_fd; off_t* bad_block_offsets; int bad_block_alloc; @@ -455,32 +458,45 @@ free(ctx); } -MtdWriteContext *mtd_write_partition(const MtdPartition *partition) +MtdWriteContext *mtd_write_descriptor(int fd, const char *dev_node_name) { MtdWriteContext *ctx = (MtdWriteContext*) malloc(sizeof(MtdWriteContext)); if (ctx == NULL) return NULL; + if (mtd_node_info(dev_node_name, &ctx->size, &ctx->erase_size, NULL) != 0) { + free(ctx); + return NULL; + } + ctx->bad_block_offsets = NULL; ctx->bad_block_alloc = 0; ctx->bad_block_count = 0; - ctx->buffer = malloc(partition->erase_size); + ctx->buffer = malloc(ctx->erase_size); if (ctx->buffer == NULL) { free(ctx); return NULL; } + ctx->fd = fd; + ctx->owned_fd = false; + ctx->stored = 0; + return ctx; +} + +MtdWriteContext *mtd_write_partition(const MtdPartition *partition) +{ char mtddevname[32]; sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index); - ctx->fd = open(mtddevname, O_RDWR); - if (ctx->fd < 0) { - free(ctx->buffer); - free(ctx); + int fd = open(mtddevname, O_RDWR | O_CLOEXEC); + if (fd < 0) { return NULL; } - ctx->partition = partition; - ctx->stored = 0; + MtdWriteContext *ctx = mtd_write_descriptor(fd, mtddevname); + if (ctx) { + ctx->owned_fd = true; + } return ctx; } @@ -495,14 +511,13 @@ static int write_block(MtdWriteContext *ctx, const char *data) { - const MtdPartition *partition = ctx->partition; int fd = ctx->fd; off_t pos = lseek(fd, 0, SEEK_CUR); if (pos == (off_t) -1) return 1; - ssize_t size = partition->erase_size; - while (pos + size <= (int) partition->size) { + ssize_t size = ctx->erase_size; + while (pos + size <= ctx->size) { loff_t bpos = pos; int ret = ioctl(fd, MEMGETBADBLOCK, &bpos); if (ret != 0 && !(ret == -1 && errno == EOPNOTSUPP)) { @@ -510,7 +525,7 @@ fprintf(stderr, "mtd: not writing bad block at 0x%08lx (ret %d errno %d)\n", pos, ret, errno); - pos += partition->erase_size; + pos += ctx->erase_size; continue; // Don't try to erase known factory-bad blocks. } @@ -554,7 +569,7 @@ add_bad_block_offset(ctx, pos); printf("mtd: skipping write block at 0x%08lx\n", pos); ioctl(fd, MEMERASE, &erase_info); - pos += partition->erase_size; + pos += ctx->erase_size; } // Ran out of space on the device @@ -567,8 +582,8 @@ size_t wrote = 0; while (wrote < len) { // Coalesce partial writes into complete blocks - if (ctx->stored > 0 || len - wrote < ctx->partition->erase_size) { - size_t avail = ctx->partition->erase_size - ctx->stored; + if (ctx->stored > 0 || len - wrote < ctx->erase_size) { + size_t avail = ctx->erase_size - ctx->stored; size_t copy = len - wrote < avail ? len - wrote : avail; memcpy(ctx->buffer + ctx->stored, data + wrote, copy); ctx->stored += copy; @@ -576,15 +591,15 @@ } // If a complete block was accumulated, write it - if (ctx->stored == ctx->partition->erase_size) { + if (ctx->stored == ctx->erase_size) { if (write_block(ctx, ctx->buffer)) return -1; ctx->stored = 0; } // Write complete blocks directly from the user's buffer - while (ctx->stored == 0 && len - wrote >= ctx->partition->erase_size) { + while (ctx->stored == 0 && len - wrote >= ctx->erase_size) { if (write_block(ctx, data + wrote)) return -1; - wrote += ctx->partition->erase_size; + wrote += ctx->erase_size; } } @@ -595,7 +610,7 @@ { // Zero-pad and write any pending data to get us to a block boundary if (ctx->stored > 0) { - size_t zero = ctx->partition->erase_size - ctx->stored; + size_t zero = ctx->erase_size - ctx->stored; memset(ctx->buffer + ctx->stored, 0, zero); if (write_block(ctx, ctx->buffer)) return -1; ctx->stored = 0; @@ -604,7 +619,7 @@ off_t pos = lseek(ctx->fd, 0, SEEK_CUR); if ((off_t) pos == (off_t) -1) return pos; - const int total = (ctx->partition->size - pos) / ctx->partition->erase_size; + const int total = (ctx->size - pos) / ctx->erase_size; if (blocks < 0) blocks = total; if (blocks > total) { errno = ENOSPC; @@ -616,17 +631,17 @@ loff_t bpos = pos; if (ioctl(ctx->fd, MEMGETBADBLOCK, &bpos) > 0) { printf("mtd: not erasing bad block at 0x%08lx\n", pos); - pos += ctx->partition->erase_size; + pos += ctx->erase_size; continue; // Don't try to erase known factory-bad blocks. } struct erase_info_user erase_info; erase_info.start = pos; - erase_info.length = ctx->partition->erase_size; + erase_info.length = ctx->erase_size; if (ioctl(ctx->fd, MEMERASE, &erase_info) < 0) { printf("mtd: erase failure at 0x%08lx\n", pos); } - pos += ctx->partition->erase_size; + pos += ctx->erase_size; } return pos; @@ -637,7 +652,7 @@ int r = 0; // Make sure any pending data gets written if (mtd_erase_blocks(ctx, 0) == (off_t) -1) r = -1; - if (close(ctx->fd)) r = -1; + if (ctx->owned_fd && close(ctx->fd)) r = -1; free(ctx->bad_block_offsets); free(ctx->buffer); free(ctx); @@ -651,7 +666,7 @@ int i; for (i = 0; i < ctx->bad_block_count; ++i) { if (ctx->bad_block_offsets[i] == pos) { - pos += ctx->partition->erase_size; + pos += ctx->erase_size; } else if (ctx->bad_block_offsets[i] > pos) { return pos; }
diff --git a/mtdutils/mtdutils.h b/mtdutils/mtdutils.h index c8a859a..77c55d6 100644 --- a/mtdutils/mtdutils.h +++ b/mtdutils/mtdutils.h
@@ -64,7 +64,10 @@ /* NOTICE: Only use with reads of multiple erase blocks please. */ off64_t mtd_read_skip_to(const MtdReadContext *, off64_t offset); +/* write_partition opens the device node, and owns the file descriptor. */ MtdWriteContext *mtd_write_partition(const MtdPartition *); +/* write_descriptor uses the provided file descriptor. */ +MtdWriteContext *mtd_write_descriptor(int fd, const char *dev_node_name); ssize_t mtd_write_data(MtdWriteContext *, const char *data, size_t data_len); off_t mtd_erase_blocks(MtdWriteContext *, int blocks); /* 0 ok, -1 for all */ off_t mtd_find_write_start(MtdWriteContext *ctx, off_t pos);