Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
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 @@ again:
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 @@ next:
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 @@ insert:
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 @@ next_slot:
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 @@ err:
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 @@ not_found:
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