/* * Copyright (C) 2013 Fusion IO. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 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. */ #include #include #include #include "btrfs-tests.h" #include "../ctree.h" #include "../volumes.h" #include "../disk-io.h" #include "../qgroup.h" static struct vfsmount *test_mnt = NULL; static const struct super_operations btrfs_test_super_ops = { .alloc_inode = btrfs_alloc_inode, .destroy_inode = btrfs_test_destroy_inode, }; static struct dentry *btrfs_test_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { return mount_pseudo(fs_type, "btrfs_test:", &btrfs_test_super_ops, NULL, BTRFS_TEST_MAGIC); } static struct file_system_type test_type = { .name = "btrfs_test_fs", .mount = btrfs_test_mount, .kill_sb = kill_anon_super, }; struct inode *btrfs_new_test_inode(void) { return new_inode(test_mnt->mnt_sb); } int btrfs_init_test_fs(void) { int ret; ret = register_filesystem(&test_type); if (ret) { printk(KERN_ERR "btrfs: cannot register test file system\n"); return ret; } test_mnt = kern_mount(&test_type); if (IS_ERR(test_mnt)) { printk(KERN_ERR "btrfs: cannot mount test file system\n"); unregister_filesystem(&test_type); return ret; } return 0; } void btrfs_destroy_test_fs(void) { kern_unmount(test_mnt); unregister_filesystem(&test_type); } struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(void) { struct btrfs_fs_info *fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS); if (!fs_info) return fs_info; fs_info->fs_devices = kzalloc(sizeof(struct btrfs_fs_devices), GFP_NOFS); if (!fs_info->fs_devices) { kfree(fs_info); return NULL; } fs_info->super_copy = kzalloc(sizeof(struct btrfs_super_block), GFP_NOFS); if (!fs_info->super_copy) { kfree(fs_info->fs_devices); kfree(fs_info); return NULL; } if (init_srcu_struct(&fs_info->subvol_srcu)) { kfree(fs_info->fs_devices); kfree(fs_info->super_copy); kfree(fs_info); return NULL; } spin_lock_init(&fs_info->buffer_lock); spin_lock_init(&fs_info->qgroup_lock); spin_lock_init(&fs_info->qgroup_op_lock); spin_lock_init(&fs_info->super_lock); spin_lock_init(&fs_info->fs_roots_radix_lock); spin_lock_init(&fs_info->tree_mod_seq_lock); mutex_init(&fs_info->qgroup_ioctl_lock); mutex_init(&fs_info->qgroup_rescan_lock); rwlock_init(&fs_info->tree_mod_log_lock); fs_info->running_transaction = NULL; fs_info->qgroup_tree = RB_ROOT; fs_info->qgroup_ulist = NULL; atomic64_set(&fs_info->tree_mod_seq, 0); INIT_LIST_HEAD(&fs_info->dirty_qgroups); INIT_LIST_HEAD(&fs_info->dead_roots); INIT_LIST_HEAD(&fs_info->tree_mod_seq_list); INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC); INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC); return fs_info; } static void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info) { struct radix_tree_iter iter; void **slot; spin_lock(&fs_info->buffer_lock); restart: radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) { struct extent_buffer *eb; eb = radix_tree_deref_slot_protected(slot, &fs_info->buffer_lock); if (!eb) continue; /* Shouldn't happen but that kind of thinking creates CVE's */ if (radix_tree_exception(eb)) { if (radix_tree_deref_retry(eb)) goto restart; continue; } spin_unlock(&fs_info->buffer_lock); free_extent_buffer_stale(eb); spin_lock(&fs_info->buffer_lock); } spin_unlock(&fs_info->buffer_lock); btrfs_free_qgroup_config(fs_info); btrfs_free_fs_roots(fs_info); cleanup_srcu_struct(&fs_info->subvol_srcu); kfree(fs_info->super_copy); kfree(fs_info->fs_devices); kfree(fs_info); } void btrfs_free_dummy_root(struct btrfs_root *root) { if (!root) return; if (root->node) free_extent_buffer(root->node); if (root->fs_info) btrfs_free_dummy_fs_info(root->fs_info); kfree(root); }