#include <sys/stat.h>
#include "erofs/print.h"
#include "erofs/inode.h"
-#include "erofs/io.h"
#include "erofs/dir.h"
#include "erofs/compress.h"
#include "erofs/fragments.h"
usage(argc, argv);
exit(0);
case 3:
- err = blob_open_ro(&sbi, optarg);
+ err = erofs_blob_open_ro(&sbi, optarg);
if (err)
return err;
++sbi.extra_devices;
dumpcfg.show_subdirectories = true;
break;
case 6:
- sbi.diskoffset = strtoull(optarg, &endptr, 0);
+ sbi.bdev.offset = strtoull(optarg, &endptr, 0);
if (*endptr != '\0') {
erofs_err("invalid disk offset %s", optarg);
return -EINVAL;
goto exit;
}
- err = dev_open_ro(&sbi, cfg.c_img_path);
+ err = erofs_dev_open(&sbi, cfg.c_img_path, O_RDONLY | O_TRUNC);
if (err) {
erofs_err("failed to open image file");
goto exit;
exit_put_super:
erofs_put_super(&sbi);
exit_dev_close:
- dev_close(&sbi);
+ erofs_dev_close(&sbi);
exit:
- blob_closeall(&sbi);
+ erofs_blob_closeall(&sbi);
erofs_exit_configure();
return err;
}
#include <unistd.h>
#include <sys/stat.h>
#include "erofs/print.h"
-#include "erofs/io.h"
#include "erofs/compress.h"
#include "erofs/decompress.h"
#include "erofs/dir.h"
}
break;
case 3:
- ret = blob_open_ro(&sbi, optarg);
+ ret = erofs_blob_open_ro(&sbi, optarg);
if (ret)
return ret;
++sbi.extra_devices;
has_opt_preserve = true;
break;
case 12:
- sbi.diskoffset = strtoull(optarg, &endptr, 0);
+ sbi.bdev.offset = strtoull(optarg, &endptr, 0);
if (*endptr != '\0') {
erofs_err("invalid disk offset %s", optarg);
return -EINVAL;
struct erofs_super_block *sb;
int ret;
- ret = blk_read(&sbi, 0, buf, 0, 1);
+ ret = erofs_blk_read(&sbi, 0, buf, 0, 1);
if (ret) {
erofs_err("failed to read superblock to check checksum: %d",
ret);
}
addr = erofs_iloc(inode) + inode->inode_isize;
- ret = dev_read(sbi, 0, buf, addr, xattr_hdr_size);
+ ret = erofs_dev_read(sbi, 0, buf, addr, xattr_hdr_size);
if (ret < 0) {
erofs_err("failed to read xattr header @ nid %llu: %d",
inode->nid | 0ULL, ret);
while (remaining > 0) {
unsigned int entry_sz;
- ret = dev_read(sbi, 0, buf, addr, xattr_entry_size);
+ ret = erofs_dev_read(sbi, 0, buf, addr, xattr_entry_size);
if (ret) {
erofs_err("failed to read xattr entry @ nid %llu: %d",
inode->nid | 0ULL, ret);
cfg.c_dbg_lvl = -1;
#endif
- err = dev_open_ro(&sbi, cfg.c_img_path);
+ err = erofs_dev_open(&sbi, cfg.c_img_path, O_RDONLY);
if (err) {
erofs_err("failed to open image file");
goto exit;
exit_put_super:
erofs_put_super(&sbi);
exit_dev_close:
- dev_close(&sbi);
+ erofs_dev_close(&sbi);
exit:
- blob_closeall(&sbi);
+ erofs_blob_closeall(&sbi);
erofs_exit_configure();
return err ? 1 : 0;
}
#include "macosx.h"
#include "erofs/config.h"
#include "erofs/print.h"
-#include "erofs/io.h"
#include "erofs/dir.h"
#include "erofs/inode.h"
switch (key) {
case 1:
- ret = blob_open_ro(&sbi, arg + sizeof("--device=") - 1);
+ ret = erofs_blob_open_ro(&sbi, arg + sizeof("--device=") - 1);
if (ret)
return -1;
++sbi.extra_devices;
if (fusecfg.odebug && cfg.c_dbg_lvl < EROFS_DBG)
cfg.c_dbg_lvl = EROFS_DBG;
- sbi.diskoffset = fusecfg.offset;
- ret = dev_open_ro(&sbi, fusecfg.disk);
+ sbi.bdev.offset = fusecfg.offset;
+ ret = erofs_dev_open(&sbi, fusecfg.disk, O_RDONLY);
if (ret) {
fprintf(stderr, "failed to open: %s\n", fusecfg.disk);
goto err_fuse_free_args;
err_super_put:
erofs_put_super(&sbi);
err_dev_close:
- blob_closeall(&sbi);
- dev_close(&sbi);
+ erofs_blob_closeall(&sbi);
+ erofs_dev_close(&sbi);
err_fuse_free_args:
free(opts.mountpoint);
fuse_opt_free_args(&args);
#include <pthread.h>
#endif
#include "atomic.h"
+#include "io.h"
#ifndef PATH_MAX
#define PATH_MAX 4096 /* # chars in a path name including nul */
u8 xattr_prefix_count;
struct erofs_xattr_prefix_item *xattr_prefixes;
- int devfd, devblksz;
- /* offset when reading multi-part images */
- u64 diskoffset;
+ struct erofs_vfile bdev;
+ int devblksz;
u64 devsz;
dev_t dev;
unsigned int nblobs;
int z_erofs_map_blocks_iter(struct erofs_inode *vi,
struct erofs_map_blocks *map, int flags);
+/* io.c */
+int erofs_dev_open(struct erofs_sb_info *sbi, const char *dev, int flags);
+void erofs_dev_close(struct erofs_sb_info *sbi);
+void erofs_blob_closeall(struct erofs_sb_info *sbi);
+int erofs_blob_open_ro(struct erofs_sb_info *sbi, const char *dev);
+
+int erofs_dev_read(struct erofs_sb_info *sbi, int device_id,
+ void *buf, u64 offset, size_t len);
+
+static inline int erofs_dev_write(struct erofs_sb_info *sbi, const void *buf,
+ u64 offset, size_t len)
+{
+ return erofs_io_pwrite(&sbi->bdev, buf, offset, len);
+}
+
+static inline int erofs_dev_fillzero(struct erofs_sb_info *sbi, u64 offset,
+ size_t len, bool pad)
+{
+ return erofs_io_fallocate(&sbi->bdev, offset, len, pad);
+}
+
+static inline int erofs_dev_resize(struct erofs_sb_info *sbi,
+ erofs_blk_t blocks)
+{
+ return erofs_io_ftruncate(&sbi->bdev, (u64)blocks * erofs_blksiz(sbi));
+}
+
+static inline int erofs_blk_write(struct erofs_sb_info *sbi, const void *buf,
+ erofs_blk_t blkaddr, u32 nblocks)
+{
+ return erofs_dev_write(sbi, buf, erofs_pos(sbi, blkaddr),
+ erofs_pos(sbi, nblocks));
+}
+
+static inline int erofs_blk_read(struct erofs_sb_info *sbi, int device_id,
+ void *buf, erofs_blk_t start, u32 nblocks)
+{
+ return erofs_dev_read(sbi, device_id, buf, erofs_pos(sbi, start),
+ erofs_pos(sbi, nblocks));
+}
+
#ifdef EUCLEAN
#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */
#else
#define _GNU_SOURCE
#endif
#include <unistd.h>
-#include "internal.h"
+#include "defs.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
-void blob_closeall(struct erofs_sb_info *sbi);
-int blob_open_ro(struct erofs_sb_info *sbi, const char *dev);
-int dev_open(struct erofs_sb_info *sbi, const char *devname);
-int dev_open_ro(struct erofs_sb_info *sbi, const char *dev);
-void dev_close(struct erofs_sb_info *sbi);
-int dev_write(struct erofs_sb_info *sbi, const void *buf,
- u64 offset, size_t len);
-int dev_read(struct erofs_sb_info *sbi, int device_id,
- void *buf, u64 offset, size_t len);
-int dev_fillzero(struct erofs_sb_info *sbi, u64 offset,
- size_t len, bool padding);
-int dev_fsync(struct erofs_sb_info *sbi);
-int dev_resize(struct erofs_sb_info *sbi, erofs_blk_t nblocks);
-
-ssize_t erofs_copy_file_range(int fd_in, erofs_off_t *off_in,
- int fd_out, erofs_off_t *off_out,
+struct erofs_vfile;
+
+struct erofs_vfops {
+ int (*pread)(struct erofs_vfile *vf, void *buf, u64 offset, size_t len);
+ int (*pwrite)(struct erofs_vfile *vf, const void *buf, u64 offset, size_t len);
+ int (*fsync)(struct erofs_vfile *vf);
+ int (*fallocate)(struct erofs_vfile *vf, u64 offset, size_t len, bool pad);
+ int (*ftruncate)(struct erofs_vfile *vf, u64 length);
+};
+
+struct erofs_vfile {
+ struct erofs_vfops *ops;
+ u64 offset;
+ int fd;
+};
+
+int erofs_io_pwrite(struct erofs_vfile *vf, const void *buf, u64 pos, size_t len);
+int erofs_io_fsync(struct erofs_vfile *vf);
+int erofs_io_fallocate(struct erofs_vfile *vf, u64 offset, size_t len, bool pad);
+int erofs_io_ftruncate(struct erofs_vfile *vf, u64 length);
+int erofs_io_pread(struct erofs_vfile *vf, void *buf, u64 offset, size_t len);
+
+ssize_t erofs_copy_file_range(int fd_in, u64 *off_in, int fd_out, u64 *off_out,
size_t length);
-static inline int blk_write(struct erofs_sb_info *sbi, const void *buf,
- erofs_blk_t blkaddr, u32 nblocks)
-{
- return dev_write(sbi, buf, erofs_pos(sbi, blkaddr),
- erofs_pos(sbi, nblocks));
-}
-
-static inline int blk_read(struct erofs_sb_info *sbi, int device_id, void *buf,
- erofs_blk_t start, u32 nblocks)
-{
- return dev_read(sbi, device_id, buf, erofs_pos(sbi, start),
- erofs_pos(sbi, nblocks));
-}
-
#ifdef __cplusplus
}
#endif
#include "erofs/blobchunk.h"
#include "erofs/block_list.h"
#include "erofs/cache.h"
-#include "erofs/io.h"
#include "sha256.h"
#include <unistd.h>
0 : extent_end - extent_start,
first_extent, true);
- return dev_write(inode->sbi, inode->chunkindexes, off, inode->extent_isize);
+ return erofs_dev_write(inode->sbi, inode->chunkindexes, off,
+ inode->extent_isize);
}
int erofs_blob_mergechunks(struct erofs_inode *inode, unsigned int chunkbits,
{
struct erofs_buffer_head *bh;
ssize_t length;
- erofs_off_t pos_in, pos_out;
+ u64 pos_in, pos_out;
ssize_t ret;
if (blobfile) {
};
memcpy(dis.tag, sbi->devs[i].tag, sizeof(dis.tag));
- ret = dev_write(sbi, &dis, pos_out, sizeof(dis));
+ ret = erofs_dev_write(sbi, &dis, pos_out, sizeof(dis));
if (ret)
return ret;
pos_out += sizeof(dis);
pos_out = erofs_btell(bh, false);
remapped_base = erofs_blknr(sbi, pos_out);
- pos_out += sbi->diskoffset;
+ pos_out += sbi->bdev.offset;
if (blobfile) {
pos_in = 0;
ret = erofs_copy_file_range(fileno(blobfile), &pos_in,
- sbi->devfd, &pos_out, datablob_size);
+ sbi->bdev.fd, &pos_out, datablob_size);
ret = ret < datablob_size ? -EIO : 0;
} else {
ret = 0;
*/
#include <stdlib.h>
#include <erofs/cache.h>
-#include "erofs/io.h"
#include "erofs/print.h"
static struct erofs_buffer_block blkh = {
padding = blksiz - (p->buffers.off & (blksiz - 1));
if (padding != blksiz)
- dev_fillzero(&sbi, erofs_pos(&sbi, blkaddr) - padding,
- padding, true);
+ erofs_dev_fillzero(&sbi, erofs_pos(&sbi, blkaddr) - padding,
+ padding, true);
if (p->type != DATA)
erofs_metablkcnt += BLK_ROUND_UP(&sbi, p->buffers.off);
#include <stdlib.h>
#include <unistd.h>
#include "erofs/print.h"
-#include "erofs/io.h"
#include "erofs/cache.h"
#include "erofs/compress.h"
#include "erofs/dedupe.h"
} else {
erofs_dbg("Writing %u uncompressed data to block %u", count,
ctx->blkaddr);
- ret = blk_write(sbi, dst, ctx->blkaddr, 1);
+ ret = erofs_blk_write(sbi, dst, ctx->blkaddr, 1);
if (ret)
return ret;
}
erofs_dbg("Writing %u compressed data to %u of %u blocks",
e->length, ctx->blkaddr, e->compressedblks);
- ret = blk_write(sbi, dst - padding, ctx->blkaddr,
- e->compressedblks);
+ ret = erofs_blk_write(sbi, dst - padding, ctx->blkaddr,
+ e->compressedblks);
if (ret)
return ret;
}
/* skip write data but leave blkaddr for inline fallback */
if (ei->e.inlined || !ei->e.compressedblks)
continue;
- ret2 = blk_write(sbi, sctx->membuf + blkoff * erofs_blksiz(sbi),
- ei->e.blkaddr, ei->e.compressedblks);
+ ret2 = erofs_blk_write(sbi, sctx->membuf + blkoff * erofs_blksiz(sbi),
+ ei->e.blkaddr, ei->e.compressedblks);
blkoff += ei->e.compressedblks;
if (ret2) {
ret = ret2;
return PTR_ERR(bh);
}
erofs_mapbh(bh->block);
- ret = dev_write(sbi, &lz4alg, erofs_btell(bh, false),
- sizeof(lz4alg));
+ ret = erofs_dev_write(sbi, &lz4alg, erofs_btell(bh, false),
+ sizeof(lz4alg));
bh->op = &erofs_drop_directly_bhops;
}
#ifdef HAVE_LIBLZMA
return PTR_ERR(bh);
}
erofs_mapbh(bh->block);
- ret = dev_write(sbi, &lzmaalg, erofs_btell(bh, false),
- sizeof(lzmaalg));
+ ret = erofs_dev_write(sbi, &lzmaalg, erofs_btell(bh, false),
+ sizeof(lzmaalg));
bh->op = &erofs_drop_directly_bhops;
}
#endif
return PTR_ERR(bh);
}
erofs_mapbh(bh->block);
- ret = dev_write(sbi, &zalg, erofs_btell(bh, false),
- sizeof(zalg));
+ ret = erofs_dev_write(sbi, &zalg, erofs_btell(bh, false),
+ sizeof(zalg));
bh->op = &erofs_drop_directly_bhops;
}
#ifdef HAVE_LIBZSTD
return PTR_ERR(bh);
}
erofs_mapbh(bh->block);
- ret = dev_write(sbi, &zalg, erofs_btell(bh, false),
- sizeof(zalg));
+ ret = erofs_dev_write(sbi, &zalg, erofs_btell(bh, false),
+ sizeof(zalg));
bh->op = &erofs_drop_directly_bhops;
}
#endif
#include <stdlib.h>
#include "erofs/print.h"
#include "erofs/internal.h"
-#include "erofs/io.h"
#include "erofs/trace.h"
#include "erofs/decompress.h"
pos = roundup(erofs_iloc(vi) + vi->inode_isize +
vi->xattr_isize, unit) + unit * chunknr;
- err = blk_read(sbi, 0, buf, erofs_blknr(sbi, pos), 1);
+ err = erofs_blk_read(sbi, 0, buf, erofs_blknr(sbi, pos), 1);
if (err < 0)
return -EIO;
if (ret)
return ret;
- ret = dev_read(sbi, mdev.m_deviceid, buffer, mdev.m_pa + offset, len);
+ ret = erofs_dev_read(sbi, mdev.m_deviceid, buffer, mdev.m_pa + offset, len);
if (ret < 0)
return -EIO;
return 0;
return ret;
}
- ret = dev_read(sbi, mdev.m_deviceid, raw, mdev.m_pa, map->m_plen);
+ ret = erofs_dev_read(sbi, mdev.m_deviceid, raw, mdev.m_pa, map->m_plen);
if (ret < 0)
return ret;
u8 data[EROFS_MAX_BLOCK_SIZE];
*offset = round_up(*offset, 4);
- ret = blk_read(sbi, 0, data, erofs_blknr(sbi, *offset), 1);
+ ret = erofs_blk_read(sbi, 0, data, erofs_blknr(sbi, *offset), 1);
if (ret)
return ERR_PTR(ret);
len = le16_to_cpu(*(__le16 *)(data + erofs_blkoff(sbi, *offset)));
for (i = 0; i < len; i += cnt) {
cnt = min_t(int, erofs_blksiz(sbi) - erofs_blkoff(sbi, *offset),
len - i);
- ret = blk_read(sbi, 0, data, erofs_blknr(sbi, *offset), 1);
+ ret = erofs_blk_read(sbi, 0, data, erofs_blknr(sbi, *offset), 1);
if (ret) {
free(buffer);
return ERR_PTR(ret);
struct stat st;
/* try to use the devfd for regfiles on stream 0 */
- if (strm == dbufstrm && sbi.devsz == INT64_MAX) {
+ if (strm == dbufstrm && !sbi.bdev.ops) {
strm->devpos = 1ULL << 40;
- if (!ftruncate(sbi.devfd, strm->devpos << 1)) {
- strm->fd = dup(sbi.devfd);
+ if (!ftruncate(sbi.bdev.fd, strm->devpos << 1)) {
+ strm->fd = dup(sbi.bdev.fd);
if (lseek(strm->fd, strm->devpos,
SEEK_SET) != strm->devpos)
return -EIO;
#include "erofs/diskbuf.h"
#include "erofs/inode.h"
#include "erofs/cache.h"
-#include "erofs/io.h"
#include "erofs/compress.h"
#include "erofs/xattr.h"
#include "erofs/exclude.h"
char buf[EROFS_MAX_BLOCK_SIZE];
fill_dirblock(buf, erofs_blksiz(sbi), q, head, end);
- return blk_write(sbi, buf, blkaddr, 1);
+ return erofs_blk_write(sbi, buf, blkaddr, 1);
}
erofs_nid_t erofs_lookupnid(struct erofs_inode *inode)
return ret;
if (nblocks)
- blk_write(sbi, buf, inode->u.i_blkaddr, nblocks);
+ erofs_blk_write(sbi, buf, inode->u.i_blkaddr, nblocks);
inode->idata_size = inode->i_size % erofs_blksiz(sbi);
if (inode->idata_size) {
inode->idata = malloc(inode->idata_size);
return -EAGAIN;
}
- ret = blk_write(sbi, buf, inode->u.i_blkaddr + i, 1);
+ ret = erofs_blk_write(sbi, buf, inode->u.i_blkaddr + i, 1);
if (ret)
return ret;
}
BUG_ON(1);
}
- ret = dev_write(sbi, &u, off, inode->inode_isize);
+ ret = erofs_dev_write(sbi, &u, off, inode->inode_isize);
if (ret)
return ret;
off += inode->inode_isize;
if (IS_ERR(xattrs))
return PTR_ERR(xattrs);
- ret = dev_write(sbi, xattrs, off, inode->xattr_isize);
+ ret = erofs_dev_write(sbi, xattrs, off, inode->xattr_isize);
free(xattrs);
if (ret)
return ret;
} else {
/* write compression metadata */
off = roundup(off, 8);
- ret = dev_write(sbi, inode->compressmeta, off,
- inode->extent_isize);
+ ret = erofs_dev_write(sbi, inode->compressmeta, off,
+ inode->extent_isize);
if (ret)
return ret;
}
const erofs_off_t off = erofs_btell(bh, false);
int ret;
- ret = dev_write(inode->sbi, inode->idata, off, inode->idata_size);
+ ret = erofs_dev_write(inode->sbi, inode->idata, off, inode->idata_size);
if (ret)
return ret;
/* pad 0'ed data for the other cases */
zero_pos = pos + inode->idata_size;
}
- ret = dev_write(sbi, inode->idata, pos, inode->idata_size);
+ ret = erofs_dev_write(sbi, inode->idata, pos, inode->idata_size);
if (ret)
return ret;
DBG_BUGON(inode->idata_size > erofs_blksiz(sbi));
if (inode->idata_size < erofs_blksiz(sbi)) {
- ret = dev_fillzero(sbi, zero_pos,
+ ret = erofs_dev_fillzero(sbi, zero_pos,
erofs_blksiz(sbi) - inode->idata_size,
false);
if (ret)
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
-#include "erofs/io.h"
+#include "erofs/internal.h"
#ifdef HAVE_LINUX_FS_H
#include <linux/fs.h>
#endif
#define EROFS_MODNAME "erofs_io"
#include "erofs/print.h"
-static int dev_get_blkdev_size(int fd, u64 *bytes)
+int erofs_io_pwrite(struct erofs_vfile *vf, const void *buf,
+ u64 pos, size_t len)
+{
+ ssize_t ret;
+
+ if (unlikely(cfg.c_dry_run))
+ return 0;
+
+ if (vf->ops)
+ return vf->ops->pwrite(vf, buf, pos, len);
+
+ pos += vf->offset;
+ do {
+#ifdef HAVE_PWRITE64
+ ret = pwrite64(vf->fd, buf, len, (off64_t)pos);
+#else
+ ret = pwrite(vf->fd, buf, len, (off_t)pos);
+#endif
+ if (ret <= 0) {
+ erofs_err("failed to write: %s", strerror(errno));
+ return -errno;
+ }
+ len -= ret;
+ buf += ret;
+ pos += ret;
+ } while (len);
+
+ return 0;
+}
+
+int erofs_io_fsync(struct erofs_vfile *vf)
+{
+ int ret;
+
+ if (unlikely(cfg.c_dry_run))
+ return 0;
+
+ if (vf->ops)
+ return vf->ops->fsync(vf);
+
+ ret = fsync(vf->fd);
+ if (ret) {
+ erofs_err("failed to fsync(!): %s", strerror(errno));
+ return -errno;
+ }
+ return 0;
+}
+
+int erofs_io_fallocate(struct erofs_vfile *vf, u64 offset,
+ size_t len, bool zeroout)
+{
+ static const char zero[EROFS_MAX_BLOCK_SIZE] = {0};
+ int ret;
+
+ if (unlikely(cfg.c_dry_run))
+ return 0;
+
+ if (vf->ops)
+ return vf->ops->fallocate(vf, offset, len, zeroout);
+
+#if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE)
+ if (!zeroout && fallocate(vf->fd, FALLOC_FL_PUNCH_HOLE |
+ FALLOC_FL_KEEP_SIZE, offset + vf->offset, len) >= 0)
+ return 0;
+#endif
+ while (len > EROFS_MAX_BLOCK_SIZE) {
+ ret = erofs_io_pwrite(vf, zero, offset, EROFS_MAX_BLOCK_SIZE);
+ if (ret)
+ return ret;
+ len -= EROFS_MAX_BLOCK_SIZE;
+ offset += EROFS_MAX_BLOCK_SIZE;
+ }
+ return erofs_io_pwrite(vf, zero, offset, len);
+}
+
+int erofs_io_ftruncate(struct erofs_vfile *vf, u64 length)
+{
+ int ret;
+ struct stat st;
+
+ if (unlikely(cfg.c_dry_run))
+ return 0;
+
+ if (vf->ops)
+ return vf->ops->ftruncate(vf, length);
+
+ ret = fstat(vf->fd, &st);
+ if (ret) {
+ erofs_err("failed to fstat: %s", strerror(errno));
+ return -errno;
+ }
+ length += vf->offset;
+ if (S_ISBLK(st.st_mode) || st.st_size == length)
+ return 0;
+ return ftruncate(vf->fd, length);
+}
+
+int erofs_io_pread(struct erofs_vfile *vf, void *buf, u64 pos, size_t len)
+{
+ ssize_t ret;
+
+ if (unlikely(cfg.c_dry_run))
+ return 0;
+
+ if (vf->ops)
+ return vf->ops->pread(vf, buf, pos, len);
+
+ pos += vf->offset;
+ do {
+#ifdef HAVE_PREAD64
+ ret = pread64(vf->fd, buf, len, (off64_t)pos);
+#else
+ ret = pread(vf->fd, buf, len, (off_t)pos);
+#endif
+ if (ret <= 0) {
+ if (!ret) {
+ erofs_info("reach EOF of device");
+ memset(buf, 0, len);
+ return 0;
+ }
+ if (errno != EINTR) {
+ erofs_err("failed to read: %s", strerror(errno));
+ return -errno;
+ }
+ ret = 0;
+ }
+ pos += ret;
+ len -= ret;
+ buf += ret;
+ } while (len);
+ return 0;
+}
+
+static int erofs_get_bdev_size(int fd, u64 *bytes)
{
errno = ENOTSUP;
#ifdef BLKGETSIZE64
return -errno;
}
-void dev_close(struct erofs_sb_info *sbi)
+#if defined(__linux__) && !defined(BLKDISCARD)
+#define BLKDISCARD _IO(0x12, 119)
+#endif
+
+static int erofs_bdev_discard(int fd, u64 block, u64 count)
{
- close(sbi->devfd);
- free(sbi->devname);
- sbi->devname = NULL;
- sbi->devfd = -1;
- sbi->devsz = 0;
+#ifdef BLKDISCARD
+ u64 range[2] = { block, count };
+
+ return ioctl(fd, BLKDISCARD, &range);
+#else
+ return -EOPNOTSUPP;
+#endif
}
-int dev_open(struct erofs_sb_info *sbi, const char *dev)
+int erofs_dev_open(struct erofs_sb_info *sbi, const char *dev, int flags)
{
+ bool ro = (flags & O_ACCMODE) == O_RDONLY;
+ bool truncate = flags & O_TRUNC;
struct stat st;
int fd, ret;
repeat:
#endif
- fd = open(dev, O_RDWR | O_CREAT | O_BINARY, 0644);
+ fd = open(dev, (ro ? O_RDONLY : O_RDWR | O_CREAT) | O_BINARY, 0644);
if (fd < 0) {
- erofs_err("failed to open(%s).", dev);
+ erofs_err("failed to open %s: %s", dev, strerror(errno));
return -errno;
}
+ if (ro || !truncate)
+ goto out;
+
ret = fstat(fd, &st);
if (ret) {
- erofs_err("failed to fstat(%s).", dev);
+ erofs_err("failed to fstat(%s): %s", dev, strerror(errno));
close(fd);
return -errno;
}
switch (st.st_mode & S_IFMT) {
case S_IFBLK:
- ret = dev_get_blkdev_size(fd, &sbi->devsz);
+ ret = erofs_get_bdev_size(fd, &sbi->devsz);
if (ret) {
- erofs_err("failed to get block device size(%s).", dev);
+ erofs_err("failed to get block device size(%s): %s",
+ dev, strerror(errno));
close(fd);
return ret;
}
sbi->devsz = round_down(sbi->devsz, erofs_blksiz(sbi));
+ ret = erofs_bdev_discard(fd, 0, sbi->devsz);
+ if (ret)
+ erofs_err("failed to erase block device(%s): %s",
+ dev, erofs_strerror(ret));
break;
case S_IFREG:
if (st.st_size) {
return -errno;
}
}
- /* INT64_MAX is the limit of kernel vfs */
- sbi->devsz = INT64_MAX;
sbi->devblksz = st.st_blksize;
break;
default:
return -EINVAL;
}
+out:
sbi->devname = strdup(dev);
if (!sbi->devname) {
close(fd);
return -ENOMEM;
}
- sbi->devfd = fd;
-
+ sbi->bdev.fd = fd;
erofs_info("successfully to open %s", dev);
return 0;
}
-void blob_closeall(struct erofs_sb_info *sbi)
+void erofs_dev_close(struct erofs_sb_info *sbi)
+{
+ close(sbi->bdev.fd);
+ free(sbi->devname);
+ sbi->devname = NULL;
+ sbi->bdev.fd = -1;
+}
+
+void erofs_blob_closeall(struct erofs_sb_info *sbi)
{
unsigned int i;
sbi->nblobs = 0;
}
-int blob_open_ro(struct erofs_sb_info *sbi, const char *dev)
+int erofs_blob_open_ro(struct erofs_sb_info *sbi, const char *dev)
{
int fd = open(dev, O_RDONLY | O_BINARY);
return 0;
}
-/* XXX: temporary soluation. Disk I/O implementation needs to be refactored. */
-int dev_open_ro(struct erofs_sb_info *sbi, const char *dev)
+int erofs_dev_read(struct erofs_sb_info *sbi, int device_id,
+ void *buf, u64 offset, size_t len)
{
- int fd = open(dev, O_RDONLY | O_BINARY);
-
- if (fd < 0) {
- erofs_err("failed to open(%s).", dev);
- return -errno;
- }
-
- sbi->devname = strdup(dev);
- if (!sbi->devname) {
- close(fd);
- return -ENOMEM;
- }
- sbi->devfd = fd;
- sbi->devsz = INT64_MAX;
- return 0;
-}
-
-int dev_write(struct erofs_sb_info *sbi, const void *buf, u64 offset, size_t len)
-{
- int ret;
-
- if (cfg.c_dry_run)
- return 0;
-
- if (!buf) {
- erofs_err("buf is NULL");
- return -EINVAL;
- }
-
- offset += sbi->diskoffset;
- if (offset >= sbi->devsz || len > sbi->devsz ||
- offset > sbi->devsz - len) {
- erofs_err("Write posion[%" PRIu64 ", %zd] is too large beyond the end of device(%" PRIu64 ").",
- offset, len, sbi->devsz);
- return -EINVAL;
- }
-
-#ifdef HAVE_PWRITE64
- ret = pwrite64(sbi->devfd, buf, len, (off64_t)offset);
-#else
- ret = pwrite(sbi->devfd, buf, len, (off_t)offset);
-#endif
- if (ret != (int)len) {
- if (ret < 0) {
- erofs_err("Failed to write data into device - %s:[%" PRIu64 ", %zd].",
- sbi->devname, offset, len);
- return -errno;
- }
-
- erofs_err("Writing data into device - %s:[%" PRIu64 ", %zd] - was truncated.",
- sbi->devname, offset, len);
- return -ERANGE;
- }
- return 0;
-}
-
-int dev_fillzero(struct erofs_sb_info *sbi, u64 offset, size_t len, bool padding)
-{
- static const char zero[EROFS_MAX_BLOCK_SIZE] = {0};
- int ret;
-
- if (cfg.c_dry_run)
- return 0;
-
-#if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE)
- if (!padding && fallocate(sbi->devfd, FALLOC_FL_PUNCH_HOLE |
- FALLOC_FL_KEEP_SIZE, offset + sbi->diskoffset, len) >= 0)
- return 0;
-#endif
- while (len > erofs_blksiz(sbi)) {
- ret = dev_write(sbi, zero, offset, erofs_blksiz(sbi));
- if (ret)
- return ret;
- len -= erofs_blksiz(sbi);
- offset += erofs_blksiz(sbi);
- }
- return dev_write(sbi, zero, offset, len);
-}
-
-int dev_fsync(struct erofs_sb_info *sbi)
-{
- int ret;
-
- ret = fsync(sbi->devfd);
- if (ret) {
- erofs_err("Could not fsync device!!!");
- return -EIO;
- }
- return 0;
-}
-
-int dev_resize(struct erofs_sb_info *sbi, erofs_blk_t blocks)
-{
- int ret;
- struct stat st;
- u64 length;
-
- if (cfg.c_dry_run || sbi->devsz != INT64_MAX)
- return 0;
-
- ret = fstat(sbi->devfd, &st);
- if (ret) {
- erofs_err("failed to fstat.");
- return -errno;
- }
-
- length = (u64)blocks * erofs_blksiz(sbi);
- length += sbi->diskoffset;
- if (st.st_size == length)
- return 0;
- if (st.st_size > length)
- return ftruncate(sbi->devfd, length);
-
- length = length - st.st_size;
-#if defined(HAVE_FALLOCATE)
- if (fallocate(sbi->devfd, 0, st.st_size, length) >= 0)
- return 0;
-#endif
- return dev_fillzero(sbi, st.st_size - sbi->diskoffset,
- length, true);
-}
-
-int dev_read(struct erofs_sb_info *sbi, int device_id,
- void *buf, u64 offset, size_t len)
-{
- int read_count, fd;
-
- if (cfg.c_dry_run)
- return 0;
-
- if (!buf) {
- erofs_err("buf is NULL");
- return -EINVAL;
- }
-
- if (!device_id) {
- fd = sbi->devfd;
- offset += sbi->diskoffset;
- } else {
- if (device_id > sbi->nblobs) {
- erofs_err("invalid device id %d", device_id);
- return -ENODEV;
- }
- fd = sbi->blobfd[device_id - 1];
- }
-
- while (len > 0) {
-#ifdef HAVE_PREAD64
- read_count = pread64(fd, buf, len, (off64_t)offset);
-#else
- read_count = pread(fd, buf, len, (off_t)offset);
-#endif
- if (read_count < 1) {
- if (!read_count) {
- erofs_info("Reach EOF of device - %s:[%" PRIu64 ", %zd].",
- sbi->devname, offset, len);
- memset(buf, 0, len);
- return 0;
- } else if (errno != EINTR) {
- erofs_err("Failed to read data from device - %s:[%" PRIu64 ", %zd].",
- sbi->devname, offset, len);
- return -errno;
- }
- }
- offset += read_count;
- len -= read_count;
- buf += read_count;
- }
- return 0;
+ if (device_id)
+ return erofs_io_pread(&((struct erofs_vfile) {
+ .fd = sbi->blobfd[device_id - 1],
+ }), buf, offset, len);
+ return erofs_io_pread(&sbi->bdev, buf, offset, len);
}
-static ssize_t __erofs_copy_file_range(int fd_in, erofs_off_t *off_in,
- int fd_out, erofs_off_t *off_out,
+static ssize_t __erofs_copy_file_range(int fd_in, u64 *off_in,
+ int fd_out, u64 *off_out,
size_t length)
{
size_t copied = 0;
return copied;
}
-ssize_t erofs_copy_file_range(int fd_in, erofs_off_t *off_in,
- int fd_out, erofs_off_t *off_out,
+ssize_t erofs_copy_file_range(int fd_in, u64 *off_in, int fd_out, u64 *off_out,
size_t length)
{
#ifdef HAVE_COPY_FILE_RANGE
#include <sys/sysmacros.h>
#endif
#include "erofs/print.h"
-#include "erofs/io.h"
+#include "erofs/internal.h"
static dev_t erofs_new_decode_dev(u32 dev)
{
DBG_BUGON(!sbi);
inode_loc = erofs_iloc(vi);
- ret = dev_read(sbi, 0, buf, inode_loc, sizeof(*dic));
+ ret = erofs_dev_read(sbi, 0, buf, inode_loc, sizeof(*dic));
if (ret < 0)
return -EIO;
case EROFS_INODE_LAYOUT_EXTENDED:
vi->inode_isize = sizeof(struct erofs_inode_extended);
- ret = dev_read(sbi, 0, buf + sizeof(*dic),
+ ret = erofs_dev_read(sbi, 0, buf + sizeof(*dic),
inode_loc + sizeof(*dic),
sizeof(*die) - sizeof(*dic));
if (ret < 0)
#include "erofs/print.h"
#include "erofs/inode.h"
#include "erofs/rebuild.h"
-#include "erofs/io.h"
#include "erofs/dir.h"
#include "erofs/xattr.h"
#include "erofs/blobchunk.h"
*/
#include <string.h>
#include <stdlib.h>
-#include "erofs/io.h"
#include "erofs/print.h"
#include "erofs/xattr.h"
struct erofs_deviceslot dis;
int ret;
- ret = dev_read(sbi, 0, &dis, pos, sizeof(dis));
+ ret = erofs_dev_read(sbi, 0, &dis, pos, sizeof(dis));
if (ret < 0) {
free(sbi->devs);
sbi->devs = NULL;
int ret;
sbi->blkszbits = ilog2(EROFS_MAX_BLOCK_SIZE);
- ret = blk_read(sbi, 0, data, 0, erofs_blknr(sbi, sizeof(data)));
+ ret = erofs_blk_read(sbi, 0, data, 0, erofs_blknr(sbi, sizeof(data)));
if (ret < 0) {
erofs_err("cannot read erofs superblock: %d", ret);
return -EIO;
#include "erofs/inode.h"
#include "erofs/list.h"
#include "erofs/tar.h"
-#include "erofs/io.h"
#include "erofs/xattr.h"
#include "erofs/blobchunk.h"
#include "erofs/rebuild.h"
#include "erofs/hashtable.h"
#include "erofs/xattr.h"
#include "erofs/cache.h"
-#include "erofs/io.h"
#include "erofs/fragments.h"
#include "xxhash.h"
#include "liberofs_private.h"
shared_xattrs_list = sorted_n[0];
free(sorted_n);
bh->op = &erofs_drop_directly_bhops;
- ret = dev_write(sbi, buf, erofs_btell(bh, false), shared_xattrs_size);
+ ret = erofs_dev_write(sbi, buf, erofs_btell(bh, false), shared_xattrs_size);
free(buf);
erofs_bdrop(bh, false);
out:
it.blkaddr = erofs_blknr(sbi, erofs_iloc(vi) + vi->inode_isize);
it.ofs = erofs_blkoff(sbi, erofs_iloc(vi) + vi->inode_isize);
- ret = blk_read(sbi, 0, it.page, it.blkaddr, 1);
+ ret = erofs_blk_read(sbi, 0, it.page, it.blkaddr, 1);
if (ret < 0)
return -EIO;
/* cannot be unaligned */
DBG_BUGON(it.ofs != erofs_blksiz(sbi));
- ret = blk_read(sbi, 0, it.page, ++it.blkaddr, 1);
+ ret = erofs_blk_read(sbi, 0, it.page, ++it.blkaddr, 1);
if (ret < 0) {
free(vi->xattr_shared_xattrs);
vi->xattr_shared_xattrs = NULL;
it->blkaddr += erofs_blknr(sbi, it->ofs);
- ret = blk_read(sbi, 0, it->page, it->blkaddr, 1);
+ ret = erofs_blk_read(sbi, 0, it->page, it->blkaddr, 1);
if (ret < 0)
return -EIO;
it->blkaddr = erofs_blknr(sbi, erofs_iloc(vi) + inline_xattr_ofs);
it->ofs = erofs_blkoff(sbi, erofs_iloc(vi) + inline_xattr_ofs);
- ret = blk_read(sbi, 0, it->page, it->blkaddr, 1);
+ ret = erofs_blk_read(sbi, 0, it->page, it->blkaddr, 1);
if (ret < 0)
return -EIO;
it->it.ofs = xattrblock_offset(vi, vi->xattr_shared_xattrs[i]);
if (!i || blkaddr != it->it.blkaddr) {
- ret = blk_read(vi->sbi, 0, it->it.page, blkaddr, 1);
+ ret = erofs_blk_read(vi->sbi, 0, it->it.page, blkaddr, 1);
if (ret < 0)
return -EIO;
it->it.ofs = xattrblock_offset(vi, vi->xattr_shared_xattrs[i]);
if (!i || blkaddr != it->it.blkaddr) {
- ret = blk_read(vi->sbi, 0, it->it.page, blkaddr, 1);
+ ret = erofs_blk_read(vi->sbi, 0, it->it.page, blkaddr, 1);
if (ret < 0)
return -EIO;
* Created by Gao Xiang <xiang@kernel.org>
* Modified by Huang Jianan <huangjianan@oppo.com>
*/
-#include "erofs/io.h"
+#include "erofs/internal.h"
#include "erofs/print.h"
static int z_erofs_do_map_blocks(struct erofs_inode *vi,
return 0;
pos = round_up(erofs_iloc(vi) + vi->inode_isize + vi->xattr_isize, 8);
- ret = dev_read(sbi, 0, buf, pos, sizeof(buf));
+ ret = erofs_dev_read(sbi, 0, buf, pos, sizeof(buf));
if (ret < 0)
return -EIO;
if (map->index == eblk)
return 0;
- ret = blk_read(m->inode->sbi, 0, mpage, eblk, 1);
+ ret = erofs_blk_read(m->inode->sbi, 0, mpage, eblk, 1);
if (ret < 0)
return -EIO;
#include "erofs/diskbuf.h"
#include "erofs/inode.h"
#include "erofs/tar.h"
-#include "erofs/io.h"
#include "erofs/compress.h"
#include "erofs/dedupe.h"
#include "erofs/xattr.h"
list_for_each_entry_safe(src, n, &rebuild_src_list, list) {
list_del(&src->list);
erofs_put_super(src);
- dev_close(src);
+ erofs_dev_close(src);
free(src);
}
rebuild_src_count = 0;
cfg.c_ovlfs_strip = false;
break;
case 517:
- sbi.diskoffset = strtoull(optarg, &endptr, 0);
+ sbi.bdev.offset = strtoull(optarg, &endptr, 0);
if (*endptr != '\0') {
erofs_err("invalid disk offset %s", optarg);
return -EINVAL;
return -ENOMEM;
}
- err = dev_open_ro(src, srcpath);
+ err = erofs_dev_open(src, srcpath, O_RDONLY);
if (err) {
free(src);
erofs_rebuild_cleanup();
}
memcpy(buf + EROFS_SUPER_OFFSET, &sb, sizeof(sb));
- ret = dev_write(&sbi, buf, erofs_btell(bh, false), EROFS_SUPER_END);
+ ret = erofs_dev_write(&sbi, buf, erofs_btell(bh, false), EROFS_SUPER_END);
free(buf);
erofs_bdrop(bh, false);
return ret;
unsigned int len;
struct erofs_super_block *sb;
- ret = blk_read(&sbi, 0, buf, 0, erofs_blknr(&sbi, EROFS_SUPER_END) + 1);
+ ret = erofs_blk_read(&sbi, 0, buf, 0, erofs_blknr(&sbi, EROFS_SUPER_END) + 1);
if (ret) {
erofs_err("failed to read superblock to set checksum: %s",
erofs_strerror(ret));
/* set up checksum field to erofs_super_block */
sb->checksum = cpu_to_le32(crc);
- ret = blk_write(&sbi, buf, 0, 1);
+ ret = erofs_blk_write(&sbi, buf, 0, 1);
if (ret) {
erofs_err("failed to write checksummed superblock: %s",
erofs_strerror(ret));
sbi.build_time_nsec = t.tv_usec;
}
- err = dev_open(&sbi, cfg.c_img_path);
+ err = erofs_dev_open(&sbi, cfg.c_img_path, O_RDWR | O_TRUNC);
if (err) {
fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
return 1;
if (err)
goto exit;
- err = dev_resize(&sbi, nblocks);
+ err = erofs_dev_resize(&sbi, nblocks);
if (!err && erofs_sb_has_sb_chksum(&sbi))
err = erofs_mkfs_superblock_csum_set();
z_erofs_compress_exit();
z_erofs_dedupe_exit();
erofs_blocklist_close();
- dev_close(&sbi);
+ erofs_dev_close(&sbi);
erofs_cleanup_compress_hints();
erofs_cleanup_exclude_rules();
if (cfg.c_chunkbits)