Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
d8d5f3e1
Commit
d8d5f3e1
authored
Dec 11, 2007
by
Chris Mason
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Btrfs: Add lowest key information to back refs for extent tree blocks as well.
Signed-off-by:
Chris Mason
<
chris.mason@oracle.com
>
parent
7bb86316
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
110 additions
and
19 deletions
+110
-19
fs/btrfs/disk-io.c
fs/btrfs/disk-io.c
+1
-1
fs/btrfs/extent-tree.c
fs/btrfs/extent-tree.c
+101
-1
fs/btrfs/file.c
fs/btrfs/file.c
+4
-7
fs/btrfs/inode.c
fs/btrfs/inode.c
+4
-10
No files found.
fs/btrfs/disk-io.c
View file @
d8d5f3e1
...
...
@@ -210,7 +210,7 @@ static int btree_writepages(struct address_space *mapping,
{
struct
extent_map_tree
*
tree
;
tree
=
&
BTRFS_I
(
mapping
->
host
)
->
extent_tree
;
if
(
0
&&
wbc
->
sync_mode
==
WB_SYNC_NONE
)
{
if
(
wbc
->
sync_mode
==
WB_SYNC_NONE
)
{
u64
num_dirty
;
u64
start
=
0
;
unsigned
long
thresh
=
96
*
1024
*
1024
;
...
...
fs/btrfs/extent-tree.c
View file @
d8d5f3e1
...
...
@@ -457,6 +457,94 @@ static int lookup_extent_backref(struct btrfs_trans_handle *trans,
return
ret
;
}
/*
* Back reference rules. Back refs have three main goals:
*
* 1) differentiate between all holders of references to an extent so that
* when a reference is dropped we can make sure it was a valid reference
* before freeing the extent.
*
* 2) Provide enough information to quickly find the holders of an extent
* if we notice a given block is corrupted or bad.
*
* 3) Make it easy to migrate blocks for FS shrinking or storage pool
* maintenance. This is actually the same as #2, but with a slightly
* different use case.
*
* File extents can be referenced by:
*
* - multiple snapshots, subvolumes, or different generations in one subvol
* - different files inside a single subvolume (in theory, not implemented yet)
* - different offsets inside a file (bookend extents in file.c)
*
* The extent ref structure has fields for:
*
* - Objectid of the subvolume root
* - Generation number of the tree holding the reference
* - objectid of the file holding the reference
* - offset in the file corresponding to the key holding the reference
*
* When a file extent is allocated the fields are filled in:
* (root_key.objectid, trans->transid, inode objectid, offset in file)
*
* When a leaf is cow'd new references are added for every file extent found
* in the leaf. It looks the same as the create case, but trans->transid
* will be different when the block is cow'd.
*
* (root_key.objectid, trans->transid, inode objectid, offset in file)
*
* When a file extent is removed either during snapshot deletion or file
* truncation, the corresponding back reference is found
* by searching for:
*
* (btrfs_header_owner(leaf), btrfs_header_generation(leaf),
* inode objectid, offset in file)
*
* Btree extents can be referenced by:
*
* - Different subvolumes
* - Different generations of the same subvolume
*
* Storing sufficient information for a full reverse mapping of a btree
* block would require storing the lowest key of the block in the backref,
* and it would require updating that lowest key either before write out or
* every time it changed. Instead, the objectid of the lowest key is stored
* along with the level of the tree block. This provides a hint
* about where in the btree the block can be found. Searches through the
* btree only need to look for a pointer to that block, so they stop one
* level higher than the level recorded in the backref.
*
* Some btrees do not do reference counting on their extents. These
* include the extent tree and the tree of tree roots. Backrefs for these
* trees always have a generation of zero.
*
* When a tree block is created, back references are inserted:
*
* (root->root_key.objectid, trans->transid or zero, lowest_key_objectid, level)
*
* When a tree block is cow'd in a reference counted root,
* new back references are added for all the blocks it points to.
* These are of the form (trans->transid will have increased since creation):
*
* (root->root_key.objectid, trans->transid, lowest_key_objectid, level)
*
* Because the lowest_key_objectid and the level are just hints
* they are not used when backrefs are deleted. When a backref is deleted:
*
* if backref was for a tree root:
* root_objectid = root->root_key.objectid
* else
* root_objectid = btrfs_header_owner(parent)
*
* (root_objectid, btrfs_header_generation(parent) or zero, 0, 0)
*
* Back Reference Key hashing:
*
* Back references have four fields, each 64 bits long. Unfortunately,
* This is hashed into a single 64 bit number and placed into the key offset.
* The key objectid corresponds to the first byte in the extent, and the
* key type is set to BTRFS_EXTENT_REF_KEY
*/
int
btrfs_insert_extent_backref
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
struct
btrfs_path
*
path
,
u64
bytenr
,
...
...
@@ -939,10 +1027,13 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
u64
start
;
u64
end
;
struct
btrfs_fs_info
*
info
=
extent_root
->
fs_info
;
struct
extent_buffer
*
eb
;
struct
btrfs_path
*
path
;
struct
btrfs_key
ins
;
struct
btrfs_disk_key
first
;
struct
btrfs_extent_item
extent_item
;
int
ret
;
int
level
;
int
err
=
0
;
btrfs_set_stack_extent_refs
(
&
extent_item
,
1
);
...
...
@@ -961,10 +1052,19 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
&
extent_item
,
sizeof
(
extent_item
));
clear_extent_bits
(
&
info
->
extent_ins
,
start
,
end
,
EXTENT_LOCKED
,
GFP_NOFS
);
eb
=
read_tree_block
(
extent_root
,
ins
.
objectid
,
ins
.
offset
);
level
=
btrfs_header_level
(
eb
);
if
(
level
==
0
)
{
btrfs_item_key
(
eb
,
&
first
,
0
);
}
else
{
btrfs_node_key
(
eb
,
&
first
,
0
);
}
err
=
btrfs_insert_extent_backref
(
trans
,
extent_root
,
path
,
start
,
extent_root
->
root_key
.
objectid
,
0
,
0
,
0
);
0
,
btrfs_disk_key_objectid
(
&
first
),
level
);
BUG_ON
(
err
);
free_extent_buffer
(
eb
);
}
btrfs_free_path
(
path
);
return
0
;
...
...
fs/btrfs/file.c
View file @
d8d5f3e1
...
...
@@ -545,13 +545,10 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
u64
disk_num_bytes
=
0
;
u64
extent_num_bytes
=
0
;
u64
root_gen
;
u64
root_owner
;
if
(
leaf
!=
root
->
node
)
{
root_gen
=
btrfs_header_generation
(
path
->
nodes
[
1
]);
}
else
{
root_gen
=
btrfs_header_generation
(
leaf
);
}
root_gen
=
btrfs_header_generation
(
leaf
);
root_owner
=
btrfs_header_owner
(
leaf
);
if
(
found_extent
)
{
disk_bytenr
=
btrfs_file_extent_disk_bytenr
(
leaf
,
...
...
@@ -575,7 +572,7 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
ret
=
btrfs_free_extent
(
trans
,
root
,
disk_bytenr
,
disk_num_bytes
,
root
->
root_key
.
objectid
,
root
_owner
,
root_gen
,
inode
->
i_ino
,
key
.
offset
,
0
);
}
...
...
fs/btrfs/inode.c
View file @
d8d5f3e1
...
...
@@ -563,6 +563,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
u64
extent_num_bytes
=
0
;
u64
item_end
=
0
;
u64
root_gen
=
0
;
u64
root_owner
=
0
;
int
found_extent
;
int
del_item
;
int
extent_type
=
-
1
;
...
...
@@ -673,15 +674,8 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
found_extent
=
1
;
inode
->
i_blocks
-=
num_dec
;
}
if
(
leaf
==
root
->
node
)
{
root_gen
=
btrfs_header_generation
(
leaf
);
}
else
{
struct
extent_buffer
*
parent
;
parent
=
path
->
nodes
[
1
];
root_gen
=
btrfs_header_generation
(
parent
);
}
root_gen
=
btrfs_header_generation
(
leaf
);
root_owner
=
btrfs_header_owner
(
leaf
);
}
}
else
if
(
extent_type
==
BTRFS_FILE_EXTENT_INLINE
&&
!
del_item
)
{
...
...
@@ -703,7 +697,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
if
(
found_extent
)
{
ret
=
btrfs_free_extent
(
trans
,
root
,
extent_start
,
extent_num_bytes
,
root
->
root_key
.
objectid
,
root
_owner
,
root_gen
,
inode
->
i_ino
,
found_key
.
offset
,
0
);
BUG_ON
(
ret
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment