return r;
}
- size_t readlen;
- off_t file_pos = 0;
-
- size_t len = 1 << *order;
- bufferptr p(len);
+ off_t image_pos = 0;
+
+ // try to fill whole imgblklen blocks for sparsification
+
+ size_t imgblklen = 1 << *order;
+ char *p = new char[imgblklen];
+ size_t reqlen = imgblklen; // amount requested from read
+ ssize_t readlen; // amount received from one read
+ size_t blklen = 0; // amount accumulated from reads to fill blk
+
+ // loop body handles 0 return, as we may have a block to flush
+ while ((readlen = ::read(0, p + blklen, reqlen)) >= 0) {
+ blklen += readlen;
+ // if read was short, try again to fill the block before writing
+ if (readlen && ((size_t)readlen < reqlen)) {
+ reqlen -= readlen;
+ continue;
+ }
- while ((readlen = ::read(0, p.c_str(), len)) > 0) {
- bufferlist bl;
- bl.append(p);
- if ((file_pos + readlen) > cur_size) {
+ // resize output image by binary expansion as we go
+ if ((image_pos + (size_t)blklen) > cur_size) {
cur_size *= 2;
r = image.resize(cur_size);
if (r < 0) {
return r;
}
}
- r = image.write(file_pos, readlen, bl);
- if (r < 0) {
- cerr << "rbd: error writing to image block" << std::endl;
- return r;
+
+ // write as much as we got; perhaps less than imgblklen
+ bufferlist bl(blklen);
+ bl.append(p, blklen);
+ // but skip writing zeros to create sparse images
+ if (!bl.is_zero()) {
+ r = image.write(image_pos, blklen, bl);
+ if (r < 0) {
+ cerr << "rbd: error writing to image block" << cpp_strerror(r) << std::endl;
+ return r;
+ }
}
- file_pos += readlen;
+ // done with whole block, whether written or not
+ image_pos += blklen;
+ // if read had returned 0, we're at EOF and should quit
+ if (readlen == 0)
+ break;
+ blklen = 0;
+ reqlen = imgblklen;
}
- r = image.resize(file_pos);
+ r = image.resize(image_pos);
if (r < 0) {
cerr << "rbd: final image resize failed" << std::endl;
return r;
}
- return readlen; // 0 or error
+ return readlen; // 0 or -error
}
static int do_import(librbd::RBD &rbd, librados::IoCtx& io_ctx,