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
2619ba1f
Commit
2619ba1f
authored
Apr 10, 2007
by
Chris Mason
Committed by
David Woodhouse
Apr 10, 2007
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Btrfs: subvolumes
Signed-off-by:
Chris Mason
<
chris.mason@oracle.com
>
parent
2932f3ec
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
182 additions
and
43 deletions
+182
-43
fs/btrfs/TODO
fs/btrfs/TODO
+1
-0
fs/btrfs/disk-io.c
fs/btrfs/disk-io.c
+24
-14
fs/btrfs/super.c
fs/btrfs/super.c
+152
-26
fs/btrfs/transaction.c
fs/btrfs/transaction.c
+5
-3
No files found.
fs/btrfs/TODO
View file @
2619ba1f
...
...
@@ -8,6 +8,7 @@
* Check compat and incompat flags on the inode
* Add virtual filesystems, mountable snapshots
* Get rid of struct ctree_path, limiting tree levels held at one time
* EEXIST for dirs instead of hash overflow
* Release
* Do real tree locking
* Add extent mirroring (backup copies of blocks)
...
...
fs/btrfs/disk-io.c
View file @
2619ba1f
...
...
@@ -301,6 +301,12 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
int
ret
=
0
;
printk
(
"read_fs_root looking for %Lu %Lu %u
\n
"
,
location
->
objectid
,
location
->
offset
,
location
->
flags
);
root
=
radix_tree_lookup
(
&
fs_info
->
fs_roots_radix
,
(
unsigned
long
)
location
->
objectid
);
if
(
root
)
{
printk
(
"found %p in cache
\n
"
,
root
);
return
root
;
}
root
=
kmalloc
(
sizeof
(
*
root
),
GFP_NOFS
);
if
(
!
root
)
{
printk
(
"failed1
\n
"
);
...
...
@@ -349,7 +355,8 @@ printk("internal search_slot gives us %d\n", ret);
insert:
printk
(
"inserting %p
\n
"
,
root
);
root
->
ref_cows
=
1
;
ret
=
radix_tree_insert
(
&
fs_info
->
fs_roots_radix
,
(
unsigned
long
)
root
,
ret
=
radix_tree_insert
(
&
fs_info
->
fs_roots_radix
,
(
unsigned
long
)
root
->
root_key
.
objectid
,
root
);
if
(
ret
)
{
printk
(
"radix_tree_insert gives us %d
\n
"
,
ret
);
...
...
@@ -460,6 +467,20 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root
return
0
;
}
static
int
free_fs_root
(
struct
btrfs_fs_info
*
fs_info
,
struct
btrfs_root
*
root
)
{
radix_tree_delete
(
&
fs_info
->
fs_roots_radix
,
(
unsigned
long
)
root
->
root_key
.
objectid
);
if
(
root
->
inode
)
iput
(
root
->
inode
);
if
(
root
->
node
)
brelse
(
root
->
node
);
if
(
root
->
commit_root
)
brelse
(
root
->
commit_root
);
kfree
(
root
);
return
0
;
}
int
del_fs_roots
(
struct
btrfs_fs_info
*
fs_info
)
{
int
ret
;
...
...
@@ -472,19 +493,8 @@ int del_fs_roots(struct btrfs_fs_info *fs_info)
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
]);
}
for
(
i
=
0
;
i
<
ret
;
i
++
)
free_fs_root
(
fs_info
,
gang
[
i
]);
}
return
0
;
}
...
...
fs/btrfs/super.c
View file @
2619ba1f
...
...
@@ -495,10 +495,6 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
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 root %p (found %p)
\n
"
,
inode
->
i_ino
,
sub_root
,
BTRFS_I
(
inode
)
->
root
);
igrab
(
inode
);
sub_root
->
inode
=
inode
;
...
...
@@ -723,22 +719,19 @@ static int btrfs_write_inode(struct inode *inode, int wait)
}
static
struct
inode
*
btrfs_new_inode
(
struct
btrfs_trans_handle
*
trans
,
struct
inode
*
dir
,
int
mode
)
struct
btrfs_root
*
root
,
u64
objectid
,
int
mode
)
{
struct
inode
*
inode
;
struct
btrfs_inode_item
inode_item
;
struct
btrfs_root
*
root
=
BTRFS_I
(
dir
)
->
root
;
struct
btrfs_key
*
location
;
int
ret
;
u64
objectid
;
inode
=
new_inode
(
dir
->
i_
sb
);
inode
=
new_inode
(
root
->
fs_info
->
sb
);
if
(
!
inode
)
return
ERR_PTR
(
-
ENOMEM
);
BTRFS_I
(
inode
)
->
root
=
BTRFS_I
(
dir
)
->
root
;
ret
=
btrfs_find_free_objectid
(
trans
,
root
,
dir
->
i_ino
,
&
objectid
);
BUG_ON
(
ret
);
BTRFS_I
(
inode
)
->
root
=
root
;
inode
->
i_uid
=
current
->
fsuid
;
inode
->
i_gid
=
current
->
fsgid
;
...
...
@@ -804,10 +797,18 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
struct
inode
*
inode
;
int
err
;
int
drop_inode
=
0
;
u64
objectid
;
mutex_lock
(
&
root
->
fs_info
->
fs_mutex
);
trans
=
btrfs_start_transaction
(
root
,
1
);
inode
=
btrfs_new_inode
(
trans
,
dir
,
mode
);
err
=
btrfs_find_free_objectid
(
trans
,
root
,
dir
->
i_ino
,
&
objectid
);
if
(
err
)
{
err
=
-
ENOSPC
;
goto
out_unlock
;
}
inode
=
btrfs_new_inode
(
trans
,
root
,
objectid
,
mode
);
err
=
PTR_ERR
(
inode
);
if
(
IS_ERR
(
inode
))
goto
out_unlock
;
...
...
@@ -833,9 +834,9 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
}
static
int
btrfs_make_empty_dir
(
struct
btrfs_trans_handle
*
trans
,
struct
inode
*
inode
,
struct
inode
*
dir
)
struct
btrfs_root
*
root
,
u64
objectid
,
u64
dirid
)
{
struct
btrfs_root
*
root
=
BTRFS_I
(
dir
)
->
root
;
int
ret
;
char
buf
[
2
];
struct
btrfs_key
key
;
...
...
@@ -843,22 +844,20 @@ static int btrfs_make_empty_dir(struct btrfs_trans_handle *trans,
buf
[
0
]
=
'.'
;
buf
[
1
]
=
'.'
;
key
.
objectid
=
inode
->
i_ino
;
key
.
objectid
=
objectid
;
key
.
offset
=
0
;
key
.
flags
=
0
;
btrfs_set_key_type
(
&
key
,
BTRFS_INODE_ITEM_KEY
);
ret
=
btrfs_insert_dir_item
(
trans
,
root
,
buf
,
1
,
inode
->
i_ino
,
ret
=
btrfs_insert_dir_item
(
trans
,
root
,
buf
,
1
,
objectid
,
&
key
,
1
);
if
(
ret
)
goto
error
;
key
.
objectid
=
dir
->
i_ino
;
ret
=
btrfs_insert_dir_item
(
trans
,
root
,
buf
,
2
,
inode
->
i_ino
,
key
.
objectid
=
dir
id
;
ret
=
btrfs_insert_dir_item
(
trans
,
root
,
buf
,
2
,
objectid
,
&
key
,
1
);
if
(
ret
)
goto
error
;
inode
->
i_size
=
6
;
ret
=
btrfs_update_inode
(
trans
,
root
,
inode
);
error:
return
ret
;
}
...
...
@@ -870,6 +869,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
struct
btrfs_root
*
root
=
BTRFS_I
(
dir
)
->
root
;
int
err
=
0
;
int
drop_on_err
=
0
;
u64
objectid
;
mutex_lock
(
&
root
->
fs_info
->
fs_mutex
);
trans
=
btrfs_start_transaction
(
root
,
1
);
...
...
@@ -877,7 +877,14 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
err
=
PTR_ERR
(
trans
);
goto
out_unlock
;
}
inode
=
btrfs_new_inode
(
trans
,
dir
,
S_IFDIR
|
mode
);
err
=
btrfs_find_free_objectid
(
trans
,
root
,
dir
->
i_ino
,
&
objectid
);
if
(
err
)
{
err
=
-
ENOSPC
;
goto
out_unlock
;
}
inode
=
btrfs_new_inode
(
trans
,
root
,
objectid
,
S_IFDIR
|
mode
);
if
(
IS_ERR
(
inode
))
{
err
=
PTR_ERR
(
inode
);
goto
out_fail
;
...
...
@@ -886,7 +893,12 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
inode
->
i_op
=
&
btrfs_dir_inode_operations
;
inode
->
i_fop
=
&
btrfs_dir_file_operations
;
err
=
btrfs_make_empty_dir
(
trans
,
inode
,
dir
);
err
=
btrfs_make_empty_dir
(
trans
,
root
,
inode
->
i_ino
,
dir
->
i_ino
);
if
(
err
)
goto
out_fail
;
inode
->
i_size
=
6
;
err
=
btrfs_update_inode
(
trans
,
root
,
inode
);
if
(
err
)
goto
out_fail
;
err
=
btrfs_add_link
(
trans
,
dentry
,
inode
);
...
...
@@ -1666,6 +1678,102 @@ static ssize_t btrfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
return
retval
;
}
static
int
create_subvol
(
struct
btrfs_root
*
root
,
char
*
name
,
int
namelen
)
{
struct
btrfs_trans_handle
*
trans
;
struct
btrfs_key
key
;
struct
btrfs_root_item
root_item
;
struct
btrfs_inode_item
*
inode_item
;
struct
buffer_head
*
subvol
;
struct
btrfs_leaf
*
leaf
;
struct
btrfs_root
*
new_root
;
struct
inode
*
inode
;
int
ret
;
u64
objectid
;
u64
new_dirid
=
BTRFS_FIRST_FREE_OBJECTID
;
mutex_lock
(
&
root
->
fs_info
->
fs_mutex
);
trans
=
btrfs_start_transaction
(
root
,
1
);
BUG_ON
(
!
trans
);
subvol
=
btrfs_alloc_free_block
(
trans
,
root
);
leaf
=
btrfs_buffer_leaf
(
subvol
);
btrfs_set_header_nritems
(
&
leaf
->
header
,
0
);
btrfs_set_header_level
(
&
leaf
->
header
,
0
);
btrfs_set_header_blocknr
(
&
leaf
->
header
,
subvol
->
b_blocknr
);
btrfs_set_header_generation
(
&
leaf
->
header
,
trans
->
transid
);
memcpy
(
leaf
->
header
.
fsid
,
root
->
fs_info
->
disk_super
->
fsid
,
sizeof
(
leaf
->
header
.
fsid
));
inode_item
=
&
root_item
.
inode
;
memset
(
inode_item
,
0
,
sizeof
(
*
inode_item
));
btrfs_set_inode_generation
(
inode_item
,
1
);
btrfs_set_inode_size
(
inode_item
,
3
);
btrfs_set_inode_nlink
(
inode_item
,
1
);
btrfs_set_inode_nblocks
(
inode_item
,
1
);
btrfs_set_inode_mode
(
inode_item
,
S_IFDIR
|
0755
);
btrfs_set_root_blocknr
(
&
root_item
,
subvol
->
b_blocknr
);
btrfs_set_root_refs
(
&
root_item
,
1
);
mark_buffer_dirty
(
subvol
);
brelse
(
subvol
);
subvol
=
NULL
;
ret
=
btrfs_find_free_objectid
(
trans
,
root
->
fs_info
->
tree_root
,
0
,
&
objectid
);
BUG_ON
(
ret
);
btrfs_set_root_dirid
(
&
root_item
,
new_dirid
);
key
.
objectid
=
objectid
;
key
.
offset
=
1
;
key
.
flags
=
0
;
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
);
/*
* insert the directory item
*/
key
.
offset
=
(
u64
)
-
1
;
ret
=
btrfs_insert_dir_item
(
trans
,
root
->
fs_info
->
tree_root
,
name
,
namelen
,
root
->
fs_info
->
sb
->
s_root
->
d_inode
->
i_ino
,
&
key
,
0
);
BUG_ON
(
ret
);
ret
=
btrfs_commit_transaction
(
trans
,
root
);
BUG_ON
(
ret
);
new_root
=
btrfs_read_fs_root
(
root
->
fs_info
,
&
key
);
BUG_ON
(
!
new_root
);
trans
=
btrfs_start_transaction
(
new_root
,
1
);
BUG_ON
(
!
trans
);
inode
=
btrfs_new_inode
(
trans
,
new_root
,
new_dirid
,
S_IFDIR
|
0700
);
inode
->
i_op
=
&
btrfs_dir_inode_operations
;
inode
->
i_fop
=
&
btrfs_dir_file_operations
;
ret
=
btrfs_make_empty_dir
(
trans
,
new_root
,
new_dirid
,
new_dirid
);
BUG_ON
(
ret
);
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
);
iput
(
inode
);
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
return
0
;
}
static
int
create_snapshot
(
struct
btrfs_root
*
root
,
char
*
name
,
int
namelen
)
{
struct
btrfs_trans_handle
*
trans
;
...
...
@@ -1674,6 +1782,9 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
int
ret
;
u64
objectid
;
if
(
!
root
->
ref_cows
)
return
-
EINVAL
;
mutex_lock
(
&
root
->
fs_info
->
fs_mutex
);
trans
=
btrfs_start_transaction
(
root
,
1
);
BUG_ON
(
!
trans
);
...
...
@@ -1685,7 +1796,6 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen)
0
,
&
objectid
);
BUG_ON
(
ret
);
memset
(
&
new_root_item
,
0
,
sizeof
(
new_root_item
));
memcpy
(
&
new_root_item
,
&
root
->
root_item
,
sizeof
(
new_root_item
));
...
...
@@ -1728,9 +1838,9 @@ static int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int
struct
btrfs_ioctl_vol_args
vol_args
;
int
ret
;
int
namelen
;
struct
btrfs_path
*
path
;
u64
root_dirid
;
if
(
!
root
->
ref_cows
)
return
-
EINVAL
;
switch
(
cmd
)
{
case
BTRFS_IOC_SNAP_CREATE
:
if
(
copy_from_user
(
&
vol_args
,
...
...
@@ -1740,6 +1850,22 @@ static int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int
namelen
=
strlen
(
vol_args
.
name
);
if
(
namelen
>
BTRFS_VOL_NAME_MAX
)
return
-
EINVAL
;
path
=
btrfs_alloc_path
();
if
(
!
path
)
return
-
ENOMEM
;
root_dirid
=
btrfs_root_dirid
(
&
root
->
fs_info
->
tree_root
->
root_item
);
mutex_lock
(
&
root
->
fs_info
->
fs_mutex
);
ret
=
btrfs_lookup_dir_item
(
NULL
,
root
->
fs_info
->
tree_root
,
path
,
root_dirid
,
vol_args
.
name
,
namelen
,
0
);
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
if
(
ret
==
0
)
return
-
EEXIST
;
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
;
...
...
fs/btrfs/transaction.c
View file @
2619ba1f
...
...
@@ -64,7 +64,8 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
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
);
(
unsigned
long
)
root
->
root_key
.
objectid
,
BTRFS_ROOT_TRANS_TAG
);
root
->
commit_root
=
root
->
node
;
get_bh
(
root
->
node
);
}
...
...
@@ -171,7 +172,8 @@ int add_dirty_roots(struct btrfs_trans_handle *trans,
break
;
for
(
i
=
0
;
i
<
ret
;
i
++
)
{
root
=
gang
[
i
];
radix_tree_tag_clear
(
radix
,
(
unsigned
long
)
root
,
radix_tree_tag_clear
(
radix
,
(
unsigned
long
)
root
->
root_key
.
objectid
,
BTRFS_ROOT_TRANS_TAG
);
if
(
root
->
commit_root
==
root
->
node
)
{
WARN_ON
(
root
->
node
->
b_blocknr
!=
...
...
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