in fs/aligned-file.cpp [192:265]
virtual ssize_t pwritev2_mutable(struct iovec *iov, int iovcnt, off_t offset, int flags) override {
struct iovec tmpiovec[MAX_TMP_IOVEC_SIZE];
iovector_view view(tmpiovec, MAX_TMP_IOVEC_SIZE);
iovector_view buf(iov, iovcnt);
auto count = buf.sum();
if (count == 0) return 0;
range_split_power2 rs(offset, count, m_alignment);
if (rs.is_aligned() && (!m_align_memory || iov_align_check(buf)))
return m_file->pwritev2_mutable(iov, iovcnt, offset, flags);
struct stat stat;
m_file->fstat(&stat);
ssize_t filesize = stat.st_size;
auto suppose_filesize = (offset + (ssize_t)count) > filesize ? offset + count: filesize;
IOVector wbuf(m_allocator);
auto ret = wbuf.push_back(rs.aligned_length());
if (ret < rs.aligned_length())
LOG_ERROR_RETURN(0, -1, "Failed to allocate memory");
if (rs.begin_remainder > 0)
{
view.iovcnt = MAX_TMP_IOVEC_SIZE;
ssize_t ret = wbuf.slice(m_alignment, 0, &view);
assert(ret == m_alignment);
ssize_t off = rs.aligned_begin_offset();
ret = m_file->preadv2(view.iov, view.iovcnt, off, flags);
if ((ret < 0) || ((off + ret < filesize) && (ret < (ssize_t)m_alignment)))
LOG_ERRNO_RETURN(0, -1, "failed to aligned [`]->preadv2(iov=`, iovcnt=`, offset=`, flags=`) and patch the first alignment block",
m_file, view.iov, view.iovcnt, off, flags);
if (ret < (ssize_t)m_alignment) {
view.extract_front(ret);
for (auto &p : view) {
memset(p.iov_base, 0, p.iov_len);
}
}
}
if (!rs.small_note && rs.end_remainder > 0)
{
ssize_t off = rs.aligned_end_offset() - m_alignment; // this should never be negative
if (filesize - off > (ssize_t)(rs.end_remainder)) {
// that means there is still parts of data after the rear end of pwrite block
view.iovcnt = MAX_TMP_IOVEC_SIZE;
ssize_t ret = wbuf.slice(m_alignment, wbuf.sum() - m_alignment, &view);
assert(ret == m_alignment);
ret = m_file->preadv2(view.iov, view.iovcnt, off, flags);
if (ret < 0)
LOG_ERRNO_RETURN(0, -1, "failed to aligned [`]->preadv2(ptr=`, count=`, offset=`, flags=`)",
m_file, view.iov, view.iovcnt, off, flags);
if ((ret + off < filesize) && (ret < (ssize_t)m_alignment)) // cannot fetch all data of file, and cannot fillup aligned block
LOG_ERRNO_RETURN(0, -1, "aligned [`]->preadv2(ptr=`, count=`, offset=`, flags=`) partial read",
m_file, view.iov, view.iovcnt, off, flags);
}
}
view.iovcnt = MAX_TMP_IOVEC_SIZE;
ret = wbuf.slice(count, rs.begin_remainder, &view);
assert(ret == count);
ret = view.memcpy_from(&buf, count);
assert(ret == count);
auto actual_write = m_file->pwritev2_mutable(wbuf.iovec(), wbuf.iovcnt(), rs.aligned_begin_offset(), flags);
auto current_tail = rs.aligned_begin_offset() + actual_write;
if ((ssize_t)current_tail < offset)
LOG_ERRNO_RETURN(0, -1, "failed to pwritev2");
if (suppose_filesize < current_tail) { // that means have written more than needs
m_file->ftruncate(suppose_filesize);
current_tail = suppose_filesize;
} else { // means pwrite will not extend file
}
auto count_write = current_tail - offset;
if (count_write > count)
count_write = count;
return count_write;
}