From patchwork Sun Feb 10 22:19:02 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arvin Schnell X-Patchwork-Id: 2122991 Return-Path: X-Original-To: patchwork-linux-btrfs@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id 0B8D1DF24C for ; Sun, 10 Feb 2013 22:19:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756748Ab3BJWTH (ORCPT ); Sun, 10 Feb 2013 17:19:07 -0500 Received: from cantor2.suse.de ([195.135.220.15]:33676 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756603Ab3BJWTF (ORCPT ); Sun, 10 Feb 2013 17:19:05 -0500 Received: from relay2.suse.de (unknown [195.135.220.254]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx2.suse.de (Postfix) with ESMTP id F2D4DA4386 for ; Sun, 10 Feb 2013 23:19:02 +0100 (CET) Date: Sun, 10 Feb 2013 23:19:02 +0100 From: Arvin Schnell To: linux-btrfs@vger.kernel.org Subject: Re: Diff using send-receive code / RFC Message-ID: <20130210221902.GA7270@suse.de> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.17 (2007-11-01) Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org On Sun, Feb 10, 2013 at 10:21:31PM +0530, nafisa mandliwala wrote: > Hello, > We're a team of 4 final year computer science students and are > working on generating a diff between file system snapshots using the > send receive code. This was just implemented in snapper. Unfortunately I was in a hurry so the code doesn't look so good. Instead of improving the code in snapper (C++) I thought about implementing it in C so that it can be included in btrfsprogs (and libbtrfs). Here is an example: # btrfs send -a -p /testsuite/.snapshots/1/snapshot /testsuite/.snapshots/2/snapshot | cat At subvol /testsuite/.snapshots/2/snapshot Comparing testsuite/.snapshots/1/snapshot and testsuite/.snapshots/2/snapshot. +.... /foo +.... /foo/bar +.... /foo/bar/world Attached you can find my current state. It's completely unfinished and only works from some test-cases. To get it compiled you either need some patches posted here earlier (e.g. NO_FILE_DATA) or must make minor modifications. But I would like to get feedback about this feature on the list. Kind Regards, Arvin diff --git a/cmds-send.c b/cmds-send.c index 9b47e70..340a4d2 100644 --- a/cmds-send.c +++ b/cmds-send.c @@ -39,6 +39,7 @@ #include "send.h" #include "send-utils.h" +#include "send-analyser.h" static int g_verbose = 0; @@ -52,6 +53,9 @@ struct btrfs_send { char *root_path; struct subvol_uuid_search sus; + + int do_analyse; + struct btrfs_stream_analyser analyser; }; int find_mount_root(const char *path, char **mount_root) @@ -209,21 +213,34 @@ static void *dump_thread(void *arg_) char buf[4096]; int readed; - while (1) { - readed = read(s->send_fd, buf, sizeof(buf)); - if (readed < 0) { - ret = -errno; - fprintf(stderr, "ERROR: failed to read stream from " + if (!s->do_analyse) + { + while (1) { + readed = read(s->send_fd, buf, sizeof(buf)); + if (readed < 0) { + ret = -errno; + fprintf(stderr, "ERROR: failed to read stream from " "kernel. %s\n", strerror(-ret)); - goto out; + goto out; + } + if (!readed) { + ret = 0; + goto out; + } + ret = write_buf(s->dump_fd, buf, readed); + if (ret < 0) + goto out; } - if (!readed) { - ret = 0; - goto out; + } + else + { + while (1) { + ret = analyser_process(&s->analyser, s->send_fd); + if (ret == 0) + goto out; + if (ret < 0) + goto out; } - ret = write_buf(s->dump_fd, buf, readed); - if (ret < 0) - goto out; } out: @@ -234,6 +251,31 @@ out: return ERR_PTR(ret); } + +static void setup(struct btrfs_send *s, u64 root_id1, u64 root_id2) +{ + struct subvol_info *si1 = subvol_uuid_search(&s->sus, root_id1, NULL, 0, + NULL, subvol_search_by_root_id); + assert(si1); + s->analyser.fd1 = open(si1->path, O_RDONLY | O_NOATIME); + + struct subvol_info *si2 = subvol_uuid_search(&s->sus, root_id2, NULL, 0, + NULL, subvol_search_by_root_id); + assert(si2); + s->analyser.fd2 = open(si2->path, O_RDONLY | O_NOATIME); + + fprintf(stderr, "Comparing %s and %s.\n", si1->path, si2->path); +} + + +static void output(const char *path, unsigned int status, void *user) +{ + char *s = analyser_status_to_string(status); + printf("%s %s\n", s, path); + free(s); +} + + static int do_send(struct btrfs_send *send, u64 root_id, u64 parent_root) { int ret; @@ -274,6 +316,13 @@ static int do_send(struct btrfs_send *send, u64 root_id, u64 parent_root) io_send.send_fd = pipefd[1]; send->send_fd = pipefd[0]; + if (send->do_analyse) + { + analyser_create(&send->analyser); + setup(send, parent_root, root_id); + io_send.flags = BTRFS_SEND_FLAG_NO_FILE_DATA; + } + if (!ret) ret = pthread_create(&t_read, &t_attr, dump_thread, send); @@ -321,6 +370,11 @@ static int do_send(struct btrfs_send *send, u64 root_id, u64 parent_root) ret = 0; + if (send->do_analyse) + { + analyser_result(&send->analyser, output, NULL); + } + out: if (subvol_fd != -1) close(subvol_fd); @@ -427,7 +481,7 @@ int cmd_send_start(int argc, char **argv) memset(&send, 0, sizeof(send)); send.dump_fd = fileno(stdout); - while ((c = getopt(argc, argv, "vf:i:p:")) != -1) { + while ((c = getopt(argc, argv, "vf:i:p:a")) != -1) { switch (c) { case 'v': g_verbose++; @@ -468,6 +522,9 @@ int cmd_send_start(int argc, char **argv) goto out; } break; + case 'a': + send.do_analyse = 1; + break; case '?': default: fprintf(stderr, "ERROR: send args invalid.\n"); @@ -630,6 +687,7 @@ static const char * const cmd_send_usage[] = { "-v Enable verbose debug output. Each", " occurrency of this option increases the", " verbose level more.", + "-a Analyse the stream.", "-i Informs btrfs send that this subvolume,", " can be taken as 'clone source'. This can", " be used for incremental sends.",