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
nexedi
linux
Commits
54aa1f4d
Commit
54aa1f4d
authored
Jun 22, 2007
by
Chris Mason
Committed by
David Woodhouse
Jun 22, 2007
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Btrfs: Audit callers and return codes to make sure -ENOSPC gets up the stack
Signed-off-by:
Chris Mason
<
chris.mason@oracle.com
>
parent
11bd143f
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
410 additions
and
215 deletions
+410
-215
fs/btrfs/ctree.c
fs/btrfs/ctree.c
+82
-24
fs/btrfs/ctree.h
fs/btrfs/ctree.h
+0
-3
fs/btrfs/dir-item.c
fs/btrfs/dir-item.c
+3
-3
fs/btrfs/disk-io.c
fs/btrfs/disk-io.c
+1
-1
fs/btrfs/extent-tree.c
fs/btrfs/extent-tree.c
+115
-26
fs/btrfs/file-item.c
fs/btrfs/file-item.c
+6
-40
fs/btrfs/file.c
fs/btrfs/file.c
+81
-50
fs/btrfs/inode.c
fs/btrfs/inode.c
+107
-58
fs/btrfs/root-tree.c
fs/btrfs/root-tree.c
+0
-1
fs/btrfs/super.c
fs/btrfs/super.c
+1
-2
fs/btrfs/transaction.c
fs/btrfs/transaction.c
+14
-7
No files found.
fs/btrfs/ctree.c
View file @
54aa1f4d
...
...
@@ -73,6 +73,7 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
{
struct
buffer_head
*
cow
;
struct
btrfs_node
*
cow_node
;
int
ret
;
if
(
btrfs_header_generation
(
btrfs_buffer_header
(
buf
))
==
trans
->
transid
)
{
...
...
@@ -80,6 +81,8 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
return
0
;
}
cow
=
btrfs_alloc_free_block
(
trans
,
root
,
buf
->
b_blocknr
);
if
(
IS_ERR
(
cow
))
return
PTR_ERR
(
cow
);
cow_node
=
btrfs_buffer_node
(
cow
);
if
(
buf
->
b_size
!=
root
->
blocksize
||
cow
->
b_size
!=
root
->
blocksize
)
WARN_ON
(
1
);
...
...
@@ -87,7 +90,9 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_set_header_blocknr
(
&
cow_node
->
header
,
bh_blocknr
(
cow
));
btrfs_set_header_generation
(
&
cow_node
->
header
,
trans
->
transid
);
btrfs_set_header_owner
(
&
cow_node
->
header
,
root
->
root_key
.
objectid
);
btrfs_inc_ref
(
trans
,
root
,
buf
);
ret
=
btrfs_inc_ref
(
trans
,
root
,
buf
);
if
(
ret
)
return
ret
;
if
(
buf
==
root
->
node
)
{
root
->
node
=
cow
;
get_bh
(
cow
);
...
...
@@ -320,6 +325,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
int
wret
;
int
pslot
;
int
orig_slot
=
path
->
slots
[
level
];
int
err_on_enospc
=
0
;
u64
orig_ptr
;
if
(
level
==
0
)
...
...
@@ -363,29 +369,43 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
BTRFS_NODEPTRS_PER_BLOCK
(
root
)
/
4
)
return
0
;
if
(
btrfs_header_nritems
(
&
mid
->
header
)
<
2
)
err_on_enospc
=
1
;
left_buf
=
read_node_slot
(
root
,
parent_buf
,
pslot
-
1
);
right_buf
=
read_node_slot
(
root
,
parent_buf
,
pslot
+
1
);
/* first, try to make some room in the middle buffer */
if
(
left_buf
)
{
btrfs_cow_block
(
trans
,
root
,
left_buf
,
parent_buf
,
pslot
-
1
,
&
left_buf
);
wret
=
btrfs_cow_block
(
trans
,
root
,
left_buf
,
parent_buf
,
pslot
-
1
,
&
left_buf
);
if
(
wret
)
{
ret
=
wret
;
goto
enospc
;
}
left
=
btrfs_buffer_node
(
left_buf
);
orig_slot
+=
btrfs_header_nritems
(
&
left
->
header
);
wret
=
push_node_left
(
trans
,
root
,
left_buf
,
mid_buf
);
if
(
wret
<
0
)
ret
=
wret
;
if
(
btrfs_header_nritems
(
&
mid
->
header
)
<
2
)
err_on_enospc
=
1
;
}
/*
* then try to empty the right most buffer into the middle
*/
if
(
right_buf
)
{
btrfs_cow_block
(
trans
,
root
,
right_buf
,
parent_buf
,
pslot
+
1
,
&
right_buf
);
wret
=
btrfs_cow_block
(
trans
,
root
,
right_buf
,
parent_buf
,
pslot
+
1
,
&
right_buf
);
if
(
wret
)
{
ret
=
wret
;
goto
enospc
;
}
right
=
btrfs_buffer_node
(
right_buf
);
wret
=
push_node_left
(
trans
,
root
,
mid_buf
,
right_buf
);
if
(
wret
<
0
)
if
(
wret
<
0
&&
wret
!=
-
ENOSPC
)
ret
=
wret
;
if
(
btrfs_header_nritems
(
&
right
->
header
)
==
0
)
{
u64
blocknr
=
bh_blocknr
(
right_buf
);
...
...
@@ -421,8 +441,10 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
*/
BUG_ON
(
!
left_buf
);
wret
=
balance_node_right
(
trans
,
root
,
mid_buf
,
left_buf
);
if
(
wret
<
0
)
if
(
wret
<
0
)
{
ret
=
wret
;
goto
enospc
;
}
BUG_ON
(
wret
==
1
);
}
if
(
btrfs_header_nritems
(
&
mid
->
header
)
==
0
)
{
...
...
@@ -467,7 +489,7 @@ static int balance_level(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_node_blockptr
(
btrfs_buffer_node
(
path
->
nodes
[
level
]),
path
->
slots
[
level
]))
BUG
();
enospc:
if
(
right_buf
)
btrfs_block_release
(
root
,
right_buf
);
if
(
left_buf
)
...
...
@@ -519,10 +541,15 @@ static int push_nodes_for_insert(struct btrfs_trans_handle *trans,
if
(
left_nr
>=
BTRFS_NODEPTRS_PER_BLOCK
(
root
)
-
1
)
{
wret
=
1
;
}
else
{
btrfs_cow_block
(
trans
,
root
,
left_buf
,
parent_buf
,
ret
=
btrfs_cow_block
(
trans
,
root
,
left_buf
,
parent_buf
,
pslot
-
1
,
&
left_buf
);
if
(
ret
)
wret
=
1
;
else
{
left
=
btrfs_buffer_node
(
left_buf
);
wret
=
push_node_left
(
trans
,
root
,
left_buf
,
mid_buf
);
wret
=
push_node_left
(
trans
,
root
,
left_buf
,
mid_buf
);
}
}
if
(
wret
<
0
)
ret
=
wret
;
...
...
@@ -561,12 +588,17 @@ static int push_nodes_for_insert(struct btrfs_trans_handle *trans,
if
(
right_nr
>=
BTRFS_NODEPTRS_PER_BLOCK
(
root
)
-
1
)
{
wret
=
1
;
}
else
{
btrfs_cow_block
(
trans
,
root
,
right_buf
,
parent_buf
,
pslot
+
1
,
&
right_buf
);
ret
=
btrfs_cow_block
(
trans
,
root
,
right_buf
,
parent_buf
,
pslot
+
1
,
&
right_buf
);
if
(
ret
)
wret
=
1
;
else
{
right
=
btrfs_buffer_node
(
right_buf
);
wret
=
balance_node_right
(
trans
,
root
,
right_buf
,
mid_buf
);
}
}
if
(
wret
<
0
)
ret
=
wret
;
if
(
wret
==
0
)
{
...
...
@@ -631,6 +663,10 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
p
->
nodes
[
level
+
1
],
p
->
slots
[
level
+
1
],
&
cow_buf
);
if
(
wret
)
{
btrfs_block_release
(
root
,
cow_buf
);
return
wret
;
}
b
=
cow_buf
;
c
=
btrfs_buffer_node
(
b
);
}
...
...
@@ -737,6 +773,7 @@ static int push_node_left(struct btrfs_trans_handle *trans, struct btrfs_root
src_nritems
=
btrfs_header_nritems
(
&
src
->
header
);
dst_nritems
=
btrfs_header_nritems
(
&
dst
->
header
);
push_items
=
BTRFS_NODEPTRS_PER_BLOCK
(
root
)
-
dst_nritems
;
if
(
push_items
<=
0
)
{
return
1
;
}
...
...
@@ -827,6 +864,8 @@ static int insert_new_root(struct btrfs_trans_handle *trans, struct btrfs_root
BUG_ON
(
path
->
nodes
[
level
-
1
]
!=
root
->
node
);
t
=
btrfs_alloc_free_block
(
trans
,
root
,
root
->
node
->
b_blocknr
);
if
(
IS_ERR
(
t
))
return
PTR_ERR
(
t
);
c
=
btrfs_buffer_node
(
t
);
memset
(
c
,
0
,
root
->
blocksize
);
btrfs_set_header_nritems
(
&
c
->
header
,
1
);
...
...
@@ -929,10 +968,15 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_header_nritems
(
&
c
->
header
)
<
BTRFS_NODEPTRS_PER_BLOCK
(
root
)
-
1
)
return
0
;
if
(
ret
<
0
)
return
ret
;
}
c_nritems
=
btrfs_header_nritems
(
&
c
->
header
);
split_buffer
=
btrfs_alloc_free_block
(
trans
,
root
,
t
->
b_blocknr
);
if
(
IS_ERR
(
split_buffer
))
return
PTR_ERR
(
split_buffer
);
split
=
btrfs_buffer_node
(
split_buffer
);
btrfs_set_header_flags
(
&
split
->
header
,
btrfs_header_flags
(
&
c
->
header
));
btrfs_set_header_level
(
&
split
->
header
,
btrfs_header_level
(
&
c
->
header
));
...
...
@@ -1022,6 +1066,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
struct
btrfs_item
*
item
;
u32
left_nritems
;
u32
right_nritems
;
int
ret
;
slot
=
path
->
slots
[
1
];
if
(
!
path
->
nodes
[
1
])
{
...
...
@@ -1041,7 +1086,12 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
return
1
;
}
/* cow and double check */
btrfs_cow_block
(
trans
,
root
,
right_buf
,
upper
,
slot
+
1
,
&
right_buf
);
ret
=
btrfs_cow_block
(
trans
,
root
,
right_buf
,
upper
,
slot
+
1
,
&
right_buf
);
if
(
ret
)
{
btrfs_block_release
(
root
,
right_buf
);
return
1
;
}
right
=
btrfs_buffer_leaf
(
right_buf
);
free_space
=
btrfs_leaf_free_space
(
root
,
right
);
if
(
free_space
<
data_size
+
sizeof
(
struct
btrfs_item
))
{
...
...
@@ -1162,7 +1212,11 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
}
/* cow and double check */
btrfs_cow_block
(
trans
,
root
,
t
,
path
->
nodes
[
1
],
slot
-
1
,
&
t
);
ret
=
btrfs_cow_block
(
trans
,
root
,
t
,
path
->
nodes
[
1
],
slot
-
1
,
&
t
);
if
(
ret
)
{
/* we hit -ENOSPC, but it isn't fatal here */
return
1
;
}
left
=
btrfs_buffer_leaf
(
t
);
free_space
=
btrfs_leaf_free_space
(
root
,
left
);
if
(
free_space
<
data_size
+
sizeof
(
struct
btrfs_item
))
{
...
...
@@ -1309,8 +1363,11 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
slot
=
path
->
slots
[
0
];
nritems
=
btrfs_header_nritems
(
&
l
->
header
);
mid
=
(
nritems
+
1
)
/
2
;
right_buffer
=
btrfs_alloc_free_block
(
trans
,
root
,
l_buf
->
b_blocknr
);
BUG_ON
(
!
right_buffer
);
if
(
IS_ERR
(
right_buffer
))
return
PTR_ERR
(
right_buffer
);
right
=
btrfs_buffer_leaf
(
right_buffer
);
memset
(
&
right
->
header
,
0
,
sizeof
(
right
->
header
));
btrfs_set_header_blocknr
(
&
right
->
header
,
bh_blocknr
(
right_buffer
));
...
...
@@ -1407,7 +1464,9 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
if
(
!
double_split
)
return
ret
;
right_buffer
=
btrfs_alloc_free_block
(
trans
,
root
,
l_buf
->
b_blocknr
);
BUG_ON
(
!
right_buffer
);
if
(
IS_ERR
(
right_buffer
))
return
PTR_ERR
(
right_buffer
);
right
=
btrfs_buffer_leaf
(
right_buffer
);
memset
(
&
right
->
header
,
0
,
sizeof
(
right
->
header
));
btrfs_set_header_blocknr
(
&
right
->
header
,
bh_blocknr
(
right_buffer
));
...
...
@@ -1655,7 +1714,6 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
ptr
,
data
,
data_size
);
btrfs_mark_buffer_dirty
(
path
->
nodes
[
0
]);
}
btrfs_release_path
(
root
,
path
);
btrfs_free_path
(
path
);
return
ret
;
}
...
...
@@ -1775,12 +1833,12 @@ int btrfs_del_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
slot
=
path
->
slots
[
1
];
get_bh
(
leaf_buf
);
wret
=
push_leaf_left
(
trans
,
root
,
path
,
1
);
if
(
wret
<
0
)
if
(
wret
<
0
&&
wret
!=
-
ENOSPC
)
ret
=
wret
;
if
(
path
->
nodes
[
0
]
==
leaf_buf
&&
btrfs_header_nritems
(
&
leaf
->
header
))
{
wret
=
push_leaf_right
(
trans
,
root
,
path
,
1
);
if
(
wret
<
0
)
if
(
wret
<
0
&&
wret
!=
-
ENOSPC
)
ret
=
wret
;
}
if
(
btrfs_header_nritems
(
&
leaf
->
header
)
==
0
)
{
...
...
fs/btrfs/ctree.h
View file @
54aa1f4d
...
...
@@ -1126,9 +1126,6 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
struct
btrfs_root
*
root
,
u64
objectid
,
u64
offset
,
char
*
data
,
size_t
len
);
int
btrfs_csum_verify_file_block
(
struct
btrfs_root
*
root
,
u64
objectid
,
u64
offset
,
char
*
data
,
size_t
len
);
struct
btrfs_csum_item
*
btrfs_lookup_csum
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
struct
btrfs_path
*
path
,
...
...
fs/btrfs/dir-item.c
View file @
54aa1f4d
...
...
@@ -47,6 +47,8 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
if
(
ret
)
return
ERR_PTR
(
ret
);
}
if
(
ret
<
0
)
return
ERR_PTR
(
ret
);
WARN_ON
(
ret
>
0
);
leaf
=
btrfs_buffer_leaf
(
path
->
nodes
[
0
]);
item
=
leaf
->
items
+
path
->
slots
[
0
];
...
...
@@ -225,14 +227,13 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
struct
btrfs_leaf
*
leaf
;
u32
sub_item_len
;
u32
item_len
;
int
ret
;
int
ret
=
0
;
leaf
=
btrfs_buffer_leaf
(
path
->
nodes
[
0
]);
sub_item_len
=
sizeof
(
*
di
)
+
btrfs_dir_name_len
(
di
);
item_len
=
btrfs_item_size
(
leaf
->
items
+
path
->
slots
[
0
]);
if
(
sub_item_len
==
btrfs_item_size
(
leaf
->
items
+
path
->
slots
[
0
]))
{
ret
=
btrfs_del_item
(
trans
,
root
,
path
);
BUG_ON
(
ret
);
}
else
{
char
*
ptr
=
(
char
*
)
di
;
char
*
start
=
btrfs_item_ptr
(
leaf
,
path
->
slots
[
0
],
char
);
...
...
@@ -240,7 +241,6 @@ int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans,
item_len
-
(
ptr
+
sub_item_len
-
start
));
ret
=
btrfs_truncate_item
(
trans
,
root
,
path
,
item_len
-
sub_item_len
);
BUG_ON
(
ret
);
}
return
0
;
}
...
...
fs/btrfs/disk-io.c
View file @
54aa1f4d
...
...
@@ -580,7 +580,7 @@ int close_ctree(struct btrfs_root *root)
btrfs_transaction_flush_work
(
root
);
mutex_lock
(
&
fs_info
->
fs_mutex
);
trans
=
btrfs_start_transaction
(
root
,
1
);
btrfs_commit_transaction
(
trans
,
root
);
ret
=
btrfs_commit_transaction
(
trans
,
root
);
/* run commit again to drop the original snapshot */
trans
=
btrfs_start_transaction
(
root
,
1
);
btrfs_commit_transaction
(
trans
,
root
);
...
...
fs/btrfs/extent-tree.c
View file @
54aa1f4d
...
...
@@ -100,6 +100,8 @@ static int cache_block_group(struct btrfs_root *root,
if
(
slot
>=
btrfs_header_nritems
(
&
leaf
->
header
))
{
reada_extent_leaves
(
root
,
path
,
limit
);
ret
=
btrfs_next_leaf
(
root
,
path
);
if
(
ret
<
0
)
goto
err
;
if
(
ret
==
0
)
{
continue
;
}
else
{
...
...
@@ -148,6 +150,7 @@ static int cache_block_group(struct btrfs_root *root,
}
block_group
->
cached
=
1
;
err:
btrfs_free_path
(
path
);
return
0
;
}
...
...
@@ -201,7 +204,9 @@ static u64 find_search_start(struct btrfs_root *root,
last
=
max
(
last
,
cache
->
last_prealloc
);
}
again:
cache_block_group
(
root
,
cache
);
ret
=
cache_block_group
(
root
,
cache
);
if
(
ret
)
goto
out
;
while
(
1
)
{
ret
=
find_first_radix_bit
(
&
root
->
fs_info
->
extent_map_radix
,
gang
,
last
,
ARRAY_SIZE
(
gang
));
...
...
@@ -398,16 +403,23 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
struct
btrfs_key
ins
;
u32
refs
;
find_free_extent
(
trans
,
root
->
fs_info
->
extent_root
,
0
,
0
,
(
u64
)
-
1
,
0
,
&
ins
,
0
);
path
=
btrfs_alloc_path
();
BUG_ON
(
!
path
);
if
(
!
path
)
return
-
ENOMEM
;
ret
=
find_free_extent
(
trans
,
root
->
fs_info
->
extent_root
,
0
,
0
,
(
u64
)
-
1
,
0
,
&
ins
,
0
);
if
(
ret
)
{
btrfs_free_path
(
path
);
return
ret
;
}
key
.
objectid
=
blocknr
;
key
.
flags
=
0
;
btrfs_set_key_type
(
&
key
,
BTRFS_EXTENT_ITEM_KEY
);
key
.
offset
=
num_blocks
;
ret
=
btrfs_search_slot
(
trans
,
root
->
fs_info
->
extent_root
,
&
key
,
path
,
0
,
1
);
if
(
ret
<
0
)
return
ret
;
if
(
ret
!=
0
)
{
BUG
();
}
...
...
@@ -442,12 +454,14 @@ static int lookup_extent_ref(struct btrfs_trans_handle *trans,
btrfs_set_key_type
(
&
key
,
BTRFS_EXTENT_ITEM_KEY
);
ret
=
btrfs_search_slot
(
trans
,
root
->
fs_info
->
extent_root
,
&
key
,
path
,
0
,
0
);
if
(
ret
<
0
)
goto
out
;
if
(
ret
!=
0
)
BUG
();
l
=
btrfs_buffer_leaf
(
path
->
nodes
[
0
]);
item
=
btrfs_item_ptr
(
l
,
path
->
slots
[
0
],
struct
btrfs_extent_item
);
*
refs
=
btrfs_extent_refs
(
item
);
btrfs_release_path
(
root
->
fs_info
->
extent_root
,
path
);
out:
btrfs_free_path
(
path
);
return
0
;
}
...
...
@@ -469,6 +483,8 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
int
i
;
int
leaf
;
int
ret
;
int
faili
;
int
err
;
if
(
!
root
->
ref_cows
)
return
0
;
...
...
@@ -491,14 +507,45 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
continue
;
ret
=
btrfs_inc_extent_ref
(
trans
,
root
,
disk_blocknr
,
btrfs_file_extent_disk_num_blocks
(
fi
));
BUG_ON
(
ret
);
if
(
ret
)
{
faili
=
i
;
goto
fail
;
}
}
else
{
blocknr
=
btrfs_node_blockptr
(
buf_node
,
i
);
ret
=
btrfs_inc_extent_ref
(
trans
,
root
,
blocknr
,
1
);
BUG_ON
(
ret
);
if
(
ret
)
{
faili
=
i
;
goto
fail
;
}
}
}
return
0
;
fail:
for
(
i
=
0
;
i
<
faili
;
i
++
)
{
if
(
leaf
)
{
u64
disk_blocknr
;
key
=
&
buf_leaf
->
items
[
i
].
key
;
if
(
btrfs_disk_key_type
(
key
)
!=
BTRFS_EXTENT_DATA_KEY
)
continue
;
fi
=
btrfs_item_ptr
(
buf_leaf
,
i
,
struct
btrfs_file_extent_item
);
if
(
btrfs_file_extent_type
(
fi
)
==
BTRFS_FILE_EXTENT_INLINE
)
continue
;
disk_blocknr
=
btrfs_file_extent_disk_blocknr
(
fi
);
if
(
disk_blocknr
==
0
)
continue
;
err
=
btrfs_free_extent
(
trans
,
root
,
disk_blocknr
,
btrfs_file_extent_disk_num_blocks
(
fi
),
0
);
BUG_ON
(
err
);
}
else
{
blocknr
=
btrfs_node_blockptr
(
buf_node
,
i
);
err
=
btrfs_free_extent
(
trans
,
root
,
blocknr
,
1
,
0
);
BUG_ON
(
err
);
}
}
return
ret
;
}
static
int
write_one_cache_group
(
struct
btrfs_trans_handle
*
trans
,
...
...
@@ -512,15 +559,20 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
struct
btrfs_block_group_item
*
bi
;
struct
btrfs_key
ins
;
find_free_extent
(
trans
,
extent_root
,
0
,
0
,
(
u64
)
-
1
,
0
,
&
ins
,
0
);
ret
=
find_free_extent
(
trans
,
extent_root
,
0
,
0
,
(
u64
)
-
1
,
0
,
&
ins
,
0
);
/* FIXME, set bit to recalc cache groups on next mount */
if
(
ret
)
return
ret
;
ret
=
btrfs_search_slot
(
trans
,
extent_root
,
&
cache
->
key
,
path
,
0
,
1
);
if
(
ret
<
0
)
goto
fail
;
BUG_ON
(
ret
);
bi
=
btrfs_item_ptr
(
btrfs_buffer_leaf
(
path
->
nodes
[
0
]),
path
->
slots
[
0
],
struct
btrfs_block_group_item
);
memcpy
(
bi
,
&
cache
->
item
,
sizeof
(
*
bi
));
mark_buffer_dirty
(
path
->
nodes
[
0
]);
btrfs_release_path
(
extent_root
,
path
);
fail:
finish_current_insert
(
trans
,
extent_root
);
pending_ret
=
del_pending_extents
(
trans
,
extent_root
);
if
(
ret
)
...
...
@@ -543,6 +595,7 @@ static int write_dirty_block_radix(struct btrfs_trans_handle *trans,
int
werr
=
0
;
int
i
;
struct
btrfs_path
*
path
;
unsigned
long
off
=
0
;
path
=
btrfs_alloc_path
();
if
(
!
path
)
...
...
@@ -550,18 +603,28 @@ static int write_dirty_block_radix(struct btrfs_trans_handle *trans,
while
(
1
)
{
ret
=
radix_tree_gang_lookup_tag
(
radix
,
(
void
**
)
cache
,
0
,
ARRAY_SIZE
(
cache
),
off
,
ARRAY_SIZE
(
cache
),
BTRFS_BLOCK_GROUP_DIRTY
);
if
(
!
ret
)
break
;
for
(
i
=
0
;
i
<
ret
;
i
++
)
{
radix_tree_tag_clear
(
radix
,
cache
[
i
]
->
key
.
objectid
+
cache
[
i
]
->
key
.
offset
-
1
,
BTRFS_BLOCK_GROUP_DIRTY
);
err
=
write_one_cache_group
(
trans
,
root
,
path
,
cache
[
i
]);
if
(
err
)
/*
* if we fail to write the cache group, we want
* to keep it marked dirty in hopes that a later
* write will work
*/
if
(
err
)
{
werr
=
err
;
off
=
cache
[
i
]
->
key
.
objectid
+
cache
[
i
]
->
key
.
offset
;
continue
;
}
radix_tree_tag_clear
(
radix
,
cache
[
i
]
->
key
.
objectid
+
cache
[
i
]
->
key
.
offset
-
1
,
BTRFS_BLOCK_GROUP_DIRTY
);
}
}
btrfs_free_path
(
path
);
...
...
@@ -801,14 +864,20 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_set_key_type
(
&
key
,
BTRFS_EXTENT_ITEM_KEY
);
key
.
offset
=
num_blocks
;
find_free_extent
(
trans
,
root
,
0
,
0
,
(
u64
)
-
1
,
0
,
&
ins
,
0
);
path
=
btrfs_alloc_path
();
BUG_ON
(
!
path
);
if
(
!
path
)
return
-
ENOMEM
;
ret
=
btrfs_search_slot
(
trans
,
extent_root
,
&
key
,
path
,
-
1
,
1
);
ret
=
find_free_extent
(
trans
,
root
,
0
,
0
,
(
u64
)
-
1
,
0
,
&
ins
,
0
);
if
(
ret
)
{
BUG
();
btrfs_free_path
(
path
);
return
ret
;
}
ret
=
btrfs_search_slot
(
trans
,
extent_root
,
&
key
,
path
,
-
1
,
1
);
if
(
ret
<
0
)
return
ret
;
BUG_ON
(
ret
);
ei
=
btrfs_item_ptr
(
btrfs_buffer_leaf
(
path
->
nodes
[
0
]),
path
->
slots
[
0
],
struct
btrfs_extent_item
);
BUG_ON
(
ei
->
refs
==
0
);
...
...
@@ -827,8 +896,9 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_set_super_blocks_used
(
info
->
disk_super
,
super_blocks_used
-
num_blocks
);
ret
=
btrfs_del_item
(
trans
,
extent_root
,
path
);
if
(
ret
)
BUG
();
if
(
ret
)
{
return
ret
;
}
ret
=
update_block_group
(
trans
,
root
,
blocknr
,
num_blocks
,
0
,
mark_free
,
0
);
BUG_ON
(
ret
);
...
...
@@ -1075,7 +1145,6 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
path
->
slots
[
0
]
++
;
cond_resched
();
}
// FIXME -ENOSPC
check_pending:
/* we have to make sure we didn't find an extent that has already
* been allocated by the map tree or the original allocation
...
...
@@ -1246,6 +1315,14 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
ret
=
find_free_extent
(
trans
,
root
,
num_blocks
,
search_start
,
search_end
,
hint_block
,
ins
,
data
);
if
(
ret
)
{
if
(
search_start
==
0
)
return
ret
;
search_end
=
search_start
-
1
;
search_start
=
0
;
hint_block
=
search_start
;
ret
=
find_free_extent
(
trans
,
root
,
num_blocks
,
search_start
,
search_end
,
hint_block
,
ins
,
data
);
if
(
ret
)
return
ret
;
}
...
...
@@ -1271,6 +1348,15 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
search_end
,
hint_block
,
&
prealloc_key
,
0
);
if
(
ret
)
{
if
(
search_start
==
0
)
return
ret
;
search_end
=
search_start
-
1
;
search_start
=
0
;
hint_block
=
search_start
;
ret
=
find_free_extent
(
trans
,
root
,
0
,
search_start
,
search_end
,
hint_block
,
&
prealloc_key
,
0
);
if
(
ret
)
return
ret
;
}
}
...
...
@@ -1309,11 +1395,14 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
ret
=
btrfs_alloc_extent
(
trans
,
root
,
root
->
root_key
.
objectid
,
1
,
hint
,
(
unsigned
long
)
-
1
,
&
ins
,
0
);
if
(
ret
)
{
BUG
(
);
return
NULL
;
BUG
_ON
(
ret
>
0
);
return
ERR_PTR
(
ret
)
;
}
BUG_ON
(
ret
);
buf
=
btrfs_find_create_tree_block
(
root
,
ins
.
objectid
);
if
(
!
buf
)
{
btrfs_free_extent
(
trans
,
root
,
ins
.
objectid
,
1
,
0
);
return
ERR_PTR
(
-
ENOMEM
);
}
set_buffer_uptodate
(
buf
);
set_buffer_checked
(
buf
);
set_radix_bit
(
&
trans
->
transaction
->
dirty_pages
,
buf
->
b_page
->
index
);
...
...
fs/btrfs/file-item.c
View file @
54aa1f4d
...
...
@@ -45,6 +45,8 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
ret
=
btrfs_insert_empty_item
(
trans
,
root
,
path
,
&
file_key
,
sizeof
(
*
item
));
if
(
ret
<
0
)
goto
out
;
BUG_ON
(
ret
);
item
=
btrfs_item_ptr
(
btrfs_buffer_leaf
(
path
->
nodes
[
0
]),
path
->
slots
[
0
],
struct
btrfs_file_extent_item
);
...
...
@@ -55,10 +57,9 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
btrfs_set_file_extent_generation
(
item
,
trans
->
transid
);
btrfs_set_file_extent_type
(
item
,
BTRFS_FILE_EXTENT_REG
);
btrfs_mark_buffer_dirty
(
path
->
nodes
[
0
]);
btrfs_release_path
(
root
,
path
);
out:
btrfs_free_path
(
path
);
return
0
;
return
ret
;
}
struct
btrfs_csum_item
*
btrfs_lookup_csum
(
struct
btrfs_trans_handle
*
trans
,
...
...
@@ -213,6 +214,8 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
csum_offset
=
0
;
ret
=
btrfs_insert_empty_item
(
trans
,
root
,
path
,
&
file_key
,
BTRFS_CRC32_SIZE
);
if
(
ret
<
0
)
goto
fail
;
if
(
ret
!=
0
)
{
WARN_ON
(
1
);
goto
fail
;
...
...
@@ -261,40 +264,3 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
return
ret
;
}
int
btrfs_csum_verify_file_block
(
struct
btrfs_root
*
root
,
u64
objectid
,
u64
offset
,
char
*
data
,
size_t
len
)
{
int
ret
;
struct
btrfs_key
file_key
;
struct
btrfs_path
*
path
;
struct
btrfs_csum_item
*
item
;
char
result
[
BTRFS_CRC32_SIZE
];
path
=
btrfs_alloc_path
();
BUG_ON
(
!
path
);
file_key
.
objectid
=
objectid
;
file_key
.
offset
=
offset
;
file_key
.
flags
=
0
;
btrfs_set_key_type
(
&
file_key
,
BTRFS_CSUM_ITEM_KEY
);
mutex_lock
(
&
root
->
fs_info
->
fs_mutex
);
item
=
btrfs_lookup_csum
(
NULL
,
root
,
path
,
objectid
,
offset
,
0
);
if
(
IS_ERR
(
item
))
{
ret
=
PTR_ERR
(
item
);
/* a csum that isn't present is a preallocated region. */
if
(
ret
==
-
ENOENT
||
ret
==
-
EFBIG
)
ret
=
-
ENOENT
;
goto
fail
;
}
ret
=
btrfs_csum_data
(
root
,
data
,
len
,
result
);
WARN_ON
(
ret
);
if
(
memcmp
(
result
,
&
item
->
csum
,
BTRFS_CRC32_SIZE
))
ret
=
1
;
fail:
btrfs_release_path
(
root
,
path
);
btrfs_free_path
(
path
);
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
return
ret
;
}
fs/btrfs/file.c
View file @
54aa1f4d
...
...
@@ -81,54 +81,40 @@ static void btrfs_drop_pages(struct page **pages, size_t num_pages)
}
}
static
int
dirty_and_release_pages
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
struct
file
*
file
,
struct
page
**
pages
,
size_t
num_pages
,
loff_t
pos
,
size_t
write_bytes
)
static
int
insert_inline_extent
(
struct
btrfs_root
*
root
,
struct
inode
*
inode
,
u64
offset
,
ssize_t
size
,
struct
buffer_head
*
bh
)
{
int
i
;
int
offset
;
int
err
=
0
;
int
ret
;
int
this_write
;
struct
inode
*
inode
=
file
->
f_path
.
dentry
->
d_inode
;
struct
buffer_head
*
bh
;
struct
btrfs_file_extent_item
*
ei
;
for
(
i
=
0
;
i
<
num_pages
;
i
++
)
{
offset
=
pos
&
(
PAGE_CACHE_SIZE
-
1
);
this_write
=
min
((
size_t
)
PAGE_CACHE_SIZE
-
offset
,
write_bytes
);
/* FIXME, one block at a time */
bh
=
page_buffers
(
pages
[
i
]);
if
(
buffer_mapped
(
bh
)
&&
bh
->
b_blocknr
==
0
)
{
struct
btrfs_key
key
;
struct
btrfs_path
*
path
;
char
*
ptr
,
*
kaddr
;
struct
btrfs_trans_handle
*
trans
;
struct
btrfs_file_extent_item
*
ei
;
u32
datasize
;
int
err
=
0
;
int
ret
;
path
=
btrfs_alloc_path
();
if
(
!
path
)
return
-
ENOMEM
;
mutex_lock
(
&
root
->
fs_info
->
fs_mutex
);
trans
=
btrfs_start_transaction
(
root
,
1
);
btrfs_set_trans_block_group
(
trans
,
inode
);
/* create an inline extent, and copy the data in */
path
=
btrfs_alloc_path
();
BUG_ON
(
!
path
);
key
.
objectid
=
inode
->
i_ino
;
key
.
offset
=
pages
[
i
]
->
index
<<
PAGE_CACHE_SHIFT
;
key
.
offset
=
offset
;
key
.
flags
=
0
;
btrfs_set_key_type
(
&
key
,
BTRFS_EXTENT_DATA_KEY
);
BUG_ON
(
write_bytes
>=
PAGE_CACHE_SIZE
);
datasize
=
offset
+
btrfs_file_extent_calc_inline_size
(
write_bytes
);
BUG_ON
(
size
>=
PAGE_CACHE_SIZE
);
datasize
=
btrfs_file_extent_calc_inline_size
(
size
);
ret
=
btrfs_insert_empty_item
(
trans
,
root
,
path
,
&
key
,
datasize
);
BUG_ON
(
ret
);
if
(
ret
)
{
err
=
ret
;
goto
fail
;
}
ei
=
btrfs_item_ptr
(
btrfs_buffer_leaf
(
path
->
nodes
[
0
]),
path
->
slots
[
0
],
struct
btrfs_file_extent_item
);
btrfs_set_file_extent_generation
(
ei
,
trans
->
transid
);
...
...
@@ -139,14 +125,49 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
kaddr
=
kmap_atomic
(
bh
->
b_page
,
KM_USER0
);
btrfs_memcpy
(
root
,
path
->
nodes
[
0
]
->
b_data
,
ptr
,
kaddr
+
bh_offset
(
bh
),
offset
+
write_bytes
);
size
);
kunmap_atomic
(
kaddr
,
KM_USER0
);
mark_buffer_dirty
(
path
->
nodes
[
0
]);
fail:
btrfs_free_path
(
path
);
ret
=
btrfs_end_transaction
(
trans
,
root
);
BUG_ON
(
ret
);
if
(
ret
&&
!
err
)
err
=
ret
;
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
return
err
;
}
static
int
dirty_and_release_pages
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
struct
file
*
file
,
struct
page
**
pages
,
size_t
num_pages
,
loff_t
pos
,
size_t
write_bytes
)
{
int
i
;
int
offset
;
int
err
=
0
;
int
ret
;
int
this_write
;
struct
inode
*
inode
=
file
->
f_path
.
dentry
->
d_inode
;
struct
buffer_head
*
bh
;
for
(
i
=
0
;
i
<
num_pages
;
i
++
)
{
offset
=
pos
&
(
PAGE_CACHE_SIZE
-
1
);
this_write
=
min
((
size_t
)
PAGE_CACHE_SIZE
-
offset
,
write_bytes
);
/* FIXME, one block at a time */
bh
=
page_buffers
(
pages
[
i
]);
if
(
buffer_mapped
(
bh
)
&&
bh
->
b_blocknr
==
0
)
{
ret
=
insert_inline_extent
(
root
,
inode
,
pages
[
i
]
->
index
<<
PAGE_CACHE_SHIFT
,
offset
+
this_write
,
bh
);
if
(
ret
)
{
err
=
ret
;
goto
failed
;
}
}
ret
=
btrfs_commit_write
(
file
,
pages
[
i
],
offset
,
...
...
@@ -321,6 +342,7 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
btrfs_file_extent_disk_blocknr
(
extent
);
}
ret
=
btrfs_del_item
(
trans
,
root
,
path
);
/* TODO update progress marker and return */
BUG_ON
(
ret
);
btrfs_release_path
(
root
,
path
);
extent
=
NULL
;
...
...
@@ -452,7 +474,8 @@ static int prepare_pages(struct btrfs_root *root,
err
=
btrfs_drop_extents
(
trans
,
root
,
inode
,
start_pos
,
(
pos
+
write_bytes
+
root
->
blocksize
-
1
)
&
~
((
u64
)
root
->
blocksize
-
1
),
&
hint_block
);
BUG_ON
(
err
);
if
(
err
)
goto
failed_release
;
}
/* insert any holes we need to create */
...
...
@@ -469,7 +492,8 @@ static int prepare_pages(struct btrfs_root *root,
last_pos_in_file
,
0
,
0
,
hole_size
);
}
BUG_ON
(
err
);
if
(
err
)
goto
failed_release
;
}
/*
...
...
@@ -481,11 +505,13 @@ static int prepare_pages(struct btrfs_root *root,
err
=
btrfs_alloc_extent
(
trans
,
root
,
inode
->
i_ino
,
num_blocks
,
hint_block
,
(
u64
)
-
1
,
&
ins
,
1
);
BUG_ON
(
err
);
if
(
err
)
goto
failed_truncate
;
err
=
btrfs_insert_file_extent
(
trans
,
root
,
inode
->
i_ino
,
start_pos
,
ins
.
objectid
,
ins
.
offset
,
ins
.
offset
);
BUG_ON
(
err
);
if
(
err
)
goto
failed_truncate
;
}
else
{
ins
.
offset
=
0
;
ins
.
objectid
=
0
;
...
...
@@ -618,16 +644,21 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
ret
=
prepare_pages
(
root
,
file
,
pages
,
num_pages
,
pos
,
first_index
,
last_index
,
write_bytes
);
BUG_ON
(
ret
);
if
(
ret
)
goto
out
;
ret
=
btrfs_copy_from_user
(
pos
,
num_pages
,
write_bytes
,
pages
,
buf
);
BUG_ON
(
ret
);
if
(
ret
)
{
btrfs_drop_pages
(
pages
,
num_pages
);
goto
out
;
}
ret
=
dirty_and_release_pages
(
NULL
,
root
,
file
,
pages
,
num_pages
,
pos
,
write_bytes
);
BUG_ON
(
ret
);
btrfs_drop_pages
(
pages
,
num_pages
);
if
(
ret
)
goto
out
;
buf
+=
write_bytes
;
count
-=
write_bytes
;
...
...
fs/btrfs/inode.c
View file @
54aa1f4d
...
...
@@ -212,7 +212,11 @@ static int btrfs_unlink_trans(struct btrfs_trans_handle *trans,
struct
btrfs_dir_item
*
di
;
path
=
btrfs_alloc_path
();
BUG_ON
(
!
path
);
if
(
!
path
)
{
ret
=
-
ENOMEM
;
goto
err
;
}
di
=
btrfs_lookup_dir_item
(
trans
,
root
,
path
,
dir
->
i_ino
,
name
,
name_len
,
-
1
);
if
(
IS_ERR
(
di
))
{
...
...
@@ -225,7 +229,8 @@ static int btrfs_unlink_trans(struct btrfs_trans_handle *trans,
}
objectid
=
btrfs_disk_key_objectid
(
&
di
->
location
);
ret
=
btrfs_delete_one_dir_name
(
trans
,
root
,
path
,
di
);
BUG_ON
(
ret
);
if
(
ret
)
goto
err
;
btrfs_release_path
(
root
,
path
);
di
=
btrfs_lookup_dir_index_item
(
trans
,
root
,
path
,
dir
->
i_ino
,
...
...
@@ -239,7 +244,6 @@ static int btrfs_unlink_trans(struct btrfs_trans_handle *trans,
goto
err
;
}
ret
=
btrfs_delete_one_dir_name
(
trans
,
root
,
path
,
di
);
BUG_ON
(
ret
);
dentry
->
d_inode
->
i_ctime
=
dir
->
i_ctime
;
err:
...
...
@@ -248,7 +252,7 @@ static int btrfs_unlink_trans(struct btrfs_trans_handle *trans,
dir
->
i_size
-=
name_len
*
2
;
btrfs_update_inode
(
trans
,
root
,
dir
);
drop_nlink
(
dentry
->
d_inode
);
btrfs_update_inode
(
trans
,
root
,
dentry
->
d_inode
);
ret
=
btrfs_update_inode
(
trans
,
root
,
dentry
->
d_inode
);
dir
->
i_sb
->
s_dirt
=
1
;
}
return
ret
;
...
...
@@ -359,9 +363,10 @@ static int btrfs_free_inode(struct btrfs_trans_handle *trans,
BUG_ON
(
!
path
);
ret
=
btrfs_lookup_inode
(
trans
,
root
,
path
,
&
BTRFS_I
(
inode
)
->
location
,
-
1
);
BUG_ON
(
ret
);
if
(
ret
>
0
)
ret
=
-
ENOENT
;
if
(
!
ret
)
ret
=
btrfs_del_item
(
trans
,
root
,
path
);
BUG_ON
(
ret
);
btrfs_free_path
(
path
);
return
ret
;
}
...
...
@@ -516,7 +521,8 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
}
if
(
del_item
)
{
ret
=
btrfs_del_item
(
trans
,
root
,
path
);
BUG_ON
(
ret
);
if
(
ret
)
goto
error
;
}
else
{
break
;
}
...
...
@@ -577,19 +583,22 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
page
->
index
<<
PAGE_CACHE_SHIFT
,
(
page
->
index
+
1
)
<<
PAGE_CACHE_SHIFT
,
&
alloc_hint
);
BUG_ON
(
ret
);
if
(
ret
)
goto
out
;
ret
=
btrfs_alloc_extent
(
trans
,
root
,
inode
->
i_ino
,
1
,
alloc_hint
,
(
u64
)
-
1
,
&
ins
,
1
);
BUG_ON
(
ret
);
if
(
ret
)
goto
out
;
ret
=
btrfs_insert_file_extent
(
trans
,
root
,
inode
->
i_ino
,
page
->
index
<<
PAGE_CACHE_SHIFT
,
ins
.
objectid
,
1
,
1
);
BUG_ON
(
ret
);
if
(
ret
)
goto
out
;
SetPageChecked
(
page
);
kaddr
=
kmap
(
page
);
memset
(
kaddr
+
offset
,
0
,
PAGE_CACHE_SIZE
-
offset
);
flush_dcache_page
(
page
);
btrfs_csum_file_block
(
trans
,
root
,
inode
->
i_ino
,
ret
=
btrfs_csum_file_block
(
trans
,
root
,
inode
->
i_ino
,
page
->
index
<<
PAGE_CACHE_SHIFT
,
kaddr
,
PAGE_CACHE_SIZE
);
kunmap
(
page
);
...
...
@@ -633,9 +642,10 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
btrfs_set_trans_block_group
(
trans
,
inode
);
err
=
btrfs_insert_file_extent
(
trans
,
root
,
inode
->
i_ino
,
pos
,
0
,
0
,
hole_size
);
BUG_ON
(
err
);
btrfs_end_transaction
(
trans
,
root
);
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
if
(
err
)
return
err
;
}
out:
err
=
inode_setattr
(
inode
,
attr
);
...
...
@@ -657,12 +667,20 @@ void btrfs_delete_inode(struct inode *inode)
trans
=
btrfs_start_transaction
(
root
,
1
);
btrfs_set_trans_block_group
(
trans
,
inode
);
ret
=
btrfs_truncate_in_trans
(
trans
,
root
,
inode
);
BUG_ON
(
ret
);
btrfs_free_inode
(
trans
,
root
,
inode
);
if
(
ret
)
goto
no_delete_lock
;
ret
=
btrfs_free_inode
(
trans
,
root
,
inode
);
if
(
ret
)
goto
no_delete_lock
;
btrfs_end_transaction
(
trans
,
root
);
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
btrfs_btree_balance_dirty
(
root
);
return
;
no_delete_lock:
btrfs_end_transaction
(
trans
,
root
);
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
btrfs_btree_balance_dirty
(
root
);
no_delete:
clear_inode
(
inode
);
}
...
...
@@ -946,7 +964,7 @@ int btrfs_write_inode(struct inode *inode, int wait)
}
/*
* This is somewhat expense, updating the tree every time the
* This is somewhat expens
iv
e, updating the tree every time the
* inode changes. But, it is most likely to find the inode in cache.
* FIXME, needs more benchmarking...there are no reasons other than performance
* to keep or drop this code.
...
...
@@ -1002,8 +1020,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
btrfs_set_key_type
(
location
,
BTRFS_INODE_ITEM_KEY
);
ret
=
btrfs_insert_inode
(
trans
,
root
,
objectid
,
&
inode_item
);
BUG_ON
(
ret
);
if
(
ret
)
return
ERR_PTR
(
ret
);
insert_inode_hash
(
inode
);
return
inode
;
}
...
...
@@ -1121,7 +1139,9 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
drop_inode
=
1
;
dir
->
i_sb
->
s_dirt
=
1
;
btrfs_update_inode_block_group
(
trans
,
dir
);
btrfs_update_inode
(
trans
,
root
,
inode
);
err
=
btrfs_update_inode
(
trans
,
root
,
inode
);
if
(
err
)
drop_inode
=
1
;
btrfs_end_transaction
(
trans
,
root
);
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
...
...
@@ -1349,17 +1369,26 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock,
ret
=
btrfs_alloc_extent
(
trans
,
root
,
inode
->
i_ino
,
1
,
alloc_hint
,
(
u64
)
-
1
,
&
ins
,
1
);
BUG_ON
(
ret
);
if
(
ret
)
{
err
=
ret
;
goto
out
;
}
ret
=
btrfs_insert_file_extent
(
trans
,
root
,
inode
->
i_ino
,
iblock
<<
inode
->
i_blkbits
,
ins
.
objectid
,
ins
.
offset
,
ins
.
offset
);
BUG_ON
(
ret
);
if
(
ret
)
{
err
=
ret
;
goto
out
;
}
btrfs_map_bh_to_logical
(
root
,
result
,
ins
.
objectid
);
}
out:
if
(
trans
)
err
=
btrfs_end_transaction
(
trans
,
root
);
if
(
trans
)
{
ret
=
btrfs_end_transaction
(
trans
,
root
);
if
(
!
err
)
err
=
ret
;
}
btrfs_free_path
(
path
);
return
err
;
}
...
...
@@ -1375,7 +1404,7 @@ int btrfs_get_block(struct inode *inode, sector_t iblock,
return
err
;
}
int
btrfs_get_block_csum
(
struct
inode
*
inode
,
sector_t
iblock
,
static
int
btrfs_get_block_csum
(
struct
inode
*
inode
,
sector_t
iblock
,
struct
buffer_head
*
result
,
int
create
)
{
int
ret
;
...
...
@@ -1397,7 +1426,7 @@ int btrfs_get_block_csum(struct inode *inode, sector_t iblock,
/* a csum that isn't present is a preallocated region. */
if
(
ret
==
-
ENOENT
||
ret
==
-
EFBIG
)
ret
=
0
;
result
->
b_private
=
0
;
result
->
b_private
=
NULL
;
goto
out
;
}
memcpy
((
char
*
)
&
result
->
b_private
,
&
item
->
csum
,
BTRFS_CRC32_SIZE
);
...
...
@@ -1736,11 +1765,10 @@ static int __btrfs_write_full_page(struct inode *inode, struct page *page,
trans
=
btrfs_start_transaction
(
root
,
1
);
btrfs_set_trans_block_group
(
trans
,
inode
);
kaddr
=
kmap
(
page
);
ret
=
btrfs_csum_file_block
(
trans
,
root
,
inode
->
i_ino
,
btrfs_csum_file_block
(
trans
,
root
,
inode
->
i_ino
,
off
,
kaddr
+
bh_offset
(
bh
),
bh
->
b_size
);
kunmap
(
page
);
BUG_ON
(
ret
);
ret
=
btrfs_end_transaction
(
trans
,
root
);
BUG_ON
(
ret
);
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
...
...
@@ -1930,7 +1958,6 @@ static void btrfs_truncate(struct inode *inode)
/* FIXME, add redo link to tree so we don't leak on crash */
ret
=
btrfs_truncate_in_trans
(
trans
,
root
,
inode
);
BUG_ON
(
ret
);
btrfs_update_inode
(
trans
,
root
,
inode
);
ret
=
btrfs_end_transaction
(
trans
,
root
);
BUG_ON
(
ret
);
...
...
@@ -1970,6 +1997,7 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
struct
inode
*
inode
;
struct
inode
*
dir
;
int
ret
;
int
err
;
u64
objectid
;
u64
new_dirid
=
BTRFS_FIRST_FREE_OBJECTID
;
...
...
@@ -1978,8 +2006,8 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
BUG_ON
(
!
trans
);
subvol
=
btrfs_alloc_free_block
(
trans
,
root
,
0
);
if
(
subvol
==
NULL
)
return
-
ENOSPC
;
if
(
IS_ERR
(
subvol
)
)
return
PTR_ERR
(
subvol
)
;
leaf
=
btrfs_buffer_leaf
(
subvol
);
btrfs_set_header_nritems
(
&
leaf
->
header
,
0
);
btrfs_set_header_level
(
&
leaf
->
header
,
0
);
...
...
@@ -2005,7 +2033,8 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
ret
=
btrfs_find_free_objectid
(
trans
,
root
->
fs_info
->
tree_root
,
0
,
&
objectid
);
BUG_ON
(
ret
);
if
(
ret
)
goto
fail
;
btrfs_set_root_dirid
(
&
root_item
,
new_dirid
);
...
...
@@ -2015,7 +2044,8 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
btrfs_set_key_type
(
&
key
,
BTRFS_ROOT_ITEM_KEY
);
ret
=
btrfs_insert_root
(
trans
,
root
->
fs_info
->
tree_root
,
&
key
,
&
root_item
);
BUG_ON
(
ret
);
if
(
ret
)
goto
fail
;
/*
* insert the directory item
...
...
@@ -2025,10 +2055,12 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
ret
=
btrfs_insert_dir_item
(
trans
,
root
->
fs_info
->
tree_root
,
name
,
namelen
,
dir
->
i_ino
,
&
key
,
BTRFS_FT_DIR
);
BUG_ON
(
ret
);
if
(
ret
)
goto
fail
;
ret
=
btrfs_commit_transaction
(
trans
,
root
);
BUG_ON
(
ret
);
if
(
ret
)
goto
fail_commit
;
new_root
=
btrfs_read_fs_root
(
root
->
fs_info
,
&
key
);
BUG_ON
(
!
new_root
);
...
...
@@ -2038,24 +2070,29 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
inode
=
btrfs_new_inode
(
trans
,
new_root
,
new_dirid
,
BTRFS_I
(
dir
)
->
block_group
,
S_IFDIR
|
0700
);
if
(
IS_ERR
(
inode
))
goto
fail
;
inode
->
i_op
=
&
btrfs_dir_inode_operations
;
inode
->
i_fop
=
&
btrfs_dir_file_operations
;
new_root
->
inode
=
inode
;
ret
=
btrfs_make_empty_dir
(
trans
,
new_root
,
new_dirid
,
new_dirid
);
BUG_ON
(
ret
);
if
(
ret
)
goto
fail
;
inode
->
i_nlink
=
1
;
inode
->
i_size
=
6
;
ret
=
btrfs_update_inode
(
trans
,
new_root
,
inode
);
BUG_ON
(
ret
);
ret
=
btrfs_commit_transaction
(
trans
,
new_root
);
BUG_ON
(
ret
);
if
(
ret
)
goto
fail
;
fail:
err
=
btrfs_commit_transaction
(
trans
,
root
);
if
(
err
&&
!
ret
)
ret
=
err
;
fail_commit:
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
btrfs_btree_balance_dirty
(
root
);
return
0
;
return
ret
;
}
static
int
create_snapshot
(
struct
btrfs_root
*
root
,
char
*
name
,
int
namelen
)
...
...
@@ -2064,6 +2101,7 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
struct
btrfs_key
key
;
struct
btrfs_root_item
new_root_item
;
int
ret
;
int
err
;
u64
objectid
;
if
(
!
root
->
ref_cows
)
...
...
@@ -2074,11 +2112,13 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
BUG_ON
(
!
trans
);
ret
=
btrfs_update_inode
(
trans
,
root
,
root
->
inode
);
BUG_ON
(
ret
);
if
(
ret
)
goto
fail
;
ret
=
btrfs_find_free_objectid
(
trans
,
root
->
fs_info
->
tree_root
,
0
,
&
objectid
);
BUG_ON
(
ret
);
if
(
ret
)
goto
fail
;
memcpy
(
&
new_root_item
,
&
root
->
root_item
,
sizeof
(
new_root_item
));
...
...
@@ -2091,7 +2131,8 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
ret
=
btrfs_insert_root
(
trans
,
root
->
fs_info
->
tree_root
,
&
key
,
&
new_root_item
);
BUG_ON
(
ret
);
if
(
ret
)
goto
fail
;
/*
* insert the directory item
...
...
@@ -2102,16 +2143,20 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
root
->
fs_info
->
sb
->
s_root
->
d_inode
->
i_ino
,
&
key
,
BTRFS_FT_DIR
);
BUG_ON
(
ret
);
if
(
ret
)
goto
fail
;
ret
=
btrfs_inc_root_ref
(
trans
,
root
);
BUG_ON
(
ret
);
if
(
ret
)
goto
fail
;
ret
=
btrfs_commit_transaction
(
trans
,
root
);
BUG_ON
(
ret
);
fail:
err
=
btrfs_commit_transaction
(
trans
,
root
);
if
(
err
&&
!
ret
)
ret
=
err
;
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
btrfs_btree_balance_dirty
(
root
);
return
0
;
return
ret
;
}
int
btrfs_ioctl
(
struct
inode
*
inode
,
struct
file
*
filp
,
unsigned
int
...
...
@@ -2148,12 +2193,13 @@ int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int
btrfs_free_path
(
path
);
if
(
di
&&
!
IS_ERR
(
di
))
return
-
EEXIST
;
if
(
IS_ERR
(
di
))
return
PTR_ERR
(
di
);
if
(
root
==
root
->
fs_info
->
tree_root
)
ret
=
create_subvol
(
root
,
vol_args
.
name
,
namelen
);
else
ret
=
create_snapshot
(
root
,
vol_args
.
name
,
namelen
);
WARN_ON
(
ret
);
break
;
default:
return
-
ENOTTY
;
...
...
@@ -2316,7 +2362,6 @@ static int btrfs_rename(struct inode * old_dir, struct dentry *old_dentry,
old_parent_oid
=
btrfs_disk_key_objectid
(
&
di
->
location
);
ret
=
btrfs_del_item
(
trans
,
root
,
path
);
if
(
ret
)
{
ret
=
-
EIO
;
goto
out_fail
;
}
btrfs_release_path
(
root
,
path
);
...
...
@@ -2335,7 +2380,6 @@ static int btrfs_rename(struct inode * old_dir, struct dentry *old_dentry,
}
ret
=
btrfs_del_item
(
trans
,
root
,
path
);
if
(
ret
)
{
ret
=
-
EIO
;
goto
out_fail
;
}
btrfs_release_path
(
root
,
path
);
...
...
@@ -2361,7 +2405,9 @@ static int btrfs_rename(struct inode * old_dir, struct dentry *old_dentry,
clear_nlink
(
new_inode
);
else
drop_nlink
(
new_inode
);
btrfs_update_inode
(
trans
,
root
,
new_inode
);
ret
=
btrfs_update_inode
(
trans
,
root
,
new_inode
);
if
(
ret
)
goto
out_fail
;
}
ret
=
btrfs_add_link
(
trans
,
new_dentry
,
old_inode
);
if
(
ret
)
...
...
@@ -2433,7 +2479,10 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
datasize
=
btrfs_file_extent_calc_inline_size
(
name_len
);
err
=
btrfs_insert_empty_item
(
trans
,
root
,
path
,
&
key
,
datasize
);
BUG_ON
(
err
);
if
(
err
)
{
drop_inode
=
1
;
goto
out_unlock
;
}
ei
=
btrfs_item_ptr
(
btrfs_buffer_leaf
(
path
->
nodes
[
0
]),
path
->
slots
[
0
],
struct
btrfs_file_extent_item
);
btrfs_set_file_extent_generation
(
ei
,
trans
->
transid
);
...
...
@@ -2447,13 +2496,13 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
inode
->
i_op
=
&
btrfs_symlink_inode_operations
;
inode
->
i_mapping
->
a_ops
=
&
btrfs_symlink_aops
;
inode
->
i_size
=
name_len
-
1
;
btrfs_update_inode
(
trans
,
root
,
inode
);
err
=
0
;
err
=
btrfs_update_inode
(
trans
,
root
,
inode
);
if
(
err
)
drop_inode
=
1
;
out_unlock:
btrfs_end_transaction
(
trans
,
root
);
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
if
(
drop_inode
)
{
inode_dec_link_count
(
inode
);
iput
(
inode
);
...
...
fs/btrfs/root-tree.c
View file @
54aa1f4d
...
...
@@ -90,7 +90,6 @@ int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root
{
int
ret
;
ret
=
btrfs_insert_item
(
trans
,
root
,
key
,
item
,
sizeof
(
*
item
));
BUG_ON
(
ret
);
return
ret
;
}
...
...
fs/btrfs/super.c
View file @
54aa1f4d
...
...
@@ -125,9 +125,8 @@ static int btrfs_sync_fs(struct super_block *sb, int wait)
trans
=
btrfs_start_transaction
(
root
,
1
);
ret
=
btrfs_commit_transaction
(
trans
,
root
);
sb
->
s_dirt
=
0
;
BUG_ON
(
ret
);
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
return
0
;
return
ret
;
}
static
void
btrfs_write_super
(
struct
super_block
*
sb
)
...
...
fs/btrfs/transaction.c
View file @
54aa1f4d
...
...
@@ -219,7 +219,8 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans,
struct
btrfs_root
*
root
;
int
i
;
int
ret
;
int
err
;
int
err
=
0
;
while
(
1
)
{
ret
=
radix_tree_gang_lookup_tag
(
radix
,
(
void
**
)
gang
,
0
,
ARRAY_SIZE
(
gang
),
...
...
@@ -251,11 +252,12 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans,
err
=
btrfs_insert_root
(
trans
,
root
->
fs_info
->
tree_root
,
&
root
->
root_key
,
&
root
->
root_item
);
BUG_ON
(
err
);
if
(
err
)
break
;
list_add
(
&
dirty
->
list
,
list
);
}
}
return
0
;
return
err
;
}
static
int
drop_dirty_roots
(
struct
btrfs_root
*
tree_root
,
...
...
@@ -263,7 +265,7 @@ static int drop_dirty_roots(struct btrfs_root *tree_root,
{
struct
dirty_root
*
dirty
;
struct
btrfs_trans_handle
*
trans
;
int
ret
;
int
ret
=
0
;
while
(
!
list_empty
(
list
))
{
mutex_lock
(
&
tree_root
->
fs_info
->
fs_mutex
);
dirty
=
list_entry
(
list
->
next
,
struct
dirty_root
,
list
);
...
...
@@ -274,14 +276,15 @@ static int drop_dirty_roots(struct btrfs_root *tree_root,
BUG_ON
(
ret
);
ret
=
btrfs_del_root
(
trans
,
tree_root
,
&
dirty
->
snap_key
);
BUG_ON
(
ret
);
if
(
ret
)
break
;
ret
=
btrfs_end_transaction
(
trans
,
tree_root
);
BUG_ON
(
ret
);
kfree
(
dirty
);
mutex_unlock
(
&
tree_root
->
fs_info
->
fs_mutex
);
btrfs_btree_balance_dirty
(
tree_root
);
}
return
0
;
return
ret
;
}
int
btrfs_commit_transaction
(
struct
btrfs_trans_handle
*
trans
,
...
...
@@ -321,9 +324,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
}
finish_wait
(
&
trans
->
transaction
->
writer_wait
,
&
wait
);
WARN_ON
(
cur_trans
!=
trans
->
transaction
);
add_dirty_roots
(
trans
,
&
root
->
fs_info
->
fs_roots_radix
,
&
dirty_fs_roots
);
ret
=
add_dirty_roots
(
trans
,
&
root
->
fs_info
->
fs_roots_radix
,
&
dirty_fs_roots
);
BUG_ON
(
ret
);
ret
=
btrfs_commit_tree_roots
(
trans
,
root
);
BUG_ON
(
ret
);
cur_trans
=
root
->
fs_info
->
running_transaction
;
root
->
fs_info
->
running_transaction
=
NULL
;
if
(
cur_trans
->
list
.
prev
!=
&
root
->
fs_info
->
trans_list
)
{
...
...
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