Re: Diff using send-receive code / RFC
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 -- Arvin Schnell, Senior Software Engineer, Research & Development SUSE LINUX Products GmbH, GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer, HRB 16746 (AG Nürnberg) Maxfeldstraße 5 90409 Nürnberg Germany /* * Copyright (c) 2013 Arvin Schnell * * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 021110-1307, USA. */ #define _GNU_SOURCE #include #include #include #include #include #include "btrfs/send.h" #include "btrfs/send-stream.h" #include "btrfs/rbtree.h" #include "btrfs/send-analyser.h" struct tree_root { struct rb_root rb_root; }; struct tree_node { struct rb_node rb_node; char *name; unsigned int status; struct tree_root children; }; static void tree_root_init(struct tree_root *root) { root->rb_root = RB_ROOT; } static struct tree_node *tree_node_init(const char *name) { struct tree_node *node = malloc(sizeof(struct tree_node)); node->name = strdup(name); node->status = 0; tree_root_init(&node->children); return node; } static struct tree_node *tree_find(struct tree_root *root, const char *name) { struct rb_node *rb_node = root->rb_root.rb_node; while (rb_node) { struct tree_node *data = rb_entry(rb_node, struct tree_node, rb_node); int result = strcmp(name, data->name); if (result < 0) rb_node = rb_node->rb_left; else if (result > 0) rb_node = rb_node->rb_right; else return data; } return NULL; } static int tree_insert(struct tree_root *root, struct tree_node *node) { struct rb_node **new = &(root->rb_root.rb_node); struct rb_node *parent = NULL; while (*new) { struct tree_node *this = rb_entry(*new, struct tree_node, rb_node); parent = *new; int result = strcmp(node->name, this->name); if (result < 0) new = &(*new)->rb_left; else if (result > 0) new = &(*new)->rb_right; else return 0; } rb_link_node(&node->rb_node, parent, new); rb_insert_color(&node->rb_node, &root->rb_root); return 1; } /* find node or create new one, return 1 if already existing */ static int tree_find_or_insert(struct tree_root *root, const char *name, struct tree_node **node) { struct rb_node **new = &(root->rb_root.rb_node); struct rb_node *parent = NULL; while (*new) { struct tree_node *this = rb_entry(*new, struct tree_node, rb_node); parent = *new; int result = strcmp(name, this->name); if (result < 0) new = &(*new)->rb_left; else if (result > 0) new = &(*new)->rb_right; else { *node = this; return 1; } } *node = tree_node_init(name); rb_link_node(&(*node)->rb_node, parent, new); rb_insert_color(&(*node)->rb_node, &root->rb_root); return 0; } static void tree_remove(struct tree_root *root, struct tree_node *node) { rb_erase(&node->rb_node, &root->rb_root); free(node->name); free(node); } static void tree_cut(struct tree_root *root, struct tree_node *node) { rb_erase(&node->rb_node, &root->rb_root); } static struct tree_node *tree_node_first(struct tree_root *root) { struct rb_node *rb_node = rb_first(&root->rb_root); if (!rb_node) return NULL; return rb_entry(rb_node, struct tree_node, rb_node); } static struct tree_node *tree_node_next(struct tree_node *node) { struct rb_node *rb_node = rb_next(&node->rb_node); if (!rb_node) return NULL; return rb_entry(rb_node, struct tree_node, rb_no
Re: Deleted subvolume reappears and other cleaner issues
Thanks for your comments, Josef. Another thing that confuses me is that there are some cases, in which btrfs_drop_snapshot() has a failure, but still returns 0, like for example, if btrfs_del_root() fails. (For cases when btrfs_drop_snapshot() returns non-zero there is a BUG_ON). So in this case for me __btrfs_abort_transaction() sees that trans->blocks_used==0, so it doesn't call __btrfs_std_error, which would further force the filesystem to become RO. So after that btrfs_drop_snapshot successfully completes, and, basically, nobody will retry the subvol deletion. In addition, in this case, after couple of seconds the machine completely freezes for me. I have not yet succeeded to determine why. Thanks, Alex. On Wed, Feb 6, 2013 at 5:14 PM, Josef Bacik wrote: > On Thu, Jan 31, 2013 at 06:03:06AM -0700, Alex Lyakas wrote: >> Hi, >> I want to check if any of the below issues are worth/should be fixed: >> >> # btrfs_ioctl_snap_destroy() does not commit a transaction. As a >> result, user can ask to delete a subvol, he receives "ok" back. Even >> if user does "btrfs sub list", >> he will not see the deleted subvol (even though the transaction was >> not committed yet). But if a crash happens, ORPHAN_ITEM will not >> re-appear after crash. >> So after crash, the subvolume still exists perfectly fine (happened >> couple of times here). > > Same thing happens to normal unlinks, I don't see a reason to have different > rules for subvols. > >> >> # btrfs_drop_snapshot() does not commit a transaction after >> btrfs_del_orphan_item(). So if the subvol deletion completed in one go >> (did not have to detach and re-attach to transaction, thus committing >> the ORPHAN_ITEM and drop_progress/level), then after crash ORPHAN_ITEM >> will not be in the tree, and subvolume still exists. >> > > Again same thing happens with normal files. > >> # btrfs_drop_snapshot() checks btrfs_should_end_transaction(), and >> then does btrfs_end_transaction_throttle() and >> btrfs_start_transaction(). However, it looks like it can rejoin the >> same transaction if transaction was not not blocked yet. Minor issue, >> perhaps? > > No if we didn't block then its ok and we wait longer, we only throttle to give > the transaction stuff a chance to commit, so if the join logic decides its ok > to > go on then we're good. > >> >> # umount may get delayed because of pending-for-deletion subvolumes: >> btrfs_commit_super() locks the cleaner_mutex, so it will wait for the >> cleaner to complete. >> On the other hand, cleaner will not give up until it completes >> processing all its splice. If currently cleaner is not running, then >> btrfs_commit_super() >> calls btrfs_clean_old_snapshots() directly. So does it make sense: >> - btrfs_commit_super() will not call btrfs_clean_old_snapshots() >> - close_ctree() calls kthread_stop(cleaner_kthread) early, and cleaner >> thread periodically checks if it needs to exit > > I don't quite follow this, but sure? Thanks, > > Josef -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: btrfs and LVM snapshots (Re: kernel BUG at fs/btrfs/extent-tree.c:1772)
On 02/10/2013 01:32 AM, Piotr Pawłow wrote: > Hello, >> Yeah you can't mount images, we clear out the chunk tree so >> nothing works. Let me know if you run into any problems in the >> future. Thanks, > > That's surprising, I haven't seen it mentioned anywhere. > > With any other filesystem I could use an LVM snapshot to save the > original state, but with a multi-device btrfs it would be very > risky. Origin and snapshot volumes could easily get mixed up by > kernel and tools. > > I tried that in qemu, and I've seen btrfs happily mount 1 origin and > 1 snapshot device as a single FS. And then I've seen it mount both > origin devices, even though one of them had old content. Naturally > it complained a lot about bad checksums. I can confirm that, even with a single-device btrfs filesystem. However I am curious why you want to use the lvm snapshot capability instead of the btrfs one. > > Is there any way to avoid such mix-ups? To somehow mark devices so > that btrfs would know these devices belong together? Btrfs assume that every device has an "unique" uuid. However when a device is snapshotted it uuid is copied too, so it is not unique any more. This is the reason of the btrfs confusing. > Regards -- To unsubscribe from this list: send the line "unsubscribe > linux-btrfs" in the body of a message to majord...@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it> Key fingerprint BBF5 1610 0B64 DAC6 5F7D 17B2 0EDA 9B37 8B82 E0B5 ss -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html