Loading fs/btrfs/disk-io.c +0 −2 Original line number Diff line number Diff line Loading @@ -2278,9 +2278,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, (unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node), BTRFS_UUID_SIZE); mutex_lock(&fs_info->chunk_mutex); ret = btrfs_read_chunk_tree(chunk_root); mutex_unlock(&fs_info->chunk_mutex); if (ret) { printk(KERN_WARNING "btrfs: failed to read chunk tree on %s\n", sb->s_id); Loading fs/btrfs/extent-tree.c +2 −1 Original line number Diff line number Diff line Loading @@ -7143,7 +7143,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) * space to fit our block group in. */ if (device->total_bytes > device->bytes_used + min_free) { ret = find_free_dev_extent(NULL, device, min_free, ret = find_free_dev_extent(device, min_free, &dev_offset, NULL); if (!ret) dev_nr++; Loading Loading @@ -7505,6 +7505,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, ret = update_space_info(root->fs_info, cache->flags, size, bytes_used, &cache->space_info); BUG_ON(ret); update_global_block_rsv(root->fs_info); spin_lock(&cache->space_info->lock); cache->space_info->bytes_readonly += cache->bytes_super; Loading fs/btrfs/free-space-cache.c +196 −97 Original line number Diff line number Diff line Loading @@ -319,11 +319,13 @@ static void io_ctl_drop_pages(struct io_ctl *io_ctl) io_ctl_unmap_page(io_ctl); for (i = 0; i < io_ctl->num_pages; i++) { if (io_ctl->pages[i]) { ClearPageChecked(io_ctl->pages[i]); unlock_page(io_ctl->pages[i]); page_cache_release(io_ctl->pages[i]); } } } static int io_ctl_prepare_pages(struct io_ctl *io_ctl, struct inode *inode, int uptodate) Loading Loading @@ -635,7 +637,10 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode, if (!num_entries) return 0; io_ctl_init(&io_ctl, inode, root); ret = io_ctl_init(&io_ctl, inode, root); if (ret) return ret; ret = readahead_cache(inode); if (ret) goto out; Loading Loading @@ -838,7 +843,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, struct io_ctl io_ctl; struct list_head bitmap_list; struct btrfs_key key; u64 start, end, len; u64 start, extent_start, extent_end, len; int entries = 0; int bitmaps = 0; int ret; Loading @@ -849,7 +854,9 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, if (!i_size_read(inode)) return -1; io_ctl_init(&io_ctl, inode, root); ret = io_ctl_init(&io_ctl, inode, root); if (ret) return -1; /* Get the cluster for this block_group if it exists */ if (block_group && !list_empty(&block_group->cluster_list)) Loading @@ -857,25 +864,12 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, struct btrfs_free_cluster, block_group_list); /* * We shouldn't have switched the pinned extents yet so this is the * right one */ unpin = root->fs_info->pinned_extents; /* Lock all pages first so we can lock the extent safely. */ io_ctl_prepare_pages(&io_ctl, inode, 0); lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1, 0, &cached_state, GFP_NOFS); /* * When searching for pinned extents, we need to start at our start * offset. */ if (block_group) start = block_group->key.objectid; node = rb_first(&ctl->free_space_offset); if (!node && cluster) { node = rb_first(&cluster->root); Loading Loading @@ -918,9 +912,20 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, * We want to add any pinned extents to our free space cache * so we don't leak the space */ /* * We shouldn't have switched the pinned extents yet so this is the * right one */ unpin = root->fs_info->pinned_extents; if (block_group) start = block_group->key.objectid; while (block_group && (start < block_group->key.objectid + block_group->key.offset)) { ret = find_first_extent_bit(unpin, start, &start, &end, ret = find_first_extent_bit(unpin, start, &extent_start, &extent_end, EXTENT_DIRTY); if (ret) { ret = 0; Loading @@ -928,20 +933,21 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, } /* This pinned extent is out of our range */ if (start >= block_group->key.objectid + if (extent_start >= block_group->key.objectid + block_group->key.offset) break; len = block_group->key.objectid + block_group->key.offset - start; len = min(len, end + 1 - start); extent_start = max(extent_start, start); extent_end = min(block_group->key.objectid + block_group->key.offset, extent_end + 1); len = extent_end - extent_start; entries++; ret = io_ctl_add_entry(&io_ctl, start, len, NULL); ret = io_ctl_add_entry(&io_ctl, extent_start, len, NULL); if (ret) goto out_nospc; start = end + 1; start = extent_end; } /* Write out the bitmaps */ Loading Loading @@ -2574,17 +2580,57 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster) cluster->block_group = NULL; } int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, u64 *trimmed, u64 start, u64 end, u64 minlen) static int do_trimming(struct btrfs_block_group_cache *block_group, u64 *total_trimmed, u64 start, u64 bytes, u64 reserved_start, u64 reserved_bytes) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; struct btrfs_free_space *entry = NULL; struct btrfs_space_info *space_info = block_group->space_info; struct btrfs_fs_info *fs_info = block_group->fs_info; u64 bytes = 0; u64 actually_trimmed; int ret = 0; int ret; int update = 0; u64 trimmed = 0; *trimmed = 0; spin_lock(&space_info->lock); spin_lock(&block_group->lock); if (!block_group->ro) { block_group->reserved += reserved_bytes; space_info->bytes_reserved += reserved_bytes; update = 1; } spin_unlock(&block_group->lock); spin_unlock(&space_info->lock); ret = btrfs_error_discard_extent(fs_info->extent_root, start, bytes, &trimmed); if (!ret) *total_trimmed += trimmed; btrfs_add_free_space(block_group, reserved_start, reserved_bytes); if (update) { spin_lock(&space_info->lock); spin_lock(&block_group->lock); if (block_group->ro) space_info->bytes_readonly += reserved_bytes; block_group->reserved -= reserved_bytes; space_info->bytes_reserved -= reserved_bytes; spin_unlock(&space_info->lock); spin_unlock(&block_group->lock); } return ret; } static int trim_no_bitmap(struct btrfs_block_group_cache *block_group, u64 *total_trimmed, u64 start, u64 end, u64 minlen) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; struct btrfs_free_space *entry; struct rb_node *node; int ret = 0; u64 extent_start; u64 extent_bytes; u64 bytes; while (start < end) { spin_lock(&ctl->tree_lock); Loading @@ -2595,81 +2641,118 @@ int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, } entry = tree_search_offset(ctl, start, 0, 1); if (!entry) entry = tree_search_offset(ctl, offset_to_bitmap(ctl, start), 1, 1); if (!entry || entry->offset >= end) { if (!entry) { spin_unlock(&ctl->tree_lock); break; } if (entry->bitmap) { ret = search_bitmap(ctl, entry, &start, &bytes); if (!ret) { if (start >= end) { /* skip bitmaps */ while (entry->bitmap) { node = rb_next(&entry->offset_index); if (!node) { spin_unlock(&ctl->tree_lock); goto out; } entry = rb_entry(node, struct btrfs_free_space, offset_index); } if (entry->offset >= end) { spin_unlock(&ctl->tree_lock); break; } bytes = min(bytes, end - start); bitmap_clear_bits(ctl, entry, start, bytes); if (entry->bytes == 0) free_bitmap(ctl, entry); } else { start = entry->offset + BITS_PER_BITMAP * block_group->sectorsize; extent_start = entry->offset; extent_bytes = entry->bytes; start = max(start, extent_start); bytes = min(extent_start + extent_bytes, end) - start; if (bytes < minlen) { spin_unlock(&ctl->tree_lock); ret = 0; continue; goto next; } } else { start = entry->offset; bytes = min(entry->bytes, end - start); unlink_free_space(ctl, entry); kmem_cache_free(btrfs_free_space_cachep, entry); } spin_unlock(&ctl->tree_lock); if (bytes >= minlen) { struct btrfs_space_info *space_info; int update = 0; ret = do_trimming(block_group, total_trimmed, start, bytes, extent_start, extent_bytes); if (ret) break; next: start += bytes; space_info = block_group->space_info; spin_lock(&space_info->lock); spin_lock(&block_group->lock); if (!block_group->ro) { block_group->reserved += bytes; space_info->bytes_reserved += bytes; update = 1; if (fatal_signal_pending(current)) { ret = -ERESTARTSYS; break; } spin_unlock(&block_group->lock); spin_unlock(&space_info->lock); ret = btrfs_error_discard_extent(fs_info->extent_root, start, bytes, &actually_trimmed); cond_resched(); } out: return ret; } btrfs_add_free_space(block_group, start, bytes); if (update) { spin_lock(&space_info->lock); spin_lock(&block_group->lock); if (block_group->ro) space_info->bytes_readonly += bytes; block_group->reserved -= bytes; space_info->bytes_reserved -= bytes; spin_unlock(&space_info->lock); spin_unlock(&block_group->lock); static int trim_bitmaps(struct btrfs_block_group_cache *block_group, u64 *total_trimmed, u64 start, u64 end, u64 minlen) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; struct btrfs_free_space *entry; int ret = 0; int ret2; u64 bytes; u64 offset = offset_to_bitmap(ctl, start); while (offset < end) { bool next_bitmap = false; spin_lock(&ctl->tree_lock); if (ctl->free_space < minlen) { spin_unlock(&ctl->tree_lock); break; } entry = tree_search_offset(ctl, offset, 1, 0); if (!entry) { spin_unlock(&ctl->tree_lock); next_bitmap = true; goto next; } bytes = minlen; ret2 = search_bitmap(ctl, entry, &start, &bytes); if (ret2 || start >= end) { spin_unlock(&ctl->tree_lock); next_bitmap = true; goto next; } bytes = min(bytes, end - start); if (bytes < minlen) { spin_unlock(&ctl->tree_lock); goto next; } bitmap_clear_bits(ctl, entry, start, bytes); if (entry->bytes == 0) free_bitmap(ctl, entry); spin_unlock(&ctl->tree_lock); ret = do_trimming(block_group, total_trimmed, start, bytes, start, bytes); if (ret) break; *trimmed += actually_trimmed; } next: if (next_bitmap) { offset += BITS_PER_BITMAP * ctl->unit; } else { start += bytes; bytes = 0; if (start >= offset + BITS_PER_BITMAP * ctl->unit) offset += BITS_PER_BITMAP * ctl->unit; } if (fatal_signal_pending(current)) { ret = -ERESTARTSYS; Loading @@ -2682,6 +2765,22 @@ int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, return ret; } int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, u64 *trimmed, u64 start, u64 end, u64 minlen) { int ret; *trimmed = 0; ret = trim_no_bitmap(block_group, trimmed, start, end, minlen); if (ret) return ret; ret = trim_bitmaps(block_group, trimmed, start, end, minlen); return ret; } /* * Find the left-most item in the cache tree, and then return the * smallest inode number in the item. Loading fs/btrfs/ioctl.c +15 −5 Original line number Diff line number Diff line Loading @@ -176,6 +176,8 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) struct btrfs_trans_handle *trans; unsigned int flags, oldflags; int ret; u64 ip_oldflags; unsigned int i_oldflags; if (btrfs_root_readonly(root)) return -EROFS; Loading @@ -192,6 +194,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) mutex_lock(&inode->i_mutex); ip_oldflags = ip->flags; i_oldflags = inode->i_flags; flags = btrfs_mask_flags(inode->i_mode, flags); oldflags = btrfs_flags_to_ioctl(ip->flags); if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { Loading Loading @@ -249,19 +254,24 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS); } trans = btrfs_join_transaction(root); BUG_ON(IS_ERR(trans)); trans = btrfs_start_transaction(root, 1); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out_drop; } btrfs_update_iflags(inode); inode->i_ctime = CURRENT_TIME; ret = btrfs_update_inode(trans, root, inode); BUG_ON(ret); btrfs_end_transaction(trans, root); out_drop: if (ret) { ip->flags = ip_oldflags; inode->i_flags = i_oldflags; } mnt_drop_write(file->f_path.mnt); ret = 0; out_unlock: mutex_unlock(&inode->i_mutex); return ret; Loading fs/btrfs/volumes.c +66 −119 Original line number Diff line number Diff line Loading @@ -830,7 +830,6 @@ int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, /* * find_free_dev_extent - find free space in the specified device * @trans: transaction handler * @device: the device which we search the free space in * @num_bytes: the size of the free space that we need * @start: store the start of the free space. Loading @@ -849,8 +848,7 @@ int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, * But if we don't find suitable free space, it is used to store the size of * the max free space. */ int find_free_dev_extent(struct btrfs_trans_handle *trans, struct btrfs_device *device, u64 num_bytes, int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, u64 *start, u64 *len) { struct btrfs_key key; Loading Loading @@ -894,7 +892,7 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans, key.offset = search_start; key.type = BTRFS_DEV_EXTENT_KEY; ret = btrfs_search_slot(trans, root, &key, path, 0, 0); ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto out; if (ret > 0) { Loading Loading @@ -1468,8 +1466,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) /* * does all the dirty work required for changing file system's UUID. */ static int btrfs_prepare_sprout(struct btrfs_trans_handle *trans, struct btrfs_root *root) static int btrfs_prepare_sprout(struct btrfs_root *root) { struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; struct btrfs_fs_devices *old_devices; Loading Loading @@ -1693,7 +1690,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) if (seeding_dev) { sb->s_flags &= ~MS_RDONLY; ret = btrfs_prepare_sprout(trans, root); ret = btrfs_prepare_sprout(root); BUG_ON(ret); } Loading Loading @@ -3044,8 +3041,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) return ret; } static int btrfs_add_system_chunk(struct btrfs_trans_handle *trans, struct btrfs_root *root, static int btrfs_add_system_chunk(struct btrfs_root *root, struct btrfs_key *key, struct btrfs_chunk *chunk, int item_size) { Loading Loading @@ -3221,7 +3217,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, if (total_avail == 0) continue; ret = find_free_dev_extent(trans, device, ret = find_free_dev_extent(device, max_stripe_size * dev_stripes, &dev_offset, &max_avail); if (ret && ret != -ENOSPC) Loading Loading @@ -3412,7 +3408,7 @@ static int __finish_chunk_alloc(struct btrfs_trans_handle *trans, BUG_ON(ret); if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) { ret = btrfs_add_system_chunk(trans, chunk_root, &key, chunk, ret = btrfs_add_system_chunk(chunk_root, &key, chunk, item_size); BUG_ON(ret); } Loading Loading @@ -3624,26 +3620,13 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, u64 stripe_nr; u64 stripe_nr_orig; u64 stripe_nr_end; int stripes_allocated = 8; int stripes_required = 1; int stripe_index; int i; int ret = 0; int num_stripes; int max_errors = 0; struct btrfs_bio *bbio = NULL; if (bbio_ret && !(rw & (REQ_WRITE | REQ_DISCARD))) stripes_allocated = 1; again: if (bbio_ret) { bbio = kzalloc(btrfs_bio_size(stripes_allocated), GFP_NOFS); if (!bbio) return -ENOMEM; atomic_set(&bbio->error, 0); } read_lock(&em_tree->lock); em = lookup_extent_mapping(em_tree, logical, *length); read_unlock(&em_tree->lock); Loading @@ -3662,28 +3645,6 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, if (mirror_num > map->num_stripes) mirror_num = 0; /* if our btrfs_bio struct is too small, back off and try again */ if (rw & REQ_WRITE) { if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP)) { stripes_required = map->num_stripes; max_errors = 1; } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { stripes_required = map->sub_stripes; max_errors = 1; } } if (rw & REQ_DISCARD) { if (map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) stripes_required = map->num_stripes; } if (bbio_ret && (rw & (REQ_WRITE | REQ_DISCARD)) && stripes_allocated < stripes_required) { stripes_allocated = map->num_stripes; free_extent_map(em); kfree(bbio); goto again; } stripe_nr = offset; /* * stripe_nr counts the total number of stripes we have to stride Loading Loading @@ -3775,81 +3736,55 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, } BUG_ON(stripe_index >= map->num_stripes); bbio = kzalloc(btrfs_bio_size(num_stripes), GFP_NOFS); if (!bbio) { ret = -ENOMEM; goto out; } atomic_set(&bbio->error, 0); if (rw & REQ_DISCARD) { int factor = 0; int sub_stripes = 0; u64 stripes_per_dev = 0; u32 remaining_stripes = 0; if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) { if (map->type & BTRFS_BLOCK_GROUP_RAID0) sub_stripes = 1; else sub_stripes = map->sub_stripes; factor = map->num_stripes / sub_stripes; stripes_per_dev = div_u64_rem(stripe_nr_end - stripe_nr_orig, factor, &remaining_stripes); } for (i = 0; i < num_stripes; i++) { bbio->stripes[i].physical = map->stripes[stripe_index].physical + stripe_offset + stripe_nr * map->stripe_len; bbio->stripes[i].dev = map->stripes[stripe_index].dev; if (map->type & BTRFS_BLOCK_GROUP_RAID0) { u64 stripes; u32 last_stripe = 0; int j; div_u64_rem(stripe_nr_end - 1, map->num_stripes, &last_stripe); for (j = 0; j < map->num_stripes; j++) { u32 test; div_u64_rem(stripe_nr_end - 1 - j, map->num_stripes, &test); if (test == stripe_index) break; } stripes = stripe_nr_end - 1 - j; do_div(stripes, map->num_stripes); bbio->stripes[i].length = map->stripe_len * (stripes - stripe_nr + 1); if (i == 0) { if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) { bbio->stripes[i].length = stripes_per_dev * map->stripe_len; if (i / sub_stripes < remaining_stripes) bbio->stripes[i].length += map->stripe_len; if (i < sub_stripes) bbio->stripes[i].length -= stripe_offset; stripe_offset = 0; } if (stripe_index == last_stripe) if ((i / sub_stripes + 1) % sub_stripes == remaining_stripes) bbio->stripes[i].length -= stripe_end_offset; } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { u64 stripes; int j; int factor = map->num_stripes / map->sub_stripes; u32 last_stripe = 0; div_u64_rem(stripe_nr_end - 1, factor, &last_stripe); last_stripe *= map->sub_stripes; for (j = 0; j < factor; j++) { u32 test; div_u64_rem(stripe_nr_end - 1 - j, factor, &test); if (test == stripe_index / map->sub_stripes) break; } stripes = stripe_nr_end - 1 - j; do_div(stripes, factor); bbio->stripes[i].length = map->stripe_len * (stripes - stripe_nr + 1); if (i < map->sub_stripes) { bbio->stripes[i].length -= stripe_offset; if (i == map->sub_stripes - 1) if (i == sub_stripes - 1) stripe_offset = 0; } if (stripe_index >= last_stripe && stripe_index <= (last_stripe + map->sub_stripes - 1)) { bbio->stripes[i].length -= stripe_end_offset; } } else bbio->stripes[i].length = *length; Loading @@ -3871,15 +3806,22 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, stripe_index++; } } if (bbio_ret) { if (rw & REQ_WRITE) { if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10 | BTRFS_BLOCK_GROUP_DUP)) { max_errors = 1; } } *bbio_ret = bbio; bbio->num_stripes = num_stripes; bbio->max_errors = max_errors; bbio->mirror_num = mirror_num; } out: free_extent_map(em); return 0; return ret; } int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, Loading Loading @@ -4284,7 +4226,7 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid) struct btrfs_fs_devices *fs_devices; int ret; mutex_lock(&uuid_mutex); BUG_ON(!mutex_is_locked(&uuid_mutex)); fs_devices = root->fs_info->fs_devices->seed; while (fs_devices) { Loading Loading @@ -4322,7 +4264,6 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid) fs_devices->seed = root->fs_info->fs_devices->seed; root->fs_info->fs_devices->seed = fs_devices; out: mutex_unlock(&uuid_mutex); return ret; } Loading Loading @@ -4465,6 +4406,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) if (!path) return -ENOMEM; mutex_lock(&uuid_mutex); lock_chunks(root); /* first we search for all of the device items, and then we * read in all of the chunk items. This way we can create chunk * mappings that reference all of the devices that are afound Loading Loading @@ -4515,6 +4459,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) } ret = 0; error: unlock_chunks(root); mutex_unlock(&uuid_mutex); btrfs_free_path(path); return ret; } Loading
fs/btrfs/disk-io.c +0 −2 Original line number Diff line number Diff line Loading @@ -2278,9 +2278,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, (unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node), BTRFS_UUID_SIZE); mutex_lock(&fs_info->chunk_mutex); ret = btrfs_read_chunk_tree(chunk_root); mutex_unlock(&fs_info->chunk_mutex); if (ret) { printk(KERN_WARNING "btrfs: failed to read chunk tree on %s\n", sb->s_id); Loading
fs/btrfs/extent-tree.c +2 −1 Original line number Diff line number Diff line Loading @@ -7143,7 +7143,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) * space to fit our block group in. */ if (device->total_bytes > device->bytes_used + min_free) { ret = find_free_dev_extent(NULL, device, min_free, ret = find_free_dev_extent(device, min_free, &dev_offset, NULL); if (!ret) dev_nr++; Loading Loading @@ -7505,6 +7505,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, ret = update_space_info(root->fs_info, cache->flags, size, bytes_used, &cache->space_info); BUG_ON(ret); update_global_block_rsv(root->fs_info); spin_lock(&cache->space_info->lock); cache->space_info->bytes_readonly += cache->bytes_super; Loading
fs/btrfs/free-space-cache.c +196 −97 Original line number Diff line number Diff line Loading @@ -319,11 +319,13 @@ static void io_ctl_drop_pages(struct io_ctl *io_ctl) io_ctl_unmap_page(io_ctl); for (i = 0; i < io_ctl->num_pages; i++) { if (io_ctl->pages[i]) { ClearPageChecked(io_ctl->pages[i]); unlock_page(io_ctl->pages[i]); page_cache_release(io_ctl->pages[i]); } } } static int io_ctl_prepare_pages(struct io_ctl *io_ctl, struct inode *inode, int uptodate) Loading Loading @@ -635,7 +637,10 @@ int __load_free_space_cache(struct btrfs_root *root, struct inode *inode, if (!num_entries) return 0; io_ctl_init(&io_ctl, inode, root); ret = io_ctl_init(&io_ctl, inode, root); if (ret) return ret; ret = readahead_cache(inode); if (ret) goto out; Loading Loading @@ -838,7 +843,7 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, struct io_ctl io_ctl; struct list_head bitmap_list; struct btrfs_key key; u64 start, end, len; u64 start, extent_start, extent_end, len; int entries = 0; int bitmaps = 0; int ret; Loading @@ -849,7 +854,9 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, if (!i_size_read(inode)) return -1; io_ctl_init(&io_ctl, inode, root); ret = io_ctl_init(&io_ctl, inode, root); if (ret) return -1; /* Get the cluster for this block_group if it exists */ if (block_group && !list_empty(&block_group->cluster_list)) Loading @@ -857,25 +864,12 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, struct btrfs_free_cluster, block_group_list); /* * We shouldn't have switched the pinned extents yet so this is the * right one */ unpin = root->fs_info->pinned_extents; /* Lock all pages first so we can lock the extent safely. */ io_ctl_prepare_pages(&io_ctl, inode, 0); lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1, 0, &cached_state, GFP_NOFS); /* * When searching for pinned extents, we need to start at our start * offset. */ if (block_group) start = block_group->key.objectid; node = rb_first(&ctl->free_space_offset); if (!node && cluster) { node = rb_first(&cluster->root); Loading Loading @@ -918,9 +912,20 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, * We want to add any pinned extents to our free space cache * so we don't leak the space */ /* * We shouldn't have switched the pinned extents yet so this is the * right one */ unpin = root->fs_info->pinned_extents; if (block_group) start = block_group->key.objectid; while (block_group && (start < block_group->key.objectid + block_group->key.offset)) { ret = find_first_extent_bit(unpin, start, &start, &end, ret = find_first_extent_bit(unpin, start, &extent_start, &extent_end, EXTENT_DIRTY); if (ret) { ret = 0; Loading @@ -928,20 +933,21 @@ int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, } /* This pinned extent is out of our range */ if (start >= block_group->key.objectid + if (extent_start >= block_group->key.objectid + block_group->key.offset) break; len = block_group->key.objectid + block_group->key.offset - start; len = min(len, end + 1 - start); extent_start = max(extent_start, start); extent_end = min(block_group->key.objectid + block_group->key.offset, extent_end + 1); len = extent_end - extent_start; entries++; ret = io_ctl_add_entry(&io_ctl, start, len, NULL); ret = io_ctl_add_entry(&io_ctl, extent_start, len, NULL); if (ret) goto out_nospc; start = end + 1; start = extent_end; } /* Write out the bitmaps */ Loading Loading @@ -2574,17 +2580,57 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster) cluster->block_group = NULL; } int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, u64 *trimmed, u64 start, u64 end, u64 minlen) static int do_trimming(struct btrfs_block_group_cache *block_group, u64 *total_trimmed, u64 start, u64 bytes, u64 reserved_start, u64 reserved_bytes) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; struct btrfs_free_space *entry = NULL; struct btrfs_space_info *space_info = block_group->space_info; struct btrfs_fs_info *fs_info = block_group->fs_info; u64 bytes = 0; u64 actually_trimmed; int ret = 0; int ret; int update = 0; u64 trimmed = 0; *trimmed = 0; spin_lock(&space_info->lock); spin_lock(&block_group->lock); if (!block_group->ro) { block_group->reserved += reserved_bytes; space_info->bytes_reserved += reserved_bytes; update = 1; } spin_unlock(&block_group->lock); spin_unlock(&space_info->lock); ret = btrfs_error_discard_extent(fs_info->extent_root, start, bytes, &trimmed); if (!ret) *total_trimmed += trimmed; btrfs_add_free_space(block_group, reserved_start, reserved_bytes); if (update) { spin_lock(&space_info->lock); spin_lock(&block_group->lock); if (block_group->ro) space_info->bytes_readonly += reserved_bytes; block_group->reserved -= reserved_bytes; space_info->bytes_reserved -= reserved_bytes; spin_unlock(&space_info->lock); spin_unlock(&block_group->lock); } return ret; } static int trim_no_bitmap(struct btrfs_block_group_cache *block_group, u64 *total_trimmed, u64 start, u64 end, u64 minlen) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; struct btrfs_free_space *entry; struct rb_node *node; int ret = 0; u64 extent_start; u64 extent_bytes; u64 bytes; while (start < end) { spin_lock(&ctl->tree_lock); Loading @@ -2595,81 +2641,118 @@ int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, } entry = tree_search_offset(ctl, start, 0, 1); if (!entry) entry = tree_search_offset(ctl, offset_to_bitmap(ctl, start), 1, 1); if (!entry || entry->offset >= end) { if (!entry) { spin_unlock(&ctl->tree_lock); break; } if (entry->bitmap) { ret = search_bitmap(ctl, entry, &start, &bytes); if (!ret) { if (start >= end) { /* skip bitmaps */ while (entry->bitmap) { node = rb_next(&entry->offset_index); if (!node) { spin_unlock(&ctl->tree_lock); goto out; } entry = rb_entry(node, struct btrfs_free_space, offset_index); } if (entry->offset >= end) { spin_unlock(&ctl->tree_lock); break; } bytes = min(bytes, end - start); bitmap_clear_bits(ctl, entry, start, bytes); if (entry->bytes == 0) free_bitmap(ctl, entry); } else { start = entry->offset + BITS_PER_BITMAP * block_group->sectorsize; extent_start = entry->offset; extent_bytes = entry->bytes; start = max(start, extent_start); bytes = min(extent_start + extent_bytes, end) - start; if (bytes < minlen) { spin_unlock(&ctl->tree_lock); ret = 0; continue; goto next; } } else { start = entry->offset; bytes = min(entry->bytes, end - start); unlink_free_space(ctl, entry); kmem_cache_free(btrfs_free_space_cachep, entry); } spin_unlock(&ctl->tree_lock); if (bytes >= minlen) { struct btrfs_space_info *space_info; int update = 0; ret = do_trimming(block_group, total_trimmed, start, bytes, extent_start, extent_bytes); if (ret) break; next: start += bytes; space_info = block_group->space_info; spin_lock(&space_info->lock); spin_lock(&block_group->lock); if (!block_group->ro) { block_group->reserved += bytes; space_info->bytes_reserved += bytes; update = 1; if (fatal_signal_pending(current)) { ret = -ERESTARTSYS; break; } spin_unlock(&block_group->lock); spin_unlock(&space_info->lock); ret = btrfs_error_discard_extent(fs_info->extent_root, start, bytes, &actually_trimmed); cond_resched(); } out: return ret; } btrfs_add_free_space(block_group, start, bytes); if (update) { spin_lock(&space_info->lock); spin_lock(&block_group->lock); if (block_group->ro) space_info->bytes_readonly += bytes; block_group->reserved -= bytes; space_info->bytes_reserved -= bytes; spin_unlock(&space_info->lock); spin_unlock(&block_group->lock); static int trim_bitmaps(struct btrfs_block_group_cache *block_group, u64 *total_trimmed, u64 start, u64 end, u64 minlen) { struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; struct btrfs_free_space *entry; int ret = 0; int ret2; u64 bytes; u64 offset = offset_to_bitmap(ctl, start); while (offset < end) { bool next_bitmap = false; spin_lock(&ctl->tree_lock); if (ctl->free_space < minlen) { spin_unlock(&ctl->tree_lock); break; } entry = tree_search_offset(ctl, offset, 1, 0); if (!entry) { spin_unlock(&ctl->tree_lock); next_bitmap = true; goto next; } bytes = minlen; ret2 = search_bitmap(ctl, entry, &start, &bytes); if (ret2 || start >= end) { spin_unlock(&ctl->tree_lock); next_bitmap = true; goto next; } bytes = min(bytes, end - start); if (bytes < minlen) { spin_unlock(&ctl->tree_lock); goto next; } bitmap_clear_bits(ctl, entry, start, bytes); if (entry->bytes == 0) free_bitmap(ctl, entry); spin_unlock(&ctl->tree_lock); ret = do_trimming(block_group, total_trimmed, start, bytes, start, bytes); if (ret) break; *trimmed += actually_trimmed; } next: if (next_bitmap) { offset += BITS_PER_BITMAP * ctl->unit; } else { start += bytes; bytes = 0; if (start >= offset + BITS_PER_BITMAP * ctl->unit) offset += BITS_PER_BITMAP * ctl->unit; } if (fatal_signal_pending(current)) { ret = -ERESTARTSYS; Loading @@ -2682,6 +2765,22 @@ int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, return ret; } int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, u64 *trimmed, u64 start, u64 end, u64 minlen) { int ret; *trimmed = 0; ret = trim_no_bitmap(block_group, trimmed, start, end, minlen); if (ret) return ret; ret = trim_bitmaps(block_group, trimmed, start, end, minlen); return ret; } /* * Find the left-most item in the cache tree, and then return the * smallest inode number in the item. Loading
fs/btrfs/ioctl.c +15 −5 Original line number Diff line number Diff line Loading @@ -176,6 +176,8 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) struct btrfs_trans_handle *trans; unsigned int flags, oldflags; int ret; u64 ip_oldflags; unsigned int i_oldflags; if (btrfs_root_readonly(root)) return -EROFS; Loading @@ -192,6 +194,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) mutex_lock(&inode->i_mutex); ip_oldflags = ip->flags; i_oldflags = inode->i_flags; flags = btrfs_mask_flags(inode->i_mode, flags); oldflags = btrfs_flags_to_ioctl(ip->flags); if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { Loading Loading @@ -249,19 +254,24 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS); } trans = btrfs_join_transaction(root); BUG_ON(IS_ERR(trans)); trans = btrfs_start_transaction(root, 1); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out_drop; } btrfs_update_iflags(inode); inode->i_ctime = CURRENT_TIME; ret = btrfs_update_inode(trans, root, inode); BUG_ON(ret); btrfs_end_transaction(trans, root); out_drop: if (ret) { ip->flags = ip_oldflags; inode->i_flags = i_oldflags; } mnt_drop_write(file->f_path.mnt); ret = 0; out_unlock: mutex_unlock(&inode->i_mutex); return ret; Loading
fs/btrfs/volumes.c +66 −119 Original line number Diff line number Diff line Loading @@ -830,7 +830,6 @@ int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, /* * find_free_dev_extent - find free space in the specified device * @trans: transaction handler * @device: the device which we search the free space in * @num_bytes: the size of the free space that we need * @start: store the start of the free space. Loading @@ -849,8 +848,7 @@ int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, * But if we don't find suitable free space, it is used to store the size of * the max free space. */ int find_free_dev_extent(struct btrfs_trans_handle *trans, struct btrfs_device *device, u64 num_bytes, int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, u64 *start, u64 *len) { struct btrfs_key key; Loading Loading @@ -894,7 +892,7 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans, key.offset = search_start; key.type = BTRFS_DEV_EXTENT_KEY; ret = btrfs_search_slot(trans, root, &key, path, 0, 0); ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto out; if (ret > 0) { Loading Loading @@ -1468,8 +1466,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) /* * does all the dirty work required for changing file system's UUID. */ static int btrfs_prepare_sprout(struct btrfs_trans_handle *trans, struct btrfs_root *root) static int btrfs_prepare_sprout(struct btrfs_root *root) { struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; struct btrfs_fs_devices *old_devices; Loading Loading @@ -1693,7 +1690,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) if (seeding_dev) { sb->s_flags &= ~MS_RDONLY; ret = btrfs_prepare_sprout(trans, root); ret = btrfs_prepare_sprout(root); BUG_ON(ret); } Loading Loading @@ -3044,8 +3041,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) return ret; } static int btrfs_add_system_chunk(struct btrfs_trans_handle *trans, struct btrfs_root *root, static int btrfs_add_system_chunk(struct btrfs_root *root, struct btrfs_key *key, struct btrfs_chunk *chunk, int item_size) { Loading Loading @@ -3221,7 +3217,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, if (total_avail == 0) continue; ret = find_free_dev_extent(trans, device, ret = find_free_dev_extent(device, max_stripe_size * dev_stripes, &dev_offset, &max_avail); if (ret && ret != -ENOSPC) Loading Loading @@ -3412,7 +3408,7 @@ static int __finish_chunk_alloc(struct btrfs_trans_handle *trans, BUG_ON(ret); if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) { ret = btrfs_add_system_chunk(trans, chunk_root, &key, chunk, ret = btrfs_add_system_chunk(chunk_root, &key, chunk, item_size); BUG_ON(ret); } Loading Loading @@ -3624,26 +3620,13 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, u64 stripe_nr; u64 stripe_nr_orig; u64 stripe_nr_end; int stripes_allocated = 8; int stripes_required = 1; int stripe_index; int i; int ret = 0; int num_stripes; int max_errors = 0; struct btrfs_bio *bbio = NULL; if (bbio_ret && !(rw & (REQ_WRITE | REQ_DISCARD))) stripes_allocated = 1; again: if (bbio_ret) { bbio = kzalloc(btrfs_bio_size(stripes_allocated), GFP_NOFS); if (!bbio) return -ENOMEM; atomic_set(&bbio->error, 0); } read_lock(&em_tree->lock); em = lookup_extent_mapping(em_tree, logical, *length); read_unlock(&em_tree->lock); Loading @@ -3662,28 +3645,6 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, if (mirror_num > map->num_stripes) mirror_num = 0; /* if our btrfs_bio struct is too small, back off and try again */ if (rw & REQ_WRITE) { if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP)) { stripes_required = map->num_stripes; max_errors = 1; } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { stripes_required = map->sub_stripes; max_errors = 1; } } if (rw & REQ_DISCARD) { if (map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) stripes_required = map->num_stripes; } if (bbio_ret && (rw & (REQ_WRITE | REQ_DISCARD)) && stripes_allocated < stripes_required) { stripes_allocated = map->num_stripes; free_extent_map(em); kfree(bbio); goto again; } stripe_nr = offset; /* * stripe_nr counts the total number of stripes we have to stride Loading Loading @@ -3775,81 +3736,55 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, } BUG_ON(stripe_index >= map->num_stripes); bbio = kzalloc(btrfs_bio_size(num_stripes), GFP_NOFS); if (!bbio) { ret = -ENOMEM; goto out; } atomic_set(&bbio->error, 0); if (rw & REQ_DISCARD) { int factor = 0; int sub_stripes = 0; u64 stripes_per_dev = 0; u32 remaining_stripes = 0; if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) { if (map->type & BTRFS_BLOCK_GROUP_RAID0) sub_stripes = 1; else sub_stripes = map->sub_stripes; factor = map->num_stripes / sub_stripes; stripes_per_dev = div_u64_rem(stripe_nr_end - stripe_nr_orig, factor, &remaining_stripes); } for (i = 0; i < num_stripes; i++) { bbio->stripes[i].physical = map->stripes[stripe_index].physical + stripe_offset + stripe_nr * map->stripe_len; bbio->stripes[i].dev = map->stripes[stripe_index].dev; if (map->type & BTRFS_BLOCK_GROUP_RAID0) { u64 stripes; u32 last_stripe = 0; int j; div_u64_rem(stripe_nr_end - 1, map->num_stripes, &last_stripe); for (j = 0; j < map->num_stripes; j++) { u32 test; div_u64_rem(stripe_nr_end - 1 - j, map->num_stripes, &test); if (test == stripe_index) break; } stripes = stripe_nr_end - 1 - j; do_div(stripes, map->num_stripes); bbio->stripes[i].length = map->stripe_len * (stripes - stripe_nr + 1); if (i == 0) { if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) { bbio->stripes[i].length = stripes_per_dev * map->stripe_len; if (i / sub_stripes < remaining_stripes) bbio->stripes[i].length += map->stripe_len; if (i < sub_stripes) bbio->stripes[i].length -= stripe_offset; stripe_offset = 0; } if (stripe_index == last_stripe) if ((i / sub_stripes + 1) % sub_stripes == remaining_stripes) bbio->stripes[i].length -= stripe_end_offset; } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { u64 stripes; int j; int factor = map->num_stripes / map->sub_stripes; u32 last_stripe = 0; div_u64_rem(stripe_nr_end - 1, factor, &last_stripe); last_stripe *= map->sub_stripes; for (j = 0; j < factor; j++) { u32 test; div_u64_rem(stripe_nr_end - 1 - j, factor, &test); if (test == stripe_index / map->sub_stripes) break; } stripes = stripe_nr_end - 1 - j; do_div(stripes, factor); bbio->stripes[i].length = map->stripe_len * (stripes - stripe_nr + 1); if (i < map->sub_stripes) { bbio->stripes[i].length -= stripe_offset; if (i == map->sub_stripes - 1) if (i == sub_stripes - 1) stripe_offset = 0; } if (stripe_index >= last_stripe && stripe_index <= (last_stripe + map->sub_stripes - 1)) { bbio->stripes[i].length -= stripe_end_offset; } } else bbio->stripes[i].length = *length; Loading @@ -3871,15 +3806,22 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, stripe_index++; } } if (bbio_ret) { if (rw & REQ_WRITE) { if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10 | BTRFS_BLOCK_GROUP_DUP)) { max_errors = 1; } } *bbio_ret = bbio; bbio->num_stripes = num_stripes; bbio->max_errors = max_errors; bbio->mirror_num = mirror_num; } out: free_extent_map(em); return 0; return ret; } int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, Loading Loading @@ -4284,7 +4226,7 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid) struct btrfs_fs_devices *fs_devices; int ret; mutex_lock(&uuid_mutex); BUG_ON(!mutex_is_locked(&uuid_mutex)); fs_devices = root->fs_info->fs_devices->seed; while (fs_devices) { Loading Loading @@ -4322,7 +4264,6 @@ static int open_seed_devices(struct btrfs_root *root, u8 *fsid) fs_devices->seed = root->fs_info->fs_devices->seed; root->fs_info->fs_devices->seed = fs_devices; out: mutex_unlock(&uuid_mutex); return ret; } Loading Loading @@ -4465,6 +4406,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) if (!path) return -ENOMEM; mutex_lock(&uuid_mutex); lock_chunks(root); /* first we search for all of the device items, and then we * read in all of the chunk items. This way we can create chunk * mappings that reference all of the devices that are afound Loading Loading @@ -4515,6 +4459,9 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) } ret = 0; error: unlock_chunks(root); mutex_unlock(&uuid_mutex); btrfs_free_path(path); return ret; }