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
0f7d52f4
Commit
0f7d52f4
authored
Apr 09, 2007
by
Chris Mason
Committed by
David Woodhouse
Apr 09, 2007
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Btrfs: groundwork for subvolume and snapshot roots
Signed-off-by:
Chris Mason
<
chris.mason@oracle.com
>
parent
d6e4a428
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
282 additions
and
99 deletions
+282
-99
fs/btrfs/bit-radix.c
fs/btrfs/bit-radix.c
+1
-1
fs/btrfs/ctree.h
fs/btrfs/ctree.h
+17
-3
fs/btrfs/disk-io.c
fs/btrfs/disk-io.c
+137
-41
fs/btrfs/disk-io.h
fs/btrfs/disk-io.h
+2
-0
fs/btrfs/super.c
fs/btrfs/super.c
+22
-17
fs/btrfs/transaction.c
fs/btrfs/transaction.c
+103
-37
No files found.
fs/btrfs/bit-radix.c
View file @
0f7d52f4
...
...
@@ -86,7 +86,7 @@ int find_first_radix_bit(struct radix_tree_root *radix, unsigned long *retbits,
int
i
;
int
total_found
=
0
;
ret
=
radix_tree_gang_lookup
(
radix
,
(
void
*
)
&
gang
,
0
,
ARRAY_SIZE
(
gang
));
ret
=
radix_tree_gang_lookup
(
radix
,
(
void
*
*
)
gang
,
0
,
ARRAY_SIZE
(
gang
));
for
(
i
=
0
;
i
<
ret
&&
nr
>
0
;
i
++
)
{
found
=
0
;
bits
=
gang
[
i
];
...
...
fs/btrfs/ctree.h
View file @
0f7d52f4
...
...
@@ -232,12 +232,12 @@ struct btrfs_inode_map_item {
struct
crypto_hash
;
struct
btrfs_fs_info
{
struct
btrfs_root
*
fs_root
;
struct
btrfs_root
*
extent_root
;
struct
btrfs_root
*
tree_root
;
struct
btrfs_root
*
inode_root
;
struct
btrfs_key
current_insert
;
struct
btrfs_key
last_insert
;
struct
radix_tree_root
fs_roots_radix
;
struct
radix_tree_root
pending_del_radix
;
struct
radix_tree_root
pinned_radix
;
u64
last_inode_alloc
;
...
...
@@ -266,6 +266,9 @@ struct btrfs_root {
struct
btrfs_root_item
root_item
;
struct
btrfs_key
root_key
;
struct
btrfs_fs_info
*
fs_info
;
struct
inode
*
inode
;
u64
objectid
;
u64
last_trans
;
u32
blocksize
;
int
ref_cows
;
u32
type
;
...
...
@@ -595,7 +598,7 @@ static inline u32 btrfs_key_overflow(struct btrfs_key *key)
static
inline
void
btrfs_set_key_overflow
(
struct
btrfs_key
*
key
,
u32
over
)
{
BUG_ON
(
over
>
BTRFS_KEY_OVERFLOW_MAX
);
BUG_ON
(
over
>
=
BTRFS_KEY_OVERFLOW_MAX
);
over
=
over
<<
BTRFS_KEY_OVERFLOW_SHIFT
;
key
->
flags
=
(
key
->
flags
&
~
((
u64
)
BTRFS_KEY_OVERFLOW_MASK
))
|
over
;
}
...
...
@@ -634,7 +637,7 @@ static inline void btrfs_set_disK_key_overflow(struct btrfs_disk_key *key,
u32
over
)
{
u32
flags
=
btrfs_disk_key_flags
(
key
);
BUG_ON
(
over
>
BTRFS_KEY_OVERFLOW_MAX
);
BUG_ON
(
over
>
=
BTRFS_KEY_OVERFLOW_MAX
);
over
=
over
<<
BTRFS_KEY_OVERFLOW_SHIFT
;
flags
=
(
flags
&
~
((
u64
)
BTRFS_KEY_OVERFLOW_MASK
))
|
over
;
btrfs_set_disk_key_flags
(
key
,
flags
);
...
...
@@ -748,6 +751,17 @@ static inline void btrfs_set_super_blocknr(struct btrfs_super_block *s, u64 val)
s
->
blocknr
=
cpu_to_le64
(
val
);
}
static
inline
u64
btrfs_super_generation
(
struct
btrfs_super_block
*
s
)
{
return
le64_to_cpu
(
s
->
generation
);
}
static
inline
void
btrfs_set_super_generation
(
struct
btrfs_super_block
*
s
,
u64
val
)
{
s
->
generation
=
cpu_to_le64
(
val
);
}
static
inline
u64
btrfs_super_root
(
struct
btrfs_super_block
*
s
)
{
return
le64_to_cpu
(
s
->
root
);
...
...
fs/btrfs/disk-io.c
View file @
0f7d52f4
...
...
@@ -4,9 +4,11 @@
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <linux/swap.h>
#include <linux/radix-tree.h>
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
#include "btrfs_inode.h"
static
int
check_tree_block
(
struct
btrfs_root
*
root
,
struct
buffer_head
*
buf
)
{
...
...
@@ -180,7 +182,7 @@ static int csum_tree_block(struct btrfs_root *root, struct buffer_head *bh,
static
int
btree_writepage
(
struct
page
*
page
,
struct
writeback_control
*
wbc
)
{
struct
buffer_head
*
bh
;
struct
btrfs_root
*
root
=
btrfs_sb
(
page
->
mapping
->
host
->
i_sb
)
;
struct
btrfs_root
*
root
=
BTRFS_I
(
page
->
mapping
->
host
)
->
root
;
struct
buffer_head
*
head
;
if
(
!
page_has_buffers
(
page
))
{
create_empty_buffers
(
page
,
root
->
fs_info
->
sb
->
s_blocksize
,
...
...
@@ -259,10 +261,13 @@ static int __setup_root(int blocksize,
u64
objectid
)
{
root
->
node
=
NULL
;
root
->
inode
=
NULL
;
root
->
commit_root
=
NULL
;
root
->
blocksize
=
blocksize
;
root
->
ref_cows
=
0
;
root
->
fs_info
=
fs_info
;
root
->
objectid
=
objectid
;
root
->
last_trans
=
0
;
memset
(
&
root
->
root_key
,
0
,
sizeof
(
root
->
root_key
));
memset
(
&
root
->
root_item
,
0
,
sizeof
(
root
->
root_item
));
return
0
;
...
...
@@ -287,10 +292,78 @@ static int find_and_setup_root(int blocksize,
return
0
;
}
struct
btrfs_root
*
btrfs_read_fs_root
(
struct
btrfs_fs_info
*
fs_info
,
struct
btrfs_key
*
location
)
{
struct
btrfs_root
*
root
;
struct
btrfs_root
*
tree_root
=
fs_info
->
tree_root
;
struct
btrfs_path
*
path
;
struct
btrfs_leaf
*
l
;
int
ret
=
0
;
printk
(
"read_fs_root looking for %Lu %Lu %u
\n
"
,
location
->
objectid
,
location
->
offset
,
location
->
flags
);
root
=
kmalloc
(
sizeof
(
*
root
),
GFP_NOFS
);
if
(
!
root
)
{
printk
(
"failed1
\n
"
);
return
ERR_PTR
(
-
ENOMEM
);
}
if
(
location
->
offset
==
(
u64
)
-
1
)
{
ret
=
find_and_setup_root
(
fs_info
->
sb
->
s_blocksize
,
fs_info
->
tree_root
,
fs_info
,
location
->
objectid
,
root
);
if
(
ret
)
{
printk
(
"failed2
\n
"
);
kfree
(
root
);
return
ERR_PTR
(
ret
);
}
goto
insert
;
}
__setup_root
(
fs_info
->
sb
->
s_blocksize
,
root
,
fs_info
,
location
->
objectid
);
path
=
btrfs_alloc_path
();
BUG_ON
(
!
path
);
ret
=
btrfs_search_slot
(
NULL
,
tree_root
,
location
,
path
,
0
,
0
);
if
(
ret
!=
0
)
{
printk
(
"internal search_slot gives us %d
\n
"
,
ret
);
if
(
ret
>
0
)
ret
=
-
ENOENT
;
goto
out
;
}
l
=
btrfs_buffer_leaf
(
path
->
nodes
[
0
]);
memcpy
(
&
root
->
root_item
,
btrfs_item_ptr
(
l
,
path
->
slots
[
0
],
struct
btrfs_root_item
),
sizeof
(
root
->
root_item
));
memcpy
(
&
root
->
root_key
,
location
,
sizeof
(
*
location
));
ret
=
0
;
out:
btrfs_release_path
(
root
,
path
);
btrfs_free_path
(
path
);
if
(
ret
)
{
kfree
(
root
);
return
ERR_PTR
(
ret
);
}
root
->
node
=
read_tree_block
(
root
,
btrfs_root_blocknr
(
&
root
->
root_item
));
BUG_ON
(
!
root
->
node
);
insert:
printk
(
"inserting %p
\n
"
,
root
);
root
->
ref_cows
=
1
;
ret
=
radix_tree_insert
(
&
fs_info
->
fs_roots_radix
,
(
unsigned
long
)
root
,
root
);
if
(
ret
)
{
printk
(
"radix_tree_insert gives us %d
\n
"
,
ret
);
brelse
(
root
->
node
);
kfree
(
root
);
return
ERR_PTR
(
ret
);
}
printk
(
"all worked
\n
"
);
return
root
;
}
struct
btrfs_root
*
open_ctree
(
struct
super_block
*
sb
)
{
struct
btrfs_root
*
root
=
kmalloc
(
sizeof
(
struct
btrfs_root
),
GFP_NOFS
);
struct
btrfs_root
*
extent_root
=
kmalloc
(
sizeof
(
struct
btrfs_root
),
GFP_NOFS
);
struct
btrfs_root
*
tree_root
=
kmalloc
(
sizeof
(
struct
btrfs_root
),
...
...
@@ -304,9 +377,9 @@ struct btrfs_root *open_ctree(struct super_block *sb)
init_bit_radix
(
&
fs_info
->
pinned_radix
);
init_bit_radix
(
&
fs_info
->
pending_del_radix
);
INIT_RADIX_TREE
(
&
fs_info
->
fs_roots_radix
,
GFP_NOFS
);
sb_set_blocksize
(
sb
,
4096
);
fs_info
->
running_transaction
=
NULL
;
fs_info
->
fs_root
=
root
;
fs_info
->
tree_root
=
tree_root
;
fs_info
->
extent_root
=
extent_root
;
fs_info
->
inode_root
=
inode_root
;
...
...
@@ -318,6 +391,9 @@ struct btrfs_root *open_ctree(struct super_block *sb)
fs_info
->
btree_inode
->
i_nlink
=
1
;
fs_info
->
btree_inode
->
i_size
=
sb
->
s_bdev
->
bd_inode
->
i_size
;
fs_info
->
btree_inode
->
i_mapping
->
a_ops
=
&
btree_aops
;
BTRFS_I
(
fs_info
->
btree_inode
)
->
root
=
tree_root
;
memset
(
&
BTRFS_I
(
fs_info
->
btree_inode
)
->
location
,
0
,
sizeof
(
struct
btrfs_key
));
insert_inode_hash
(
fs_info
->
btree_inode
);
mapping_set_gfp_mask
(
fs_info
->
btree_inode
->
i_mapping
,
GFP_NOFS
);
fs_info
->
hash_tfm
=
crypto_alloc_hash
(
"sha256"
,
0
,
CRYPTO_ALG_ASYNC
);
...
...
@@ -337,13 +413,12 @@ struct btrfs_root *open_ctree(struct super_block *sb)
BTRFS_SUPER_INFO_OFFSET
/
sb
->
s_blocksize
);
if
(
!
fs_info
->
sb_buffer
)
{
if
(
!
fs_info
->
sb_buffer
)
return
NULL
;
}
disk_super
=
(
struct
btrfs_super_block
*
)
fs_info
->
sb_buffer
->
b_data
;
if
(
!
btrfs_super_root
(
disk_super
))
{
if
(
!
btrfs_super_root
(
disk_super
))
return
NULL
;
}
fs_info
->
disk_super
=
disk_super
;
tree_root
->
node
=
read_tree_block
(
tree_root
,
btrfs_super_root
(
disk_super
));
...
...
@@ -358,14 +433,8 @@ struct btrfs_root *open_ctree(struct super_block *sb)
BTRFS_INODE_MAP_OBJECTID
,
inode_root
);
BUG_ON
(
ret
);
ret
=
find_and_setup_root
(
sb
->
s_blocksize
,
tree_root
,
fs_info
,
BTRFS_FS_TREE_OBJECTID
,
root
);
BUG_ON
(
ret
);
root
->
commit_root
=
root
->
node
;
get_bh
(
root
->
node
);
root
->
ref_cows
=
1
;
root
->
fs_info
->
generation
=
root
->
root_key
.
offset
+
1
;
ret
=
btrfs_find_highest_inode
(
root
,
&
root
->
fs_info
->
last_inode_alloc
);
fs_info
->
generation
=
btrfs_super_generation
(
disk_super
)
+
1
;
ret
=
btrfs_find_highest_inode
(
tree_root
,
&
fs_info
->
last_inode_alloc
);
if
(
ret
==
0
)
fs_info
->
highest_inode
=
fs_info
->
last_inode_alloc
;
memset
(
&
fs_info
->
kobj
,
0
,
sizeof
(
fs_info
->
kobj
));
...
...
@@ -373,7 +442,7 @@ struct btrfs_root *open_ctree(struct super_block *sb)
kobject_set_name
(
&
fs_info
->
kobj
,
"%s"
,
sb
->
s_id
);
kobject_register
(
&
fs_info
->
kobj
);
mutex_unlock
(
&
fs_info
->
fs_mutex
);
return
root
;
return
tree_
root
;
}
int
write_ctree_super
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
...
...
@@ -398,12 +467,42 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
return
0
;
}
int
del_fs_roots
(
struct
btrfs_fs_info
*
fs_info
)
{
int
ret
;
struct
btrfs_root
*
gang
[
8
];
int
i
;
while
(
1
)
{
ret
=
radix_tree_gang_lookup
(
&
fs_info
->
fs_roots_radix
,
(
void
**
)
gang
,
0
,
ARRAY_SIZE
(
gang
));
if
(
!
ret
)
break
;
for
(
i
=
0
;
i
<
ret
;
i
++
)
{
radix_tree_delete
(
&
fs_info
->
fs_roots_radix
,
(
unsigned
long
)
gang
[
i
]);
if
(
gang
[
i
]
->
inode
)
iput
(
gang
[
i
]
->
inode
);
else
printk
(
"no inode for root %p
\n
"
,
gang
[
i
]);
if
(
gang
[
i
]
->
node
)
brelse
(
gang
[
i
]
->
node
);
if
(
gang
[
i
]
->
commit_root
)
brelse
(
gang
[
i
]
->
commit_root
);
kfree
(
gang
[
i
]);
}
}
return
0
;
}
int
close_ctree
(
struct
btrfs_root
*
root
)
{
int
ret
;
struct
btrfs_trans_handle
*
trans
;
struct
btrfs_fs_info
*
fs_info
=
root
->
fs_info
;
mutex_lock
(
&
root
->
fs_info
->
fs_mutex
);
mutex_lock
(
&
fs_info
->
fs_mutex
);
trans
=
btrfs_start_transaction
(
root
,
1
);
btrfs_commit_transaction
(
trans
,
root
);
/* run commit again to drop the original snapshot */
...
...
@@ -412,29 +511,26 @@ int close_ctree(struct btrfs_root *root)
ret
=
btrfs_write_and_wait_transaction
(
NULL
,
root
);
BUG_ON
(
ret
);
write_ctree_super
(
NULL
,
root
);
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
if
(
root
->
node
)
btrfs_block_release
(
root
,
root
->
node
);
if
(
root
->
fs_info
->
extent_root
->
node
)
btrfs_block_release
(
root
->
fs_info
->
extent_root
,
root
->
fs_info
->
extent_root
->
node
);
if
(
root
->
fs_info
->
inode_root
->
node
)
btrfs_block_release
(
root
->
fs_info
->
inode_root
,
root
->
fs_info
->
inode_root
->
node
);
if
(
root
->
fs_info
->
tree_root
->
node
)
btrfs_block_release
(
root
->
fs_info
->
tree_root
,
root
->
fs_info
->
tree_root
->
node
);
btrfs_block_release
(
root
,
root
->
commit_root
);
btrfs_block_release
(
root
,
root
->
fs_info
->
sb_buffer
);
crypto_free_hash
(
root
->
fs_info
->
hash_tfm
);
truncate_inode_pages
(
root
->
fs_info
->
btree_inode
->
i_mapping
,
0
);
iput
(
root
->
fs_info
->
btree_inode
);
kfree
(
root
->
fs_info
->
extent_root
);
kfree
(
root
->
fs_info
->
inode_root
);
kfree
(
root
->
fs_info
->
tree_root
);
kobject_unregister
(
&
root
->
fs_info
->
kobj
);
kfree
(
root
);
mutex_unlock
(
&
fs_info
->
fs_mutex
);
if
(
fs_info
->
extent_root
->
node
)
btrfs_block_release
(
fs_info
->
extent_root
,
fs_info
->
extent_root
->
node
);
if
(
fs_info
->
inode_root
->
node
)
btrfs_block_release
(
fs_info
->
inode_root
,
fs_info
->
inode_root
->
node
);
if
(
fs_info
->
tree_root
->
node
)
btrfs_block_release
(
fs_info
->
tree_root
,
fs_info
->
tree_root
->
node
);
btrfs_block_release
(
root
,
fs_info
->
sb_buffer
);
crypto_free_hash
(
fs_info
->
hash_tfm
);
truncate_inode_pages
(
fs_info
->
btree_inode
->
i_mapping
,
0
);
iput
(
fs_info
->
btree_inode
);
del_fs_roots
(
fs_info
);
kfree
(
fs_info
->
extent_root
);
kfree
(
fs_info
->
inode_root
);
kfree
(
fs_info
->
tree_root
);
kobject_unregister
(
&
fs_info
->
kobj
);
return
0
;
}
...
...
fs/btrfs/disk-io.h
View file @
0f7d52f4
...
...
@@ -39,4 +39,6 @@ int write_ctree_super(struct btrfs_trans_handle *trans,
struct
buffer_head
*
btrfs_find_tree_block
(
struct
btrfs_root
*
root
,
u64
blocknr
);
int
btrfs_csum_data
(
struct
btrfs_root
*
root
,
char
*
data
,
size_t
len
,
char
*
result
);
struct
btrfs_root
*
btrfs_read_fs_root
(
struct
btrfs_fs_info
*
fs_info
,
struct
btrfs_key
*
location
);
#endif
fs/btrfs/super.c
View file @
0f7d52f4
...
...
@@ -436,7 +436,6 @@ int fixup_tree_root_location(struct btrfs_root *root,
{
struct
btrfs_path
*
path
;
struct
btrfs_root_item
*
ri
;
int
ret
;
if
(
btrfs_key_type
(
location
)
!=
BTRFS_ROOT_ITEM_KEY
)
return
0
;
...
...
@@ -447,22 +446,19 @@ int fixup_tree_root_location(struct btrfs_root *root,
BUG_ON
(
!
path
);
mutex_lock
(
&
root
->
fs_info
->
fs_mutex
);
ret
=
btrfs_lookup_inode
(
NULL
,
root
,
path
,
location
,
0
);
if
(
ret
)
goto
out
;
ri
=
btrfs_item_ptr
(
btrfs_buffer_leaf
(
path
->
nodes
[
0
]),
path
->
slots
[
0
],
struct
btrfs_root_item
);
*
sub_root
=
btrfs_read_fs_root
(
root
->
fs_info
,
location
);
if
(
IS_ERR
(
*
sub_root
))
return
PTR_ERR
(
*
sub_root
);
ri
=
&
(
*
sub_root
)
->
root_item
;
location
->
objectid
=
btrfs_root_dirid
(
ri
);
location
->
flags
=
0
;
btrfs_set_key_type
(
location
,
BTRFS_INODE_ITEM_KEY
);
location
->
offset
=
0
;
/* FIXME properly select the root */
*
sub_root
=
root
->
fs_info
->
fs_root
;
out:
btrfs_free_path
(
path
);
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
return
ret
;
return
0
;
}
...
...
@@ -494,6 +490,15 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
if
(
!
inode
)
return
ERR_PTR
(
-
EACCES
);
if
(
inode
->
i_state
&
I_NEW
)
{
if
(
sub_root
!=
root
)
{
ret
=
radix_tree_insert
(
&
root
->
fs_info
->
fs_roots_radix
,
(
unsigned
long
)
sub_root
,
sub_root
);
printk
(
"adding new root for inode %lu
\n
"
,
inode
->
i_ino
);
igrab
(
inode
);
sub_root
->
inode
=
inode
;
}
BTRFS_I
(
inode
)
->
root
=
sub_root
;
memcpy
(
&
BTRFS_I
(
inode
)
->
location
,
&
location
,
sizeof
(
location
));
...
...
@@ -605,7 +610,7 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
struct
inode
*
inode
;
struct
dentry
*
root_dentry
;
struct
btrfs_super_block
*
disk_super
;
struct
btrfs_root
*
root
;
struct
btrfs_root
*
tree_
root
;
struct
btrfs_inode
*
bi
;
sb
->
s_maxbytes
=
MAX_LFS_FILESIZE
;
...
...
@@ -613,14 +618,14 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
sb
->
s_op
=
&
btrfs_super_ops
;
sb
->
s_time_gran
=
1
;
root
=
open_ctree
(
sb
);
tree_
root
=
open_ctree
(
sb
);
if
(
!
root
)
{
if
(
!
tree_
root
)
{
printk
(
"btrfs: open_ctree failed
\n
"
);
return
-
EIO
;
}
sb
->
s_fs_info
=
root
;
disk_super
=
root
->
fs_info
->
disk_super
;
sb
->
s_fs_info
=
tree_
root
;
disk_super
=
tree_
root
->
fs_info
->
disk_super
;
printk
(
"read in super total blocks %Lu root %Lu
\n
"
,
btrfs_super_total_blocks
(
disk_super
),
btrfs_super_root_dir
(
disk_super
));
...
...
@@ -630,7 +635,7 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
bi
->
location
.
objectid
=
inode
->
i_ino
;
bi
->
location
.
offset
=
0
;
bi
->
location
.
flags
=
0
;
bi
->
root
=
root
->
fs_info
->
tree_root
;
bi
->
root
=
tree_root
;
btrfs_set_key_type
(
&
bi
->
location
,
BTRFS_INODE_ITEM_KEY
);
if
(
!
inode
)
...
...
fs/btrfs/transaction.c
View file @
0f7d52f4
...
...
@@ -8,6 +8,8 @@ static int total_trans = 0;
extern
struct
kmem_cache
*
btrfs_trans_handle_cachep
;
extern
struct
kmem_cache
*
btrfs_transaction_cachep
;
#define BTRFS_ROOT_TRANS_TAG 0
#define TRANS_MAGIC 0xE1E10E
static
void
put_transaction
(
struct
btrfs_transaction
*
transaction
)
{
...
...
@@ -31,9 +33,10 @@ static int join_transaction(struct btrfs_root *root)
GFP_NOFS
);
total_trans
++
;
BUG_ON
(
!
cur_trans
);
root
->
fs_info
->
generation
++
;
root
->
fs_info
->
running_transaction
=
cur_trans
;
cur_trans
->
num_writers
=
0
;
cur_trans
->
transid
=
root
->
root_key
.
offset
+
1
;
cur_trans
->
transid
=
root
->
fs_info
->
generation
;
init_waitqueue_head
(
&
cur_trans
->
writer_wait
);
init_waitqueue_head
(
&
cur_trans
->
commit_wait
);
cur_trans
->
magic
=
TRANS_MAGIC
;
...
...
@@ -51,13 +54,22 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
struct
btrfs_trans_handle
*
h
=
kmem_cache_alloc
(
btrfs_trans_handle_cachep
,
GFP_NOFS
);
int
ret
;
u64
running_trans_id
;
/* FIXME, use the right root */
root
=
root
->
fs_info
->
fs_root
;
mutex_lock
(
&
root
->
fs_info
->
trans_mutex
);
ret
=
join_transaction
(
root
);
BUG_ON
(
ret
);
h
->
transid
=
root
->
fs_info
->
running_transaction
->
transid
;
running_trans_id
=
root
->
fs_info
->
running_transaction
->
transid
;
if
(
root
!=
root
->
fs_info
->
tree_root
&&
root
->
last_trans
<
running_trans_id
)
{
radix_tree_tag_set
(
&
root
->
fs_info
->
fs_roots_radix
,
(
unsigned
long
)
root
,
BTRFS_ROOT_TRANS_TAG
);
root
->
commit_root
=
root
->
node
;
get_bh
(
root
->
node
);
}
root
->
last_trans
=
running_trans_id
;
h
->
transid
=
running_trans_id
;
h
->
transaction
=
root
->
fs_info
->
running_transaction
;
h
->
blocks_reserved
=
num_blocks
;
h
->
blocks_used
=
0
;
...
...
@@ -72,9 +84,6 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans,
{
struct
btrfs_transaction
*
cur_trans
;
/* FIXME, use the right root */
root
=
root
->
fs_info
->
fs_root
;
WARN_ON
(
trans
->
magic
!=
TRANS_MAGIC
);
WARN_ON
(
trans
->
magic2
!=
TRANS_MAGIC
);
mutex_lock
(
&
root
->
fs_info
->
trans_mutex
);
...
...
@@ -145,17 +154,96 @@ static int wait_for_commit(struct btrfs_root *root,
return
0
;
}
struct
dirty_root
{
struct
list_head
list
;
struct
btrfs_key
snap_key
;
struct
buffer_head
*
commit_root
;
struct
btrfs_root
*
root
;
};
int
add_dirty_roots
(
struct
btrfs_trans_handle
*
trans
,
struct
radix_tree_root
*
radix
,
struct
list_head
*
list
)
{
struct
dirty_root
*
dirty
;
struct
btrfs_root
*
gang
[
8
];
struct
btrfs_root
*
root
;
int
i
;
int
ret
;
int
err
;
printk
(
"add dirty
\n
"
);
while
(
1
)
{
ret
=
radix_tree_gang_lookup_tag
(
radix
,
(
void
**
)
gang
,
0
,
ARRAY_SIZE
(
gang
),
BTRFS_ROOT_TRANS_TAG
);
if
(
ret
==
0
)
break
;
for
(
i
=
0
;
i
<
ret
;
i
++
)
{
root
=
gang
[
i
];
radix_tree_tag_clear
(
radix
,
(
unsigned
long
)
root
,
BTRFS_ROOT_TRANS_TAG
);
if
(
root
->
commit_root
==
root
->
node
)
{
WARN_ON
(
root
->
node
->
b_blocknr
!=
btrfs_root_blocknr
(
&
root
->
root_item
));
brelse
(
root
->
commit_root
);
root
->
commit_root
=
NULL
;
continue
;
}
dirty
=
kmalloc
(
sizeof
(
*
dirty
),
GFP_NOFS
);
BUG_ON
(
!
dirty
);
memcpy
(
&
dirty
->
snap_key
,
&
root
->
root_key
,
sizeof
(
root
->
root_key
));
dirty
->
commit_root
=
root
->
commit_root
;
root
->
commit_root
=
NULL
;
dirty
->
root
=
root
;
printk
(
"adding dirty root %Lu gen %Lu blocknr %Lu
\n
"
,
root
->
root_key
.
objectid
,
root
->
root_key
.
offset
,
dirty
->
commit_root
->
b_blocknr
);
root
->
root_key
.
offset
=
root
->
fs_info
->
generation
;
btrfs_set_root_blocknr
(
&
root
->
root_item
,
root
->
node
->
b_blocknr
);
err
=
btrfs_insert_root
(
trans
,
root
->
fs_info
->
tree_root
,
&
root
->
root_key
,
&
root
->
root_item
);
BUG_ON
(
err
);
list_add
(
&
dirty
->
list
,
list
);
}
}
printk
(
"add dirty done
\n
"
);
return
0
;
}
int
drop_dirty_roots
(
struct
btrfs_root
*
tree_root
,
struct
list_head
*
list
)
{
struct
dirty_root
*
dirty
;
struct
btrfs_trans_handle
*
trans
;
int
ret
;
while
(
!
list_empty
(
list
))
{
dirty
=
list_entry
(
list
->
next
,
struct
dirty_root
,
list
);
list_del_init
(
&
dirty
->
list
);
trans
=
btrfs_start_transaction
(
tree_root
,
1
);
printk
(
"drop snapshot root %p, commit_root blocknr %Lu generation %Lu
\n
"
,
dirty
->
root
,
dirty
->
commit_root
->
b_blocknr
,
dirty
->
snap_key
.
offset
);
ret
=
btrfs_drop_snapshot
(
trans
,
dirty
->
root
,
dirty
->
commit_root
);
BUG_ON
(
ret
);
printk
(
"del root objectid %Lu, offset %Lu
\n
"
,
dirty
->
snap_key
.
objectid
,
dirty
->
snap_key
.
offset
);
ret
=
btrfs_del_root
(
trans
,
tree_root
,
&
dirty
->
snap_key
);
BUG_ON
(
ret
);
ret
=
btrfs_end_transaction
(
trans
,
tree_root
);
BUG_ON
(
ret
);
kfree
(
dirty
);
}
return
0
;
}
int
btrfs_commit_transaction
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
)
{
int
ret
=
0
;
struct
buffer_head
*
snap
;
struct
btrfs_key
snap_key
;
struct
btrfs_transaction
*
cur_trans
;
struct
list_head
dirty_fs_roots
;
DEFINE_WAIT
(
wait
);
/* FIXME, use the right root */
root
=
root
->
fs_info
->
fs_root
;
INIT_LIST_HEAD
(
&
dirty_fs_roots
);
mutex_lock
(
&
root
->
fs_info
->
trans_mutex
);
if
(
trans
->
transaction
->
in_commit
)
{
...
...
@@ -184,22 +272,13 @@ printk("already in commit!, waiting\n");
}
finish_wait
(
&
trans
->
transaction
->
writer_wait
,
&
wait
);
WARN_ON
(
cur_trans
!=
trans
->
transaction
);
if
(
root
->
node
!=
root
->
commit_root
)
{
memcpy
(
&
snap_key
,
&
root
->
root_key
,
sizeof
(
snap_key
));
root
->
root_key
.
offset
++
;
}
if
(
btrfs_root_blocknr
(
&
root
->
root_item
)
!=
root
->
node
->
b_blocknr
)
{
btrfs_set_root_blocknr
(
&
root
->
root_item
,
root
->
node
->
b_blocknr
);
ret
=
btrfs_insert_root
(
trans
,
root
->
fs_info
->
tree_root
,
&
root
->
root_key
,
&
root
->
root_item
);
BUG_ON
(
ret
);
}
add_dirty_roots
(
trans
,
&
root
->
fs_info
->
fs_roots_radix
,
&
dirty_fs_roots
);
ret
=
btrfs_commit_tree_roots
(
trans
,
root
);
BUG_ON
(
ret
);
cur_trans
=
root
->
fs_info
->
running_transaction
;
root
->
fs_info
->
running_transaction
=
NULL
;
btrfs_set_super_generation
(
root
->
fs_info
->
disk_super
,
root
->
fs_info
->
generation
+
1
);
mutex_unlock
(
&
root
->
fs_info
->
trans_mutex
);
ret
=
btrfs_write_and_wait_transaction
(
trans
,
root
);
BUG_ON
(
ret
);
...
...
@@ -213,21 +292,8 @@ printk("already in commit!, waiting\n");
put_transaction
(
cur_trans
);
mutex_unlock
(
&
root
->
fs_info
->
trans_mutex
);
kmem_cache_free
(
btrfs_trans_handle_cachep
,
trans
);
if
(
root
->
node
!=
root
->
commit_root
)
{
trans
=
btrfs_start_transaction
(
root
,
1
);
snap
=
root
->
commit_root
;
root
->
commit_root
=
root
->
node
;
get_bh
(
root
->
node
);
ret
=
btrfs_drop_snapshot
(
trans
,
root
,
snap
);
BUG_ON
(
ret
);
ret
=
btrfs_del_root
(
trans
,
root
->
fs_info
->
tree_root
,
&
snap_key
);
BUG_ON
(
ret
);
root
->
fs_info
->
generation
=
root
->
root_key
.
offset
+
1
;
ret
=
btrfs_end_transaction
(
trans
,
root
);
BUG_ON
(
ret
);
}
drop_dirty_roots
(
root
->
fs_info
->
tree_root
,
&
dirty_fs_roots
);
return
ret
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment