Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
1
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
6aa0e7c
Documentation
LICENSES
arch
block
certs
crypto
drivers
fs
9p
adfs
affs
afs
autofs
bcachefs
befs
bfs
btrfs
tests
Kconfig
Makefile
accessors.c
accessors.h
acl.c
acl.h
async-thread.c
async-thread.h
backref.c
backref.h
bio.c
bio.h
block-group.c
block-group.h
block-rsv.c
block-rsv.h
btrfs_inode.h
compression.c
compression.h
ctree.c
ctree.h
defrag.c
defrag.h
delalloc-space.c
delalloc-space.h
delayed-inode.c
delayed-inode.h
delayed-ref.c
delayed-ref.h
dev-replace.c
dev-replace.h
dir-item.c
dir-item.h
direct-io.c
direct-io.h
discard.c
discard.h
disk-io.c
disk-io.h
export.c
export.h
extent-io-tree.c
extent-io-tree.h
extent-tree.c
extent-tree.h
extent_io.c
extent_io.h
extent_map.c
extent_map.h
fiemap.c
fiemap.h
file-item.c
file-item.h
file.c
file.h
free-space-cache.c
free-space-cache.h
free-space-tree.c
free-space-tree.h
fs.c
fs.h
inode-item.c
inode-item.h
inode.c
ioctl.c
ioctl.h
locking.c
locking.h
lru_cache.c
lru_cache.h
lzo.c
messages.c
messages.h
misc.h
ordered-data.c
ordered-data.h
orphan.c
orphan.h
print-tree.c
print-tree.h
props.c
props.h
qgroup.c
qgroup.h
raid-stripe-tree.c
raid-stripe-tree.h
raid56.c
raid56.h
rcu-string.h
ref-verify.c
ref-verify.h
reflink.c
reflink.h
relocation.c
relocation.h
root-tree.c
root-tree.h
scrub.c
scrub.h
send.c
send.h
space-info.c
space-info.h
subpage.c
subpage.h
super.c
super.h
sysfs.c
sysfs.h
transaction.c
transaction.h
tree-checker.c
tree-checker.h
tree-log.c
tree-log.h
tree-mod-log.c
tree-mod-log.h
ulist.c
ulist.h
uuid-tree.c
uuid-tree.h
verity.c
verity.h
volumes.c
volumes.h
xattr.c
xattr.h
zlib.c
zoned.c
zoned.h
zstd.c
cachefiles
ceph
coda
configfs
cramfs
crypto
debugfs
devpts
dlm
ecryptfs
efivarfs
efs
erofs
exfat
exportfs
ext2
ext4
f2fs
fat
freevxfs
fuse
gfs2
hfs
hfsplus
hostfs
hpfs
hugetlbfs
iomap
isofs
jbd2
jffs2
jfs
kernfs
lockd
minix
netfs
nfs
nfs_common
nfsd
nilfs2
nls
notify
ntfs3
ocfs2
omfs
openpromfs
orangefs
overlayfs
proc
pstore
qnx4
qnx6
quota
ramfs
romfs
smb
squashfs
sysfs
sysv
tests
tracefs
ubifs
udf
ufs
unicode
vboxsf
verity
xfs
zonefs
Kconfig
Kconfig.binfmt
Makefile
aio.c
anon_inodes.c
attr.c
backing-file.c
bad_inode.c
binfmt_elf.c
binfmt_elf_fdpic.c
binfmt_flat.c
binfmt_misc.c
binfmt_script.c
bpf_fs_kfuncs.c
buffer.c
char_dev.c
compat_binfmt_elf.c
coredump.c
d_path.c
dax.c
dcache.c
direct-io.c
drop_caches.c
eventfd.c
eventpoll.c
exec.c
fcntl.c
fhandle.c
file.c
file_table.c
filesystems.c
fs-writeback.c
fs_context.c
fs_parser.c
fs_pin.c
fs_struct.c
fs_types.c
fsopen.c
init.c
inode.c
internal.h
ioctl.c
kernel_read_file.c
libfs.c
locks.c
mbcache.c
mnt_idmapping.c
mount.h
mpage.c
namei.c
namespace.c
nsfs.c
open.c
pidfs.c
pipe.c
pnode.c
pnode.h
posix_acl.c
proc_namespace.c
read_write.c
readdir.c
remap_range.c
select.c
seq_file.c
signalfd.c
splice.c
stack.c
stat.c
statfs.c
super.c
sync.c
sysctls.c
timerfd.c
userfaultfd.c
utimes.c
xattr.c
include
init
io_uring
ipc
kernel
lib
mm
net
rust
samples
scripts
security
sound
tools
usr
virt
.clang-format
.clippy.toml
.cocciconfig
.editorconfig
.get_maintainer.ignore
.gitattributes
.gitignore
.mailmap
.rustfmt.toml
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
Breadcrumbs
linux
/
fs
/
btrfs
/
raid-stripe-tree.c
Copy path
Blame
Blame
Latest commit
History
History
462 lines (385 loc) · 11.5 KB
Breadcrumbs
linux
/
fs
/
btrfs
/
raid-stripe-tree.c
Top
File metadata and controls
Code
Blame
462 lines (385 loc) · 11.5 KB
Raw
// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2023 Western Digital Corporation or its affiliates. */ #include <linux/btrfs_tree.h> #include "ctree.h" #include "fs.h" #include "accessors.h" #include "transaction.h" #include "disk-io.h" #include "raid-stripe-tree.h" #include "volumes.h" #include "print-tree.h" static void btrfs_partially_delete_raid_extent(struct btrfs_trans_handle *trans, struct btrfs_path *path, const struct btrfs_key *oldkey, u64 newlen, u64 frontpad) { struct btrfs_stripe_extent *extent; struct extent_buffer *leaf; int slot; size_t item_size; struct btrfs_key newkey = { .objectid = oldkey->objectid + frontpad, .type = BTRFS_RAID_STRIPE_KEY, .offset = newlen, }; ASSERT(newlen > 0); ASSERT(oldkey->type == BTRFS_RAID_STRIPE_KEY); leaf = path->nodes[0]; slot = path->slots[0]; item_size = btrfs_item_size(leaf, slot); extent = btrfs_item_ptr(leaf, slot, struct btrfs_stripe_extent); for (int i = 0; i < btrfs_num_raid_stripes(item_size); i++) { struct btrfs_raid_stride *stride = &extent->strides[i]; u64 phys; phys = btrfs_raid_stride_physical(leaf, stride); btrfs_set_raid_stride_physical(leaf, stride, phys + frontpad); } btrfs_set_item_key_safe(trans, path, &newkey); } int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 length) { struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *stripe_root = fs_info->stripe_root; struct btrfs_path *path; struct btrfs_key key; struct extent_buffer *leaf; u64 found_start; u64 found_end; u64 end = start + length; int slot; int ret; if (!btrfs_fs_incompat(fs_info, RAID_STRIPE_TREE) || !stripe_root) return 0; if (!btrfs_is_testing(fs_info)) { struct btrfs_chunk_map *map; bool use_rst; map = btrfs_find_chunk_map(fs_info, start, length); if (!map) return -EINVAL; use_rst = btrfs_need_stripe_tree_update(fs_info, map->type); btrfs_free_chunk_map(map); if (!use_rst) return 0; } path = btrfs_alloc_path(); if (!path) return -ENOMEM; while (1) { key.objectid = start; key.type = BTRFS_RAID_STRIPE_KEY; key.offset = 0; ret = btrfs_search_slot(trans, stripe_root, &key, path, -1, 1); if (ret < 0) break; if (path->slots[0] == btrfs_header_nritems(path->nodes[0])) path->slots[0]--; leaf = path->nodes[0]; slot = path->slots[0]; btrfs_item_key_to_cpu(leaf, &key, slot); found_start = key.objectid; found_end = found_start + key.offset; ret = 0; /* * The stripe extent starts before the range we want to delete, * but the range spans more than one stripe extent: * * |--- RAID Stripe Extent ---||--- RAID Stripe Extent ---| * |--- keep ---|--- drop ---| * * This means we have to get the previous item, truncate its * length and then restart the search. */ if (found_start > start) { if (slot == 0) { ret = btrfs_previous_item(stripe_root, path, start, BTRFS_RAID_STRIPE_KEY); if (ret) { if (ret > 0) ret = -ENOENT; break; } } else { path->slots[0]--; } leaf = path->nodes[0]; slot = path->slots[0]; btrfs_item_key_to_cpu(leaf, &key, slot); found_start = key.objectid; found_end = found_start + key.offset; ASSERT(found_start <= start); } if (key.type != BTRFS_RAID_STRIPE_KEY) break; /* That stripe ends before we start, we're done. */ if (found_end <= start) break; trace_btrfs_raid_extent_delete(fs_info, start, end, found_start, found_end); /* * The stripe extent starts before the range we want to delete * and ends after the range we want to delete, i.e. we're * punching a hole in the stripe extent: * * |--- RAID Stripe Extent ---| * | keep |--- drop ---| keep | * * This means we need to a) truncate the existing item and b) * create a second item for the remaining range. */ if (found_start < start && found_end > end) { size_t item_size; u64 diff_start = start - found_start; u64 diff_end = found_end - end; struct btrfs_stripe_extent *extent; struct btrfs_key newkey = { .objectid = end, .type = BTRFS_RAID_STRIPE_KEY, .offset = diff_end, }; /* The "right" item. */ ret = btrfs_duplicate_item(trans, stripe_root, path, &newkey); if (ret) break; item_size = btrfs_item_size(leaf, path->slots[0]); extent = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_stripe_extent); for (int i = 0; i < btrfs_num_raid_stripes(item_size); i++) { struct btrfs_raid_stride *stride = &extent->strides[i]; u64 phys; phys = btrfs_raid_stride_physical(leaf, stride); phys += diff_start + length; btrfs_set_raid_stride_physical(leaf, stride, phys); } /* The "left" item. */ path->slots[0]--; btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); btrfs_partially_delete_raid_extent(trans, path, &key, diff_start, 0); break; } /* * The stripe extent starts before the range we want to delete: * * |--- RAID Stripe Extent ---| * |--- keep ---|--- drop ---| * * This means we have to duplicate the tree item, truncate the * length to the new size and then re-insert the item. */ if (found_start < start) { u64 diff_start = start - found_start; btrfs_partially_delete_raid_extent(trans, path, &key, diff_start, 0); start += (key.offset - diff_start); length -= (key.offset - diff_start); if (length == 0) break; btrfs_release_path(path); continue; } /* * The stripe extent ends after the range we want to delete: * * |--- RAID Stripe Extent ---| * |--- drop ---|--- keep ---| * * This means we have to duplicate the tree item, truncate the * length to the new size and then re-insert the item. */ if (found_end > end) { u64 diff_end = found_end - end; btrfs_partially_delete_raid_extent(trans, path, &key, key.offset - length, length); ASSERT(key.offset - diff_end == length); break; } /* Finally we can delete the whole item, no more special cases. */ ret = btrfs_del_item(trans, stripe_root, path); if (ret) break; start += key.offset; length -= key.offset; if (length == 0) break; btrfs_release_path(path); } btrfs_free_path(path); return ret; } static int update_raid_extent_item(struct btrfs_trans_handle *trans, struct btrfs_key *key, struct btrfs_stripe_extent *stripe_extent, const size_t item_size) { struct btrfs_path *path; struct extent_buffer *leaf; int ret; int slot; path = btrfs_alloc_path(); if (!path) return -ENOMEM; ret = btrfs_search_slot(trans, trans->fs_info->stripe_root, key, path, 0, 1); if (ret) return (ret == 1 ? ret : -EINVAL); leaf = path->nodes[0]; slot = path->slots[0]; write_extent_buffer(leaf, stripe_extent, btrfs_item_ptr_offset(leaf, slot), item_size); btrfs_free_path(path); return ret; } EXPORT_FOR_TESTS int btrfs_insert_one_raid_extent(struct btrfs_trans_handle *trans, struct btrfs_io_context *bioc) { struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_key stripe_key; struct btrfs_root *stripe_root = fs_info->stripe_root; const int num_stripes = btrfs_bg_type_to_factor(bioc->map_type); struct btrfs_stripe_extent *stripe_extent; const size_t item_size = struct_size(stripe_extent, strides, num_stripes); int ret; stripe_extent = kzalloc(item_size, GFP_NOFS); if (!stripe_extent) { btrfs_abort_transaction(trans, -ENOMEM); btrfs_end_transaction(trans); return -ENOMEM; } trace_btrfs_insert_one_raid_extent(fs_info, bioc->logical, bioc->size, num_stripes); for (int i = 0; i < num_stripes; i++) { u64 devid = bioc->stripes[i].dev->devid; u64 physical = bioc->stripes[i].physical; struct btrfs_raid_stride *raid_stride = &stripe_extent->strides[i]; btrfs_set_stack_raid_stride_devid(raid_stride, devid); btrfs_set_stack_raid_stride_physical(raid_stride, physical); } stripe_key.objectid = bioc->logical; stripe_key.type = BTRFS_RAID_STRIPE_KEY; stripe_key.offset = bioc->size; ret = btrfs_insert_item(trans, stripe_root, &stripe_key, stripe_extent, item_size); if (ret == -EEXIST) ret = update_raid_extent_item(trans, &stripe_key, stripe_extent, item_size); if (ret) btrfs_abort_transaction(trans, ret); kfree(stripe_extent); return ret; } int btrfs_insert_raid_extent(struct btrfs_trans_handle *trans, struct btrfs_ordered_extent *ordered_extent) { struct btrfs_io_context *bioc; int ret; if (!btrfs_fs_incompat(trans->fs_info, RAID_STRIPE_TREE)) return 0; list_for_each_entry(bioc, &ordered_extent->bioc_list, rst_ordered_entry) { ret = btrfs_insert_one_raid_extent(trans, bioc); if (ret) return ret; } while (!list_empty(&ordered_extent->bioc_list)) { bioc = list_first_entry(&ordered_extent->bioc_list, typeof(*bioc), rst_ordered_entry); list_del(&bioc->rst_ordered_entry); btrfs_put_bioc(bioc); } return 0; } int btrfs_get_raid_extent_offset(struct btrfs_fs_info *fs_info, u64 logical, u64 *length, u64 map_type, u32 stripe_index, struct btrfs_io_stripe *stripe) { struct btrfs_root *stripe_root = fs_info->stripe_root; struct btrfs_stripe_extent *stripe_extent; struct btrfs_key stripe_key; struct btrfs_key found_key; struct btrfs_path *path; struct extent_buffer *leaf; const u64 end = logical + *length; int num_stripes; u64 offset; u64 found_logical; u64 found_length; u64 found_end; int slot; int ret; stripe_key.objectid = logical; stripe_key.type = BTRFS_RAID_STRIPE_KEY; stripe_key.offset = 0; path = btrfs_alloc_path(); if (!path) return -ENOMEM; if (stripe->rst_search_commit_root) { path->skip_locking = 1; path->search_commit_root = 1; } ret = btrfs_search_slot(NULL, stripe_root, &stripe_key, path, 0, 0); if (ret < 0) goto free_path; if (ret) { if (path->slots[0] != 0) path->slots[0]--; } while (1) { leaf = path->nodes[0]; slot = path->slots[0]; btrfs_item_key_to_cpu(leaf, &found_key, slot); found_logical = found_key.objectid; found_length = found_key.offset; found_end = found_logical + found_length; if (found_logical > end) { ret = -ENODATA; goto out; } if (in_range(logical, found_logical, found_length)) break; ret = btrfs_next_item(stripe_root, path); if (ret) goto out; } offset = logical - found_logical; /* * If we have a logically contiguous, but physically non-continuous * range, we need to split the bio. Record the length after which we * must split the bio. */ if (end > found_end) *length -= end - found_end; num_stripes = btrfs_num_raid_stripes(btrfs_item_size(leaf, slot)); stripe_extent = btrfs_item_ptr(leaf, slot, struct btrfs_stripe_extent); for (int i = 0; i < num_stripes; i++) { struct btrfs_raid_stride *stride = &stripe_extent->strides[i]; u64 devid = btrfs_raid_stride_devid(leaf, stride); u64 physical = btrfs_raid_stride_physical(leaf, stride); if (devid != stripe->dev->devid) continue; if ((map_type & BTRFS_BLOCK_GROUP_DUP) && stripe_index != i) continue; stripe->physical = physical + offset; trace_btrfs_get_raid_extent_offset(fs_info, logical, *length, stripe->physical, devid); ret = 0; goto free_path; } /* If we're here, we haven't found the requested devid in the stripe. */ ret = -ENODATA; out: if (ret > 0) ret = -ENODATA; if (ret && ret != -EIO && !stripe->rst_search_commit_root) { btrfs_debug(fs_info, "cannot find raid-stripe for logical [%llu, %llu] devid %llu, profile %s", logical, logical + *length, stripe->dev->devid, btrfs_bg_type_to_raid_name(map_type)); } free_path: btrfs_free_path(path); return ret; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
You can’t perform that action at this time.