From patchwork Fri Aug 26 18:51:17 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Brunner X-Patchwork-Id: 1102752 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p7QIqq9U005622 for ; Fri, 26 Aug 2011 18:52:52 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752467Ab1HZSwu (ORCPT ); Fri, 26 Aug 2011 14:52:50 -0400 Received: from mail-bw0-f46.google.com ([209.85.214.46]:36600 "EHLO mail-bw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751703Ab1HZSwt (ORCPT ); Fri, 26 Aug 2011 14:52:49 -0400 Received: by bke11 with SMTP id 11so2759248bke.19 for ; Fri, 26 Aug 2011 11:52:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=sender:date:from:to:subject:message-id:mime-version:content-type :content-disposition:user-agent; bh=DhgIXby2uTjowFw1U3n9A490aHz+7lyLjSlfHTyp6RU=; b=HcKHdNR9TUWxz+9L9VwSmUEpLZOvkWqf4WQOKAi8UVCOpoldKBYCe5kqDwswFlJfZo uPjQYIjkuOOuDKQCudK/RGvnSI7vaI9m0G+aL+MQt8fmR0m+45l63/4+XD7AUMc3oJTI 2Ge2DpbYZ1plQ1h+wtVz964NBH+/xWBmhGbho= Received: by 10.204.148.154 with SMTP id p26mr852992bkv.160.1314384768176; Fri, 26 Aug 2011 11:52:48 -0700 (PDT) Received: from sir.fritz.box (e181005048.adsl.alicedsl.de [85.181.5.48]) by mx.google.com with ESMTPS id z6sm536834bks.24.2011.08.26.11.52.44 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 26 Aug 2011 11:52:45 -0700 (PDT) Date: Fri, 26 Aug 2011 20:51:17 +0200 From: Christian Brunner To: ceph-devel@vger.kernel.org Subject: [PATCH 2/2] rbd: add an option for md5 checksumming (v3) Message-ID: <20110826185117.GA19365@sir.fritz.box> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-12-10) Sender: ceph-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: ceph-devel@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Fri, 26 Aug 2011 18:52:52 +0000 (UTC) We needed to get an md5 checksum of an rbd image. Since librbd is using a lot of sparse operations, this was not possible without writing an image to a local disk. With this patch exporting the image is no longer needed. You can do "rbd md5 image" and you will get the same output as you would call "md5sum". V1 -> V2: - use ceph::crypto classes - support for sha1 - skip holes V2 -> V3: - better handling for holes --- src/rbd.cc | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 118 insertions(+), 22 deletions(-) diff --git a/src/rbd.cc b/src/rbd.cc index a18c029..9a40941 100644 --- a/src/rbd.cc +++ b/src/rbd.cc @@ -38,6 +38,8 @@ #include #include +#include "common/ceph_crypto.h" + #include "include/rbd_types.h" #include @@ -49,6 +51,30 @@ static string dir_oid = RBD_DIRECTORY; static string dir_info_oid = RBD_INFO; +static size_t lastofs; + +enum { + OPT_NO_CMD = 0, + OPT_LIST, + OPT_INFO, + OPT_CREATE, + OPT_RESIZE, + OPT_RM, + OPT_EXPORT, + OPT_IMPORT, + OPT_COPY, + OPT_RENAME, + OPT_SNAP_CREATE, + OPT_SNAP_ROLLBACK, + OPT_SNAP_REMOVE, + OPT_SNAP_LIST, + OPT_WATCH, + OPT_MAP, + OPT_UNMAP, + OPT_SHOWMAPPED, + OPT_MD5, + OPT_SHA1, +}; void usage() { @@ -65,6 +91,8 @@ void usage() << " export [image-name] [dest-path] export image to file\n" << " import [path] [dst-image] import image from file (dest defaults\n" << " as the filename part of file)\n" + << " md5 [image-name] print md5 checksum for image\n" + << " sha1 [image-name] print sha1 checksum for image\n" << " [src-image] [dest-image] copy image to dest\n" << " [src-image] [dest-image] copy image to dest\n" << " snap ls [image-name] dump list of image snapshots\n" @@ -262,6 +290,78 @@ static int do_export(librbd::Image& image, const char *path) return 0; } +static int hash_read_cb(uint64_t ofs, size_t len, const char *buf, void *arg) +{ + ceph::crypto::Digest *Hash = (ceph::crypto::Digest *)arg; + byte *hashbuf = (byte *) buf; + byte *tempbuf = NULL; + + if (!buf) { + len = ofs-lastofs; + tempbuf = (byte *) malloc(len); + if (!tempbuf) + return -ENOMEM; + hashbuf = tempbuf; + } + Hash->Update((const byte *) hashbuf, len); + + lastofs = ofs + len; + + free(tempbuf); + + return 0; +} + +static int do_hash(librbd::Image& image, const char *imgname, int opt_cmd) +{ + int64_t r, i, digest_size; + byte *digest; + char hexval[] = "0123456789abcdef"; + char *hexdigest; + librbd::image_info_t info; + ceph::crypto::Digest *Hash; + + lastofs = 0; + + if (opt_cmd == OPT_MD5) { + Hash = (ceph::crypto::Digest *) new ceph::crypto::MD5; + } else if (opt_cmd == OPT_SHA1) { + Hash = (ceph::crypto::Digest *) new ceph::crypto::SHA1; + } else { + return -1; + } + + r = image.stat(info, sizeof(info)); + if (r < 0) + return r; + + r = image.read_iterate(0, info.size, hash_read_cb, (void *)Hash); + if (r < 0) + return r; + + if (lastofs < info.size) { + hash_read_cb(info.size, 0, NULL, (void *)Hash); + } + + digest_size = Hash->DigestSize(); + digest = (byte *) malloc(digest_size); + hexdigest = (char *) malloc((digest_size * 2 + 1) * sizeof(char)); + Hash->Final(digest); + + for(i = 0; i < digest_size; i++){ + hexdigest[i*2] = hexval[((digest[i] >> 4) & 0xF)]; + hexdigest[(i*2) + 1] = hexval[(digest[i]) & 0x0F]; + } + hexdigest[(digest_size*2)] = '\0'; + + cout << hexdigest << " " << imgname << std::endl; + + free(hexdigest); + free(digest); + + return 0; +} + static const char *imgname_from_path(const char *path) { const char *imgname; @@ -720,27 +820,6 @@ static int do_kernel_rm(const char *dev) return r; } -enum { - OPT_NO_CMD = 0, - OPT_LIST, - OPT_INFO, - OPT_CREATE, - OPT_RESIZE, - OPT_RM, - OPT_EXPORT, - OPT_IMPORT, - OPT_COPY, - OPT_RENAME, - OPT_SNAP_CREATE, - OPT_SNAP_ROLLBACK, - OPT_SNAP_REMOVE, - OPT_SNAP_LIST, - OPT_WATCH, - OPT_MAP, - OPT_UNMAP, - OPT_SHOWMAPPED, -}; - static int get_cmd(const char *cmd, bool *snapcmd) { if (strcmp(cmd, "snap") == 0) { @@ -766,6 +845,10 @@ static int get_cmd(const char *cmd, bool *snapcmd) return OPT_EXPORT; if (strcmp(cmd, "import") == 0) return OPT_IMPORT; + if (strcmp(cmd, "md5") == 0) + return OPT_MD5; + if (strcmp(cmd, "sha1") == 0) + return OPT_SHA1; if (strcmp(cmd, "copy") == 0 || strcmp(cmd, "cp") == 0) return OPT_COPY; @@ -888,6 +971,10 @@ int main(int argc, const char **argv) case OPT_IMPORT: set_conf_param(CEPH_ARGPARSE_VAL, &path, &destname); break; + case OPT_MD5: + case OPT_SHA1: + set_conf_param(CEPH_ARGPARSE_VAL, &imgname, NULL); + break; case OPT_COPY: case OPT_RENAME: set_conf_param(CEPH_ARGPARSE_VAL, &imgname, &destname); @@ -966,7 +1053,7 @@ int main(int argc, const char **argv) (opt_cmd == OPT_RESIZE || opt_cmd == OPT_INFO || opt_cmd == OPT_SNAP_LIST || opt_cmd == OPT_SNAP_CREATE || opt_cmd == OPT_SNAP_ROLLBACK || opt_cmd == OPT_SNAP_REMOVE || opt_cmd == OPT_EXPORT || opt_cmd == OPT_WATCH || - opt_cmd == OPT_COPY)) { + opt_cmd == OPT_COPY || opt_cmd == OPT_MD5 || opt_cmd == OPT_SHA1 )) { r = rbd.open(io_ctx, image, imgname); if (r < 0) { cerr << "error opening image " << imgname << ": " << strerror(r) << std::endl; @@ -1127,6 +1214,15 @@ int main(int argc, const char **argv) } break; + case OPT_MD5: + case OPT_SHA1: + r = do_hash(image, imgname, opt_cmd); + if (r < 0) { + cerr << "hashing failed: " << strerror(-r) << std::endl; + exit(1); + } + break; + case OPT_COPY: r = do_copy(image, dest_io_ctx, destname); if (r < 0) {