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
bb803951
Commit
bb803951
authored
Mar 01, 2007
by
Chris Mason
Committed by
David Woodhouse
Mar 01, 2007
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Btrfs: merge on the way down during deletes
Signed-off-by:
Chris Mason
<
chris.mason@oracle.com
>
parent
0f70abe2
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
200 additions
and
220 deletions
+200
-220
fs/btrfs/ctree.c
fs/btrfs/ctree.c
+200
-220
No files found.
fs/btrfs/ctree.c
View file @
bb803951
...
...
@@ -10,11 +10,10 @@ static int split_node(struct ctree_root *root, struct ctree_path *path,
int
level
);
static
int
split_leaf
(
struct
ctree_root
*
root
,
struct
ctree_path
*
path
,
int
data_size
);
static
int
push_node_left
(
struct
ctree_root
*
root
,
struct
ctree_path
*
path
,
int
level
);
static
int
push_node_right
(
struct
ctree_root
*
root
,
struct
ctree_path
*
path
,
int
level
);
static
int
del_ptr
(
struct
ctree_root
*
root
,
struct
ctree_path
*
path
,
int
level
);
static
int
push_node_left
(
struct
ctree_root
*
root
,
struct
tree_buffer
*
dst
,
struct
tree_buffer
*
src
);
static
int
del_ptr
(
struct
ctree_root
*
root
,
struct
ctree_path
*
path
,
int
level
,
int
slot
);
inline
void
init_path
(
struct
ctree_path
*
p
)
{
...
...
@@ -192,6 +191,138 @@ int bin_search(struct node *c, struct key *key, int *slot)
return
-
1
;
}
struct
tree_buffer
*
read_node_slot
(
struct
ctree_root
*
root
,
struct
tree_buffer
*
parent_buf
,
int
slot
)
{
struct
node
*
node
=
&
parent_buf
->
node
;
if
(
slot
<
0
)
return
NULL
;
if
(
slot
>=
node
->
header
.
nritems
)
return
NULL
;
return
read_tree_block
(
root
,
node
->
blockptrs
[
slot
]);
}
static
int
balance_level
(
struct
ctree_root
*
root
,
struct
ctree_path
*
path
,
int
level
)
{
struct
tree_buffer
*
right_buf
;
struct
tree_buffer
*
mid_buf
;
struct
tree_buffer
*
left_buf
;
struct
tree_buffer
*
parent_buf
=
NULL
;
struct
node
*
right
=
NULL
;
struct
node
*
mid
;
struct
node
*
left
=
NULL
;
struct
node
*
parent
=
NULL
;
int
ret
=
0
;
int
wret
;
int
pslot
;
int
used
=
0
;
int
count
;
int
orig_slot
=
path
->
slots
[
level
];
if
(
level
==
0
)
return
0
;
mid_buf
=
path
->
nodes
[
level
];
mid
=
&
mid_buf
->
node
;
if
(
level
<
MAX_LEVEL
-
1
)
parent_buf
=
path
->
nodes
[
level
+
1
];
pslot
=
path
->
slots
[
level
+
1
];
if
(
!
parent_buf
)
{
struct
tree_buffer
*
child
;
u64
blocknr
=
mid_buf
->
blocknr
;
if
(
mid
->
header
.
nritems
!=
1
)
return
0
;
/* promote the child to a root */
child
=
read_node_slot
(
root
,
mid_buf
,
0
);
BUG_ON
(
!
child
);
root
->
node
=
child
;
path
->
nodes
[
level
]
=
NULL
;
/* once for the path */
tree_block_release
(
root
,
mid_buf
);
/* once for the root ptr */
tree_block_release
(
root
,
mid_buf
);
return
free_extent
(
root
,
blocknr
,
1
);
}
parent
=
&
parent_buf
->
node
;
if
(
mid
->
header
.
nritems
>
NODEPTRS_PER_BLOCK
/
4
)
return
0
;
// print_tree(root, root->node);
left_buf
=
read_node_slot
(
root
,
parent_buf
,
pslot
-
1
);
right_buf
=
read_node_slot
(
root
,
parent_buf
,
pslot
+
1
);
if
(
right_buf
)
{
right
=
&
right_buf
->
node
;
used
=
right
->
header
.
nritems
;
count
=
1
;
}
if
(
left_buf
)
{
left
=
&
left_buf
->
node
;
used
+=
left
->
header
.
nritems
;
orig_slot
+=
left
->
header
.
nritems
;
count
++
;
}
if
(
left_buf
)
push_node_left
(
root
,
left_buf
,
mid_buf
);
if
(
right_buf
)
{
push_node_left
(
root
,
mid_buf
,
right_buf
);
if
(
right
->
header
.
nritems
==
0
)
{
u64
blocknr
=
right_buf
->
blocknr
;
tree_block_release
(
root
,
right_buf
);
right_buf
=
NULL
;
right
=
NULL
;
wret
=
del_ptr
(
root
,
path
,
level
+
1
,
pslot
+
1
);
if
(
wret
)
ret
=
wret
;
wret
=
free_extent
(
root
,
blocknr
,
1
);
if
(
wret
)
ret
=
wret
;
}
else
{
memcpy
(
parent
->
keys
+
pslot
+
1
,
right
->
keys
,
sizeof
(
struct
key
));
}
}
if
(
mid
->
header
.
nritems
==
0
)
{
u64
blocknr
=
mid_buf
->
blocknr
;
tree_block_release
(
root
,
mid_buf
);
mid_buf
=
NULL
;
mid
=
NULL
;
wret
=
del_ptr
(
root
,
path
,
level
+
1
,
pslot
);
if
(
wret
)
ret
=
wret
;
wret
=
free_extent
(
root
,
blocknr
,
1
);
if
(
wret
)
ret
=
wret
;
}
else
memcpy
(
parent
->
keys
+
pslot
,
mid
->
keys
,
sizeof
(
struct
key
));
if
(
left_buf
)
{
if
(
left
->
header
.
nritems
>=
orig_slot
)
{
left_buf
->
count
++
;
// released below
path
->
nodes
[
level
]
=
left_buf
;
path
->
slots
[
level
+
1
]
-=
1
;
path
->
slots
[
level
]
=
orig_slot
;
if
(
mid_buf
)
tree_block_release
(
root
,
mid_buf
);
}
else
{
orig_slot
-=
left
->
header
.
nritems
;
path
->
slots
[
level
]
=
orig_slot
;
}
}
if
(
right_buf
)
tree_block_release
(
root
,
right_buf
);
if
(
left_buf
)
tree_block_release
(
root
,
left_buf
);
return
ret
;
}
/*
* look for key in the tree. path is filled in with nodes along the way
* if key is found, we return zero and you can find the item in the leaf
...
...
@@ -208,12 +339,14 @@ int bin_search(struct node *c, struct key *key, int *slot)
int
search_slot
(
struct
ctree_root
*
root
,
struct
key
*
key
,
struct
ctree_path
*
p
,
int
ins_len
)
{
struct
tree_buffer
*
b
=
root
->
node
;
struct
tree_buffer
*
b
;
struct
node
*
c
;
int
slot
;
int
ret
;
int
level
;
again:
b
=
root
->
node
;
b
->
count
++
;
while
(
b
)
{
c
=
&
b
->
node
;
...
...
@@ -236,9 +369,17 @@ int search_slot(struct ctree_root *root, struct key *key,
b
=
p
->
nodes
[
level
];
c
=
&
b
->
node
;
slot
=
p
->
slots
[
level
];
}
else
if
(
ins_len
<
0
)
{
int
sret
=
balance_level
(
root
,
p
,
level
);
if
(
sret
)
return
sret
;
b
=
p
->
nodes
[
level
];
if
(
!
b
)
goto
again
;
c
=
&
b
->
node
;
slot
=
p
->
slots
[
level
];
}
b
=
read_tree_block
(
root
,
c
->
blockptrs
[
slot
]);
continue
;
}
else
{
struct
leaf
*
l
=
(
struct
leaf
*
)
c
;
p
->
slots
[
level
]
=
slot
;
...
...
@@ -249,9 +390,11 @@ int search_slot(struct ctree_root *root, struct key *key,
if
(
sret
)
return
sret
;
}
BUG_ON
(
root
->
node
->
count
==
1
);
return
ret
;
}
}
BUG_ON
(
root
->
node
->
count
==
1
);
return
1
;
}
...
...
@@ -301,163 +444,49 @@ static int fixup_low_keys(struct ctree_root *root,
* returns 0 if some ptrs were pushed left, < 0 if there was some horrible
* error, and > 0 if there was no room in the left hand block.
*/
static
int
push_node_left
(
struct
ctree_root
*
root
,
struct
ctree_path
*
path
,
int
level
)
static
int
push_node_left
(
struct
ctree_root
*
root
,
struct
tree_buffer
*
dst_buf
,
struct
tree_buffer
*
src_buf
)
{
int
slot
;
struct
node
*
left
;
struct
node
*
right
;
struct
node
*
src
=
&
src_buf
->
node
;
struct
node
*
dst
=
&
dst_buf
->
node
;
int
push_items
=
0
;
int
left_nritems
;
int
right_nritems
;
struct
tree_buffer
*
t
;
struct
tree_buffer
*
right_buf
;
int
src_nritems
;
int
dst_nritems
;
int
ret
=
0
;
int
wret
;
if
(
level
==
MAX_LEVEL
-
1
||
path
->
nodes
[
level
+
1
]
==
0
)
return
1
;
slot
=
path
->
slots
[
level
+
1
];
if
(
slot
==
0
)
return
1
;
t
=
read_tree_block
(
root
,
path
->
nodes
[
level
+
1
]
->
node
.
blockptrs
[
slot
-
1
]);
left
=
&
t
->
node
;
right_buf
=
path
->
nodes
[
level
];
right
=
&
right_buf
->
node
;
left_nritems
=
left
->
header
.
nritems
;
right_nritems
=
right
->
header
.
nritems
;
push_items
=
NODEPTRS_PER_BLOCK
-
(
left_nritems
+
1
);
src_nritems
=
src
->
header
.
nritems
;
dst_nritems
=
dst
->
header
.
nritems
;
push_items
=
NODEPTRS_PER_BLOCK
-
dst_nritems
;
if
(
push_items
<=
0
)
{
tree_block_release
(
root
,
t
);
return
1
;
}
if
(
right
_nritems
<
push_items
)
push_items
=
right
_nritems
;
memcpy
(
left
->
keys
+
left_nritems
,
right
->
keys
,
if
(
src
_nritems
<
push_items
)
push_items
=
src
_nritems
;
memcpy
(
dst
->
keys
+
dst_nritems
,
src
->
keys
,
push_items
*
sizeof
(
struct
key
));
memcpy
(
left
->
blockptrs
+
left_nritems
,
right
->
blockptrs
,
memcpy
(
dst
->
blockptrs
+
dst_nritems
,
src
->
blockptrs
,
push_items
*
sizeof
(
u64
));
memmove
(
right
->
keys
,
right
->
keys
+
push_items
,
(
right_nritems
-
push_items
)
*
sizeof
(
struct
key
));
memmove
(
right
->
blockptrs
,
right
->
blockptrs
+
push_items
,
(
right_nritems
-
push_items
)
*
sizeof
(
u64
));
right
->
header
.
nritems
-=
push_items
;
left
->
header
.
nritems
+=
push_items
;
/* adjust the pointers going up the tree */
wret
=
fixup_low_keys
(
root
,
path
,
right
->
keys
,
level
+
1
);
if
(
wret
<
0
)
ret
=
wret
;
if
(
push_items
<
src_nritems
)
{
memmove
(
src
->
keys
,
src
->
keys
+
push_items
,
(
src_nritems
-
push_items
)
*
sizeof
(
struct
key
));
memmove
(
src
->
blockptrs
,
src
->
blockptrs
+
push_items
,
(
src_nritems
-
push_items
)
*
sizeof
(
u64
));
}
src
->
header
.
nritems
-=
push_items
;
dst
->
header
.
nritems
+=
push_items
;
wret
=
write_tree_block
(
root
,
t
);
wret
=
write_tree_block
(
root
,
src_buf
);
if
(
wret
<
0
)
ret
=
wret
;
wret
=
write_tree_block
(
root
,
righ
t_buf
);
wret
=
write_tree_block
(
root
,
ds
t_buf
);
if
(
wret
<
0
)
ret
=
wret
;
/* then fixup the leaf pointer in the path */
if
(
path
->
slots
[
level
]
<
push_items
)
{
path
->
slots
[
level
]
+=
left_nritems
;
tree_block_release
(
root
,
path
->
nodes
[
level
]);
path
->
nodes
[
level
]
=
t
;
path
->
slots
[
level
+
1
]
-=
1
;
}
else
{
path
->
slots
[
level
]
-=
push_items
;
tree_block_release
(
root
,
t
);
}
return
ret
;
}
/*
* try to push data from one node into the next node right in the
* tree. The src node is found at specified level in the path.
* If some bytes were pushed, return 0, otherwise return 1.
*
* Lower nodes/leaves in the path are not touched, higher nodes may
* be modified to reflect the push.
*
* The path is altered to reflect the push.
*
* returns 0 if some ptrs were pushed, < 0 if there was some horrible
* error, and > 0 if there was no room in the right hand block.
*/
static
int
push_node_right
(
struct
ctree_root
*
root
,
struct
ctree_path
*
path
,
int
level
)
{
int
slot
;
struct
tree_buffer
*
t
;
struct
tree_buffer
*
src_buffer
;
struct
node
*
dst
;
struct
node
*
src
;
int
push_items
=
0
;
int
dst_nritems
;
int
src_nritems
;
/* can't push from the root */
if
(
level
==
MAX_LEVEL
-
1
||
path
->
nodes
[
level
+
1
]
==
0
)
return
1
;
/* only try to push inside the node higher up */
slot
=
path
->
slots
[
level
+
1
];
if
(
slot
==
NODEPTRS_PER_BLOCK
-
1
)
return
1
;
if
(
slot
>=
path
->
nodes
[
level
+
1
]
->
node
.
header
.
nritems
-
1
)
return
1
;
t
=
read_tree_block
(
root
,
path
->
nodes
[
level
+
1
]
->
node
.
blockptrs
[
slot
+
1
]);
dst
=
&
t
->
node
;
src_buffer
=
path
->
nodes
[
level
];
src
=
&
src_buffer
->
node
;
dst_nritems
=
dst
->
header
.
nritems
;
src_nritems
=
src
->
header
.
nritems
;
push_items
=
NODEPTRS_PER_BLOCK
-
(
dst_nritems
+
1
);
if
(
push_items
<=
0
)
{
tree_block_release
(
root
,
t
);
return
1
;
}
if
(
src_nritems
<
push_items
)
push_items
=
src_nritems
;
memmove
(
dst
->
keys
+
push_items
,
dst
->
keys
,
dst_nritems
*
sizeof
(
struct
key
));
memcpy
(
dst
->
keys
,
src
->
keys
+
src_nritems
-
push_items
,
push_items
*
sizeof
(
struct
key
));
memmove
(
dst
->
blockptrs
+
push_items
,
dst
->
blockptrs
,
dst_nritems
*
sizeof
(
u64
));
memcpy
(
dst
->
blockptrs
,
src
->
blockptrs
+
src_nritems
-
push_items
,
push_items
*
sizeof
(
u64
));
src
->
header
.
nritems
-=
push_items
;
dst
->
header
.
nritems
+=
push_items
;
/* adjust the pointers going up the tree */
memcpy
(
path
->
nodes
[
level
+
1
]
->
node
.
keys
+
path
->
slots
[
level
+
1
]
+
1
,
dst
->
keys
,
sizeof
(
struct
key
));
write_tree_block
(
root
,
path
->
nodes
[
level
+
1
]);
write_tree_block
(
root
,
t
);
write_tree_block
(
root
,
src_buffer
);
/* then fixup the pointers in the path */
if
(
path
->
slots
[
level
]
>=
src
->
header
.
nritems
)
{
path
->
slots
[
level
]
-=
src
->
header
.
nritems
;
tree_block_release
(
root
,
path
->
nodes
[
level
]);
path
->
nodes
[
level
]
=
t
;
path
->
slots
[
level
+
1
]
+=
1
;
}
else
{
tree_block_release
(
root
,
t
);
}
return
0
;
}
/*
* helper function to insert a new root level in the tree.
* A new node is allocated, and a single item is inserted to
...
...
@@ -558,16 +587,6 @@ static int split_node(struct ctree_root *root, struct ctree_path *path,
int
ret
;
int
wret
;
ret
=
push_node_left
(
root
,
path
,
level
);
if
(
!
ret
)
return
0
;
if
(
ret
<
0
)
return
ret
;
ret
=
push_node_right
(
root
,
path
,
level
);
if
(
!
ret
)
return
0
;
if
(
ret
<
0
)
return
ret
;
t
=
path
->
nodes
[
level
];
c
=
&
t
->
node
;
if
(
t
==
root
->
node
)
{
...
...
@@ -1011,6 +1030,7 @@ int insert_item(struct ctree_root *root, struct key *key,
if
(
leaf_free_space
(
leaf
)
<
0
)
BUG
();
check_leaf
(
&
path
,
0
);
release_path
(
root
,
&
path
);
return
ret
;
}
...
...
@@ -1022,77 +1042,38 @@ int insert_item(struct ctree_root *root, struct key *key,
* continuing all the way the root if required. The root is converted into
* a leaf if all the nodes are emptied.
*/
static
int
del_ptr
(
struct
ctree_root
*
root
,
struct
ctree_path
*
path
,
int
level
)
static
int
del_ptr
(
struct
ctree_root
*
root
,
struct
ctree_path
*
path
,
int
level
,
int
slot
)
{
int
slot
;
struct
tree_buffer
*
t
;
struct
node
*
node
;
struct
tree_buffer
*
parent
=
path
->
nodes
[
level
];
int
nritems
;
u64
blocknr
;
int
wret
;
int
ret
=
0
;
int
wret
;
while
(
1
)
{
t
=
path
->
nodes
[
level
];
if
(
!
t
)
break
;
node
=
&
t
->
node
;
slot
=
path
->
slots
[
level
];
nritems
=
node
->
header
.
nritems
;
if
(
slot
!=
nritems
-
1
)
{
memmove
(
node
->
keys
+
slot
,
node
->
keys
+
slot
+
1
,
sizeof
(
struct
key
)
*
(
nritems
-
slot
-
1
));
memmove
(
node
->
blockptrs
+
slot
,
node
->
blockptrs
+
slot
+
1
,
sizeof
(
u64
)
*
(
nritems
-
slot
-
1
));
}
node
->
header
.
nritems
--
;
blocknr
=
t
->
blocknr
;
write_tree_block
(
root
,
t
);
if
(
node
->
header
.
nritems
!=
0
)
{
int
tslot
;
if
(
slot
==
0
)
{
wret
=
fixup_low_keys
(
root
,
path
,
node
->
keys
,
level
+
1
);
if
(
wret
)
ret
=
wret
;
}
tslot
=
path
->
slots
[
level
+
1
];
t
->
count
++
;
wret
=
push_node_left
(
root
,
path
,
level
);
if
(
wret
<
0
)
{
ret
=
wret
;
break
;
}
if
(
node
->
header
.
nritems
!=
0
)
{
wret
=
push_node_right
(
root
,
path
,
level
);
if
(
wret
<
0
)
{
ret
=
wret
;
break
;
}
}
path
->
slots
[
level
+
1
]
=
tslot
;
if
(
node
->
header
.
nritems
!=
0
)
{
tree_block_release
(
root
,
t
);
break
;
}
tree_block_release
(
root
,
t
);
}
if
(
t
==
root
->
node
)
{
/* just turn the root into a leaf and break */
root
->
node
->
node
.
header
.
flags
=
node_level
(
0
);
write_tree_block
(
root
,
t
);
break
;
}
level
++
;
wret
=
free_extent
(
root
,
blocknr
,
1
);
node
=
&
parent
->
node
;
nritems
=
node
->
header
.
nritems
;
if
(
slot
!=
nritems
-
1
)
{
memmove
(
node
->
keys
+
slot
,
node
->
keys
+
slot
+
1
,
sizeof
(
struct
key
)
*
(
nritems
-
slot
-
1
));
memmove
(
node
->
blockptrs
+
slot
,
node
->
blockptrs
+
slot
+
1
,
sizeof
(
u64
)
*
(
nritems
-
slot
-
1
));
}
node
->
header
.
nritems
--
;
if
(
node
->
header
.
nritems
==
0
&&
parent
==
root
->
node
)
{
BUG_ON
(
node_level
(
root
->
node
->
node
.
header
.
flags
)
!=
1
);
/* just turn the root into a leaf and break */
root
->
node
->
node
.
header
.
flags
=
node_level
(
0
);
}
else
if
(
slot
==
0
)
{
wret
=
fixup_low_keys
(
root
,
path
,
node
->
keys
,
level
+
1
);
if
(
wret
)
ret
=
wret
;
if
(
!
path
->
nodes
[
level
])
BUG
();
}
wret
=
write_tree_block
(
root
,
parent
);
if
(
wret
)
ret
=
wret
;
return
ret
;
}
...
...
@@ -1135,7 +1116,7 @@ int del_item(struct ctree_root *root, struct ctree_path *path)
leaf
->
header
.
flags
=
node_level
(
0
);
write_tree_block
(
root
,
leaf_buf
);
}
else
{
wret
=
del_ptr
(
root
,
path
,
1
);
wret
=
del_ptr
(
root
,
path
,
1
,
path
->
slots
[
1
]
);
if
(
wret
)
ret
=
wret
;
wret
=
free_extent
(
root
,
leaf_buf
->
blocknr
,
1
);
...
...
@@ -1172,8 +1153,7 @@ int del_item(struct ctree_root *root, struct ctree_path *path)
}
if
(
leaf
->
header
.
nritems
==
0
)
{
u64
blocknr
=
leaf_buf
->
blocknr
;
path
->
slots
[
1
]
=
slot
;
wret
=
del_ptr
(
root
,
path
,
1
);
wret
=
del_ptr
(
root
,
path
,
1
,
slot
);
if
(
wret
)
ret
=
wret
;
tree_block_release
(
root
,
leaf_buf
);
...
...
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