summaryrefslogtreecommitdiff
path: root/src/rbd.cc
diff options
context:
space:
mode:
authorSage Weil <sage@inktank.com>2013-03-18 22:54:25 -0700
committerSage Weil <sage@inktank.com>2013-03-18 22:54:25 -0700
commit167451912272c950dc7a33222f549de01f585192 (patch)
tree660198b0408871544a8c1304d847a5b766f90c1c /src/rbd.cc
parentd47759429a6e2fdd392265e90b67046302c97644 (diff)
parent7aec13f749035b9bef5e398c1ac3d56ceec8eb81 (diff)
downloadceph-167451912272c950dc7a33222f549de01f585192.tar.gz
Merge branch 'next'
Diffstat (limited to 'src/rbd.cc')
-rw-r--r--src/rbd.cc279
1 files changed, 79 insertions, 200 deletions
diff --git a/src/rbd.cc b/src/rbd.cc
index 21186dd03e2..ca74769c5bd 100644
--- a/src/rbd.cc
+++ b/src/rbd.cc
@@ -1059,65 +1059,104 @@ done_img:
update_snap_name(*new_img, snap);
}
-static int do_import_from_stdin(librbd::RBD &rbd, librados::IoCtx& io_ctx,
- const char *imgname, int *order, int format,
- int64_t features, int64_t size)
+static int do_import(librbd::RBD &rbd, librados::IoCtx& io_ctx,
+ const char *imgname, int *order, const char *path,
+ int format, uint64_t features, uint64_t size)
{
- int r;
- // start with inherent block size; double as needed; fix when done
- size_t cur_size = 1 << *order;
+ int fd, r;
+ struct stat stat_buf;
+ MyProgressContext pc("Importing image");
- r = do_create(rbd, io_ctx, imgname, cur_size, order, format, features, 0, 0);
- if (r < 0) {
- cerr << "rbd: image creation failed" << std::endl;
- return r;
- }
- librbd::Image image;
- r = rbd.open(io_ctx, image, imgname);
- if (r < 0) {
- cerr << "rbd: failed to open image" << std::endl;
- return r;
- }
+ assert(imgname);
- off_t image_pos = 0;
+ // default order as usual
+ if (*order == 0)
+ *order = 22;
// try to fill whole imgblklen blocks for sparsification
-
+ uint64_t image_pos = 0;
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
+ librbd::Image image;
+
+ bool from_stdin = !strcmp(path, "-");
+ if (from_stdin) {
+ fd = 0;
+ size = 1 << *order;
+ } else {
+ fd = open(path, O_RDONLY);
+
+ if (fd < 0) {
+ r = -errno;
+ cerr << "rbd: error opening " << path << std::endl;
+ return r;
+ }
+
+ r = fstat(fd, &stat_buf);
+ if (r < 0) {
+ r = -errno;
+ cerr << "rbd: stat error " << path << std::endl;
+ goto done;
+ }
+ if (stat_buf.st_size)
+ size = (uint64_t)stat_buf.st_size;
+
+ if (!size) {
+ int64_t bdev_size = 0;
+ r = get_block_device_size(fd, &bdev_size);
+ if (r < 0) {
+ cerr << "rbd: unable to get size of file/block device" << std::endl;
+ goto done;
+ }
+ assert(bdev_size >= 0);
+ size = (uint64_t) bdev_size;
+ }
+ }
+ r = do_create(rbd, io_ctx, imgname, size, order, format, features, 0, 0);
+ if (r < 0) {
+ cerr << "rbd: image creation failed" << std::endl;
+ goto done;
+ }
+ r = rbd.open(io_ctx, image, imgname);
+ if (r < 0) {
+ cerr << "rbd: failed to open image" << std::endl;
+ goto done;
+ }
// loop body handles 0 return, as we may have a block to flush
- while ((readlen = ::read(0, p + blklen, reqlen)) >= 0) {
+ while ((readlen = ::read(fd, 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;
}
+ if (!from_stdin)
+ pc.update_progress(image_pos, 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);
+ bufferlist bl(blklen);
+ bl.append(p, blklen);
+ // resize output image by binary expansion as we go for stdin
+ if (from_stdin && (image_pos + (size_t)blklen) > size) {
+ size *= 2;
+ r = image.resize(size);
if (r < 0) {
cerr << "rbd: can't resize image during import" << std::endl;
- return r;
+ goto done;
}
}
// 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)
+ cerr << "rbd: error writing to image position " << image_pos
<< std::endl;
- return r;
+ goto done;
}
}
// done with whole block, whether written or not
@@ -1128,184 +1167,24 @@ static int do_import_from_stdin(librbd::RBD &rbd, librados::IoCtx& io_ctx,
blklen = 0;
reqlen = imgblklen;
}
- r = image.resize(image_pos);
- if (r < 0) {
- cerr << "rbd: final image resize failed" << std::endl;
- return r;
- }
- return readlen; // 0 or -error
-}
-
-static int do_import(librbd::RBD &rbd, librados::IoCtx& io_ctx,
- const char *imgname, int *order, const char *path,
- int format, uint64_t features, int64_t size)
-{
- int fd, r;
- struct stat stat_buf;
- struct fiemap *fiemap;
- MyProgressContext pc("Importing image");
-
- assert(imgname);
-
- // default order as usual
- if (*order == 0)
- *order = 22;
-
- if (!strcmp(path, "-"))
- return do_import_from_stdin(rbd, io_ctx, imgname, order, format,
- features, size);
- fd = open(path, O_RDONLY);
-
- if (fd < 0) {
- r = -errno;
- cerr << "rbd: error opening " << path << std::endl;
- return r;
- }
-
- r = fstat(fd, &stat_buf);
- if (r < 0) {
- r = -errno;
- cerr << "rbd: stat error " << path << std::endl;
- close(fd);
- return r;
- }
- if (stat_buf.st_size)
- size = (uint64_t)stat_buf.st_size;
-
- if (!size) {
- r = get_block_device_size(fd, &size);
+ if (from_stdin) {
+ r = image.resize(image_pos);
if (r < 0) {
- cerr << "rbd: unable to get size of file/block device: "
- << cpp_strerror(r) << std::endl;
- close(fd);
- return r;
- }
- }
-
- r = do_create(rbd, io_ctx, imgname, size, order, format, features, 0, 0);
- if (r < 0) {
- cerr << "rbd: image creation failed" << std::endl;
- close(fd);
- return r;
- }
- librbd::Image image;
- r = rbd.open(io_ctx, image, imgname);
- if (r < 0) {
- cerr << "rbd: failed to open image" << std::endl;
- close(fd);
- return r;
- }
-
- // flush it first, otherwise extents may not be allocated or readable
- fsync(fd);
- fiemap = read_fiemap(fd);
- if (fiemap && !fiemap->fm_mapped_extents) {
- cerr << "rbd: empty fiemap!" << std::endl;
- free(fiemap);
- fiemap = NULL;
- }
- if (!fiemap) {
- size_t fiemap_size = sizeof(struct fiemap) + sizeof(struct fiemap_extent);
- fiemap = (struct fiemap *)malloc(fiemap_size);
- if (!fiemap) {
- cerr << "rbd: failed to allocate fiemap, not enough memory." << std::endl;
- close(fd);
- return -ENOMEM;
- }
- fiemap->fm_start = 0;
- fiemap->fm_length = size;
- fiemap->fm_flags = 0;
- fiemap->fm_extent_count = 1;
- fiemap->fm_mapped_extents = 1;
- fiemap->fm_extents[0].fe_logical = 0;
- fiemap->fm_extents[0].fe_physical = 0;
- fiemap->fm_extents[0].fe_length = size;
- fiemap->fm_extents[0].fe_flags = 0;
- }
-
- uint64_t extent = 0;
-
- while (extent < fiemap->fm_mapped_extents) {
- off_t file_pos, end_ofs;
- size_t extent_len = 0;
- size_t read_len = 1ULL << *order;
-
- /* position within the file we're reading */
- file_pos = fiemap->fm_extents[extent].fe_logical;
-
- do { /* try to merge consecutive extents */
-#define LARGE_ENOUGH_EXTENT (32 * 1024 * 1024)
- if (extent_len &&
- extent_len + fiemap->fm_extents[extent].fe_length > LARGE_ENOUGH_EXTENT)
- break; /* don't try to merge if we're big enough */
-
- /* length of current extent */
- extent_len += fiemap->fm_extents[extent].fe_length;
- end_ofs = MIN((off_t)size, file_pos + (off_t)extent_len);
-
- extent++;
- if (extent == fiemap->fm_mapped_extents)
- break;
-
- } while (end_ofs == (off_t)fiemap->fm_extents[extent].fe_logical);
-
- uint64_t left = end_ofs - file_pos;
- while (left) {
- pc.update_progress(file_pos, size);
- uint64_t cur_seg = (left < read_len ? left : read_len);
- while (cur_seg) {
- bufferptr p(cur_seg);
- ssize_t rval;
- if(extent == 0 && fiemap->fm_extents[extent].fe_logical == 0) {
- rval = TEMP_FAILURE_RETRY(::read(fd, p.c_str(), cur_seg));
- } else {
- rval = TEMP_FAILURE_RETRY(::pread(fd, p.c_str(), cur_seg, file_pos));
- }
- if (rval < 0) {
- r = -errno;
- cerr << "rbd: error reading file: " << cpp_strerror(r) << std::endl;
- goto done;
- }
- size_t len = rval;
- if (!len) {
- r = 0;
- goto done;
- }
- bufferlist bl;
- bl.append(p);
- librbd::RBD::AioCompletion *completion =
- new librbd::RBD::AioCompletion(NULL, NULL);
- if (!completion) {
- r = -ENOMEM;
- goto done;
- }
- r = image.aio_write(file_pos, len, bl, completion);
- if (r < 0)
- goto done;
- completion->wait_for_complete();
- r = completion->get_return_value();
- completion->release();
- if (r < 0) {
- cerr << "rbd: error writing to image block" << std::endl;
- goto done;
- }
-
- file_pos += len;
- cur_seg -= len;
- left -= len;
- }
+ cerr << "rbd: final image resize failed" << std::endl;
+ goto done;
}
}
r = 0;
done:
- if (r < 0)
- pc.fail();
- else
- pc.finish();
- free(fiemap);
- close(fd);
+ if (!from_stdin) {
+ if (r < 0)
+ pc.fail();
+ else
+ pc.finish();
+ close(fd);
+ }
return r;
}