Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
b18c6685
Commit
b18c6685
authored
Apr 17, 2007
by
Chris Mason
Committed by
David Woodhouse
Apr 17, 2007
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Btrfs: progress on file_write
Signed-off-by:
Chris Mason
<
chris.mason@oracle.com
>
parent
6567e837
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
394 additions
and
49 deletions
+394
-49
fs/btrfs/ctree.c
fs/btrfs/ctree.c
+57
-0
fs/btrfs/ctree.h
fs/btrfs/ctree.h
+16
-5
fs/btrfs/extent-tree.c
fs/btrfs/extent-tree.c
+11
-9
fs/btrfs/file-item.c
fs/btrfs/file-item.c
+41
-20
fs/btrfs/super.c
fs/btrfs/super.c
+269
-15
No files found.
fs/btrfs/ctree.c
View file @
b18c6685
...
...
@@ -1249,6 +1249,63 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
return
ret
;
}
int
btrfs_truncate_item
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
struct
btrfs_path
*
path
,
u32
new_size
)
{
int
ret
=
0
;
int
slot
;
int
slot_orig
;
struct
btrfs_leaf
*
leaf
;
struct
buffer_head
*
leaf_buf
;
u32
nritems
;
unsigned
int
data_end
;
unsigned
int
old_data_start
;
unsigned
int
old_size
;
unsigned
int
size_diff
;
int
i
;
slot_orig
=
path
->
slots
[
0
];
leaf_buf
=
path
->
nodes
[
0
];
leaf
=
btrfs_buffer_leaf
(
leaf_buf
);
nritems
=
btrfs_header_nritems
(
&
leaf
->
header
);
data_end
=
leaf_data_end
(
root
,
leaf
);
slot
=
path
->
slots
[
0
];
old_data_start
=
btrfs_item_offset
(
leaf
->
items
+
slot
);
old_size
=
btrfs_item_size
(
leaf
->
items
+
slot
);
BUG_ON
(
old_size
<=
new_size
);
size_diff
=
old_size
-
new_size
;
BUG_ON
(
slot
<
0
);
BUG_ON
(
slot
>=
nritems
);
/*
* item0..itemN ... dataN.offset..dataN.size .. data0.size
*/
/* first correct the data pointers */
for
(
i
=
slot
;
i
<
nritems
;
i
++
)
{
u32
ioff
=
btrfs_item_offset
(
leaf
->
items
+
i
);
btrfs_set_item_offset
(
leaf
->
items
+
i
,
ioff
+
size_diff
);
}
/* shift the data */
printk
(
"truncate item, new_size %u old_size %u, diff %u, bufp %p, dst, %p, num %u, old_data_start %u, data_end %u
\n
"
,
new_size
,
old_size
,
size_diff
,
leaf
,
btrfs_leaf_data
(
leaf
)
+
data_end
+
size_diff
,
old_data_start
-
data_end
,
old_data_start
,
data_end
);
btrfs_memmove
(
root
,
leaf
,
btrfs_leaf_data
(
leaf
)
+
data_end
+
size_diff
,
btrfs_leaf_data
(
leaf
)
+
data_end
,
old_data_start
+
new_size
-
data_end
);
btrfs_set_item_size
(
leaf
->
items
+
slot
,
new_size
);
btrfs_mark_buffer_dirty
(
leaf_buf
);
ret
=
0
;
if
(
btrfs_leaf_free_space
(
root
,
leaf
)
<
0
)
BUG
();
check_leaf
(
root
,
path
,
0
);
return
ret
;
}
int
btrfs_extend_item
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
struct
btrfs_path
*
path
,
u32
data_size
)
{
...
...
fs/btrfs/ctree.h
View file @
b18c6685
...
...
@@ -999,7 +999,7 @@ static inline void btrfs_mark_buffer_dirty(struct buffer_head *bh)
((type *)(btrfs_leaf_data(leaf) + \
btrfs_item_offset((leaf)->items + (slot))))
/* extent-
item
.c */
/* extent-
tree
.c */
int
btrfs_inc_root_ref
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
);
struct
buffer_head
*
btrfs_alloc_free_block
(
struct
btrfs_trans_handle
*
trans
,
...
...
@@ -1013,9 +1013,16 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
*
root
,
u64
blocknr
,
u64
num_blocks
,
int
pin
);
int
btrfs_finish_extent_commit
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
);
int
btrfs_inc_extent_ref
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
u64
blocknr
,
u64
num_blocks
);
/* ctree.c */
int
btrfs_extend_item
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
struct
btrfs_path
*
path
,
u32
data_size
);
int
btrfs_truncate_item
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
struct
btrfs_path
*
path
,
u32
new_size
);
int
btrfs_search_slot
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
struct
btrfs_key
*
key
,
struct
btrfs_path
*
p
,
int
ins_len
,
int
cow
);
...
...
@@ -1073,11 +1080,10 @@ int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root
struct
btrfs_key
*
location
,
int
mod
);
/* file-item.c */
int
btrfs_
alloc
_file_extent
(
struct
btrfs_trans_handle
*
trans
,
int
btrfs_
insert
_file_extent
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
u64
objectid
,
u64
offset
,
u64
num_blocks
,
u64
hint_block
,
u64
*
result
);
u64
objectid
,
u64
pos
,
u64
offset
,
u64
num_blocks
);
int
btrfs_lookup_file_extent
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
struct
btrfs_path
*
path
,
u64
objectid
,
...
...
@@ -1090,6 +1096,11 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
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
,
u64
objectid
,
u64
offset
,
int
cow
);
/* super.c */
extern
struct
subsystem
btrfs_subsys
;
...
...
fs/btrfs/extent-tree.c
View file @
b18c6685
...
...
@@ -12,8 +12,9 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
static
int
del_pending_extents
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
extent_root
);
static
int
inc_block_ref
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
u64
blocknr
,
u64
num_blocks
)
int
btrfs_inc_extent_ref
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
u64
blocknr
,
u64
num_blocks
)
{
struct
btrfs_path
*
path
;
int
ret
;
...
...
@@ -50,8 +51,9 @@ static int inc_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
return
0
;
}
static
int
lookup_block_ref
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
u64
blocknr
,
u64
num_blocks
,
u32
*
refs
)
static
int
lookup_extent_ref
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
u64
blocknr
,
u64
num_blocks
,
u32
*
refs
)
{
struct
btrfs_path
*
path
;
int
ret
;
...
...
@@ -80,7 +82,7 @@ static int lookup_block_ref(struct btrfs_trans_handle *trans, struct btrfs_root
int
btrfs_inc_root_ref
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
)
{
return
inc_block
_ref
(
trans
,
root
,
bh_blocknr
(
root
->
node
),
1
);
return
btrfs_inc_extent
_ref
(
trans
,
root
,
bh_blocknr
(
root
->
node
),
1
);
}
int
btrfs_inc_ref
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
...
...
@@ -107,13 +109,13 @@ int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
continue
;
fi
=
btrfs_item_ptr
(
buf_leaf
,
i
,
struct
btrfs_file_extent_item
);
ret
=
inc_block
_ref
(
trans
,
root
,
ret
=
btrfs_inc_extent
_ref
(
trans
,
root
,
btrfs_file_extent_disk_blocknr
(
fi
),
btrfs_file_extent_disk_num_blocks
(
fi
));
BUG_ON
(
ret
);
}
else
{
blocknr
=
btrfs_node_blockptr
(
buf_node
,
i
);
ret
=
inc_block
_ref
(
trans
,
root
,
blocknr
,
1
);
ret
=
btrfs_inc_extent
_ref
(
trans
,
root
,
blocknr
,
1
);
BUG_ON
(
ret
);
}
}
...
...
@@ -563,7 +565,7 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
WARN_ON
(
*
level
<
0
);
WARN_ON
(
*
level
>=
BTRFS_MAX_LEVEL
);
ret
=
lookup_
block
_ref
(
trans
,
root
,
bh_blocknr
(
path
->
nodes
[
*
level
]),
ret
=
lookup_
extent
_ref
(
trans
,
root
,
bh_blocknr
(
path
->
nodes
[
*
level
]),
1
,
&
refs
);
BUG_ON
(
ret
);
if
(
refs
>
1
)
...
...
@@ -587,7 +589,7 @@ static int walk_down_tree(struct btrfs_trans_handle *trans, struct btrfs_root
}
blocknr
=
btrfs_node_blockptr
(
btrfs_buffer_node
(
cur
),
path
->
slots
[
*
level
]);
ret
=
lookup_
block
_ref
(
trans
,
root
,
blocknr
,
1
,
&
refs
);
ret
=
lookup_
extent
_ref
(
trans
,
root
,
blocknr
,
1
,
&
refs
);
BUG_ON
(
ret
);
if
(
refs
!=
1
)
{
path
->
slots
[
*
level
]
++
;
...
...
fs/btrfs/file-item.c
View file @
b18c6685
...
...
@@ -6,13 +6,11 @@
#define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \
sizeof(struct btrfs_item)) / \
sizeof(struct btrfs_csum_item)) - 1))
int
btrfs_
alloc
_file_extent
(
struct
btrfs_trans_handle
*
trans
,
int
btrfs_
insert
_file_extent
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
u64
objectid
,
u64
offset
,
u64
num_blocks
,
u64
hint_block
,
u64
*
result
)
u64
objectid
,
u64
pos
,
u64
offset
,
u64
num_blocks
)
{
struct
btrfs_key
ins
;
int
ret
=
0
;
struct
btrfs_file_extent_item
*
item
;
struct
btrfs_key
file_key
;
...
...
@@ -21,11 +19,13 @@ int btrfs_alloc_file_extent(struct btrfs_trans_handle *trans,
path
=
btrfs_alloc_path
();
BUG_ON
(
!
path
);
btrfs_init_path
(
path
);
/*
ret = btrfs_alloc_extent(trans, root, num_blocks, hint_block,
(u64)-1, &ins);
*/
BUG_ON
(
ret
);
file_key
.
objectid
=
objectid
;
file_key
.
offset
=
offset
;
file_key
.
offset
=
pos
;
file_key
.
flags
=
0
;
btrfs_set_key_type
(
&
file_key
,
BTRFS_EXTENT_DATA_KEY
);
...
...
@@ -34,21 +34,22 @@ int btrfs_alloc_file_extent(struct btrfs_trans_handle *trans,
BUG_ON
(
ret
);
item
=
btrfs_item_ptr
(
btrfs_buffer_leaf
(
path
->
nodes
[
0
]),
path
->
slots
[
0
],
struct
btrfs_file_extent_item
);
btrfs_set_file_extent_disk_blocknr
(
item
,
ins
.
objectid
);
btrfs_set_file_extent_disk_num_blocks
(
item
,
ins
.
offset
);
btrfs_set_file_extent_disk_blocknr
(
item
,
offset
);
btrfs_set_file_extent_disk_num_blocks
(
item
,
num_blocks
);
btrfs_set_file_extent_offset
(
item
,
0
);
btrfs_set_file_extent_num_blocks
(
item
,
ins
.
offset
);
btrfs_set_file_extent_num_blocks
(
item
,
num_blocks
);
btrfs_set_file_extent_generation
(
item
,
trans
->
transid
);
btrfs_mark_buffer_dirty
(
path
->
nodes
[
0
]);
*
result
=
ins
.
objectid
;
btrfs_release_path
(
root
,
path
);
btrfs_free_path
(
path
);
return
0
;
}
static
struct
btrfs_csum_item
*
__lookup_csum_item
(
struct
btrfs_root
*
root
,
struct
btrfs_path
*
path
,
u64
objectid
,
u64
offset
)
struct
btrfs_csum_item
*
btrfs_lookup_csum
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
struct
btrfs_path
*
path
,
u64
objectid
,
u64
offset
,
int
cow
)
{
int
ret
;
struct
btrfs_key
file_key
;
...
...
@@ -61,19 +62,23 @@ static struct btrfs_csum_item *__lookup_csum_item(struct btrfs_root *root,
file_key
.
offset
=
offset
;
file_key
.
flags
=
0
;
btrfs_set_key_type
(
&
file_key
,
BTRFS_CSUM_ITEM_KEY
);
ret
=
btrfs_search_slot
(
NULL
,
root
,
&
file_key
,
path
,
0
,
0
);
printk
(
"__lookup for %Lu
\n
"
,
offset
);
ret
=
btrfs_search_slot
(
trans
,
root
,
&
file_key
,
path
,
0
,
cow
);
if
(
ret
<
0
)
goto
fail
;
leaf
=
btrfs_buffer_leaf
(
path
->
nodes
[
0
]);
if
(
ret
>
0
)
{
ret
=
1
;
if
(
path
->
slots
[
0
]
==
0
)
if
(
path
->
slots
[
0
]
==
0
)
{
printk
(
"fail1
\n
"
);
goto
fail
;
}
path
->
slots
[
0
]
--
;
btrfs_disk_key_to_cpu
(
&
found_key
,
&
leaf
->
items
[
path
->
slots
[
0
]].
key
);
if
(
btrfs_key_type
(
&
found_key
)
!=
BTRFS_CSUM_ITEM_KEY
||
found_key
.
objectid
!=
objectid
)
{
printk
(
"fail2 type %u %Lu %Lu
\n
"
,
btrfs_key_type
(
&
found_key
),
found_key
.
objectid
,
objectid
);
goto
fail
;
}
csum_offset
=
(
offset
-
found_key
.
offset
)
>>
...
...
@@ -81,6 +86,7 @@ static struct btrfs_csum_item *__lookup_csum_item(struct btrfs_root *root,
if
(
csum_offset
>=
btrfs_item_size
(
leaf
->
items
+
path
->
slots
[
0
])
/
sizeof
(
struct
btrfs_csum_item
))
{
printk
(
"fail3, csum offset %lu size %u
\n
"
,
csum_offset
,
btrfs_item_size
(
leaf
->
items
+
path
->
slots
[
0
])
/
sizeof
(
struct
btrfs_csum_item
));
goto
fail
;
}
}
...
...
@@ -89,7 +95,7 @@ static struct btrfs_csum_item *__lookup_csum_item(struct btrfs_root *root,
return
item
;
fail:
if
(
ret
>
0
)
ret
=
-
E
IO
;
ret
=
-
E
NOENT
;
return
ERR_PTR
(
ret
);
}
...
...
@@ -105,7 +111,7 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
int
cow
=
mod
!=
0
;
struct
btrfs_csum_item
*
csum_item
;
csum_item
=
__lookup_csum_item
(
root
,
path
,
objectid
,
offset
);
csum_item
=
btrfs_lookup_csum
(
trans
,
root
,
path
,
objectid
,
offset
,
0
);
if
(
IS_ERR
(
csum_item
))
return
PTR_ERR
(
csum_item
);
file_key
.
objectid
=
objectid
;
...
...
@@ -113,7 +119,9 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
file_key
.
flags
=
0
;
btrfs_set_key_type
(
&
file_key
,
BTRFS_EXTENT_DATA_KEY
);
btrfs_release_path
(
root
,
path
);
printk
(
"lookup file extent searches for %Lu
\n
"
,
file_key
.
offset
);
ret
=
btrfs_search_slot
(
trans
,
root
,
&
file_key
,
path
,
ins_len
,
cow
);
printk
(
"ret is %d
\n
"
,
ret
);
return
ret
;
}
...
...
@@ -134,17 +142,23 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
path
=
btrfs_alloc_path
();
BUG_ON
(
!
path
);
btrfs_init_path
(
path
);
item
=
btrfs_lookup_csum
(
trans
,
root
,
path
,
objectid
,
offset
,
0
);
if
(
!
IS_ERR
(
item
))
goto
found
;
btrfs_release_path
(
root
,
path
);
file_key
.
objectid
=
objectid
;
file_key
.
offset
=
offset
;
file_key
.
flags
=
0
;
btrfs_set_key_type
(
&
file_key
,
BTRFS_CSUM_ITEM_KEY
);
printk
(
"searching for csum %Lu %Lu
\n
"
,
objectid
,
offset
);
ret
=
btrfs_search_slot
(
trans
,
root
,
&
file_key
,
path
,
sizeof
(
struct
btrfs_csum_item
),
1
);
printk
(
"ret %d
\n
"
,
ret
);
if
(
ret
<
0
)
goto
fail
;
if
(
ret
==
0
)
{
csum_offset
=
0
;
goto
csum
;
BUG
();
}
if
(
path
->
slots
[
0
]
==
0
)
{
btrfs_release_path
(
root
,
path
);
...
...
@@ -153,12 +167,15 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
path
->
slots
[
0
]
--
;
leaf
=
btrfs_buffer_leaf
(
path
->
nodes
[
0
]);
btrfs_disk_key_to_cpu
(
&
found_key
,
&
leaf
->
items
[
path
->
slots
[
0
]].
key
);
printk
(
"found key %Lu %Lu %u
\n
"
,
found_key
.
objectid
,
found_key
.
offset
,
found_key
.
flags
);
csum_offset
=
(
offset
-
found_key
.
offset
)
>>
root
->
fs_info
->
sb
->
s_blocksize_bits
;
printk
(
"csum_offset %Lu
\n
"
,
csum_offset
);
if
(
btrfs_key_type
(
&
found_key
)
!=
BTRFS_CSUM_ITEM_KEY
||
found_key
.
objectid
!=
objectid
||
csum_offset
>=
MAX_CSUM_ITEMS
(
root
))
{
btrfs_release_path
(
root
,
path
);
printk
(
"insert1
\n
"
);
goto
insert
;
}
if
(
csum_offset
>=
btrfs_item_size
(
leaf
->
items
+
path
->
slots
[
0
])
/
...
...
@@ -166,11 +183,13 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
ret
=
btrfs_extend_item
(
trans
,
root
,
path
,
sizeof
(
struct
btrfs_csum_item
));
BUG_ON
(
ret
);
printk
(
"item extended
\n
"
);
goto
csum
;
}
insert:
csum_offset
=
0
;
printk
(
"inserting item %Lu %Lu %u
\n
"
,
file_key
.
objectid
,
file_key
.
offset
,
file_key
.
flags
);
ret
=
btrfs_insert_empty_item
(
trans
,
root
,
path
,
&
file_key
,
sizeof
(
struct
btrfs_csum_item
));
if
(
ret
!=
0
&&
ret
!=
-
EEXIST
)
...
...
@@ -180,12 +199,14 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans,
struct
btrfs_csum_item
);
ret
=
0
;
item
+=
csum_offset
;
found:
ret
=
btrfs_csum_data
(
root
,
data
,
len
,
item
->
csum
);
btrfs_set_csum_extent_offset
(
item
,
extent_offset
);
btrfs_mark_buffer_dirty
(
path
->
nodes
[
0
]);
fail:
btrfs_release_path
(
root
,
path
);
btrfs_free_path
(
path
);
printk
(
"return ret %d
\n
"
,
ret
);
return
ret
;
}
...
...
@@ -208,7 +229,7 @@ int btrfs_csum_verify_file_block(struct btrfs_root *root,
btrfs_set_key_type
(
&
file_key
,
BTRFS_CSUM_ITEM_KEY
);
mutex_lock
(
&
root
->
fs_info
->
fs_mutex
);
item
=
__lookup_csum_item
(
root
,
path
,
objectid
,
offset
);
item
=
btrfs_lookup_csum
(
NULL
,
root
,
path
,
objectid
,
offset
,
0
);
if
(
IS_ERR
(
item
))
{
ret
=
PTR_ERR
(
item
);
goto
fail
;
...
...
fs/btrfs/super.c
View file @
b18c6685
...
...
@@ -1089,7 +1089,6 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock,
extent_start
=
btrfs_disk_key_offset
(
&
leaf
->
items
[
path
->
slots
[
0
]].
key
);
extent_start
=
extent_start
>>
inode
->
i_blkbits
;
extent_start
+=
btrfs_file_extent_offset
(
item
);
extent_end
=
extent_start
+
btrfs_file_extent_num_blocks
(
item
);
if
(
iblock
>=
extent_start
&&
iblock
<
extent_end
)
{
err
=
0
;
...
...
@@ -1103,6 +1102,7 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock,
err
=
0
;
goto
out
;
}
#if 0
ret = btrfs_alloc_file_extent(trans, root, objectid,
iblock << inode->i_blkbits,
1, extent_end, &blocknr);
...
...
@@ -1115,9 +1115,11 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock,
map_bh(result, inode->i_sb, blocknr);
btrfs_map_bh_to_logical(root, result, blocknr);
#endif
out:
btrfs_release_path
(
root
,
path
);
btrfs_free_path
(
path
);
printk
(
"mapping iblock %lu to %lu
\n
"
,
iblock
,
result
->
b_blocknr
);
if
(
trans
)
btrfs_end_transaction
(
trans
,
root
);
return
err
;
...
...
@@ -1273,8 +1275,244 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
return
err
;
}
static
int
prepare_pages
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
static
int
drop_csums
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
struct
inode
*
inode
,
u64
start
,
u64
end
)
{
struct
btrfs_path
*
path
;
struct
btrfs_leaf
*
leaf
;
struct
btrfs_key
key
;
int
slot
;
struct
btrfs_csum_item
*
item
;
char
*
old_block
=
NULL
;
u64
cur
=
start
;
u64
found_end
;
u64
num_csums
;
u64
item_size
;
int
ret
;
path
=
btrfs_alloc_path
();
if
(
!
path
)
return
-
ENOMEM
;
while
(
cur
<
end
)
{
item
=
btrfs_lookup_csum
(
trans
,
root
,
path
,
inode
->
i_ino
,
cur
,
1
);
if
(
IS_ERR
(
item
))
{
cur
+=
root
->
blocksize
;
continue
;
}
leaf
=
btrfs_buffer_leaf
(
path
->
nodes
[
0
]);
slot
=
path
->
slots
[
0
];
btrfs_disk_key_to_cpu
(
&
key
,
&
leaf
->
items
[
slot
].
key
);
item_size
=
btrfs_item_size
(
leaf
->
items
+
slot
);
num_csums
=
item_size
/
sizeof
(
struct
btrfs_csum_item
);
found_end
=
key
.
offset
+
(
num_csums
<<
inode
->
i_blkbits
);
cur
=
found_end
;
if
(
found_end
>
end
)
{
char
*
src
;
old_block
=
kmalloc
(
root
->
blocksize
,
GFP_NOFS
);
src
=
btrfs_item_ptr
(
leaf
,
slot
,
char
);
memcpy
(
old_block
,
src
,
item_size
);
}
if
(
key
.
offset
<
start
)
{
u64
new_size
=
(
start
-
key
.
offset
)
>>
inode
->
i_blkbits
;
new_size
*=
sizeof
(
struct
btrfs_csum_item
);
ret
=
btrfs_truncate_item
(
trans
,
root
,
path
,
new_size
);
BUG_ON
(
ret
);
}
else
{
btrfs_del_item
(
trans
,
root
,
path
);
}
btrfs_release_path
(
root
,
path
);
if
(
found_end
>
end
)
{
char
*
dst
;
int
i
;
int
new_size
;
num_csums
=
(
found_end
-
end
)
>>
inode
->
i_blkbits
;
new_size
=
num_csums
*
sizeof
(
struct
btrfs_csum_item
);
key
.
offset
=
end
;
ret
=
btrfs_insert_empty_item
(
trans
,
root
,
path
,
&
key
,
new_size
);
BUG_ON
(
ret
);
dst
=
btrfs_item_ptr
(
btrfs_buffer_leaf
(
path
->
nodes
[
0
]),
path
->
slots
[
0
],
char
);
memcpy
(
dst
,
old_block
+
item_size
-
new_size
,
new_size
);
item
=
(
struct
btrfs_csum_item
*
)
dst
;
for
(
i
=
0
;
i
<
num_csums
;
i
++
)
{
btrfs_set_csum_extent_offset
(
item
,
end
);
item
++
;
}
mark_buffer_dirty
(
path
->
nodes
[
0
]);
kfree
(
old_block
);
break
;
}
}
btrfs_free_path
(
path
);
return
0
;
}
static
int
drop_extents
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
struct
inode
*
inode
,
u64
start
,
u64
end
)
{
int
ret
;
struct
btrfs_key
key
;
struct
btrfs_leaf
*
leaf
;
int
slot
;
struct
btrfs_file_extent_item
*
extent
;
u64
extent_end
;
int
keep
;
struct
btrfs_file_extent_item
old
;
struct
btrfs_path
*
path
;
u64
search_start
=
start
;
int
bookend
;
path
=
btrfs_alloc_path
();
if
(
!
path
)
return
-
ENOMEM
;
search_again:
printk
(
"drop extent inode %lu start %Lu end %Lu
\n
"
,
inode
->
i_ino
,
start
,
end
);
ret
=
btrfs_lookup_file_extent
(
trans
,
root
,
path
,
inode
->
i_ino
,
search_start
,
-
1
);
if
(
ret
!=
0
)
{
printk
(
"lookup failed
\n
"
);
goto
out
;
}
while
(
1
)
{
keep
=
0
;
bookend
=
0
;
leaf
=
btrfs_buffer_leaf
(
path
->
nodes
[
0
]);
slot
=
path
->
slots
[
0
];
btrfs_disk_key_to_cpu
(
&
key
,
&
leaf
->
items
[
slot
].
key
);
printk
(
"found key %Lu %Lu %u
\n
"
,
key
.
objectid
,
key
.
offset
,
key
.
flags
);
extent
=
btrfs_item_ptr
(
leaf
,
slot
,
struct
btrfs_file_extent_item
);
extent_end
=
key
.
offset
+
(
btrfs_file_extent_num_blocks
(
extent
)
<<
inode
->
i_blkbits
);
printk
(
"extent end is %Lu
\n
"
,
extent_end
);
if
(
key
.
offset
>=
end
||
key
.
objectid
!=
inode
->
i_ino
)
{
ret
=
0
;
goto
out
;
}
if
(
btrfs_key_type
(
&
key
)
!=
BTRFS_EXTENT_DATA_KEY
)
goto
next_leaf
;
if
(
end
<
extent_end
&&
end
>=
key
.
offset
)
{
memcpy
(
&
old
,
extent
,
sizeof
(
old
));
ret
=
btrfs_inc_extent_ref
(
trans
,
root
,
btrfs_file_extent_disk_blocknr
(
&
old
),
btrfs_file_extent_disk_num_blocks
(
&
old
));
BUG_ON
(
ret
);
bookend
=
1
;
}
if
(
start
>
key
.
offset
)
{
u64
new_num
;
/* truncate existing extent */
keep
=
1
;
WARN_ON
(
start
&
(
root
->
blocksize
-
1
));
new_num
=
(
start
-
key
.
offset
)
>>
inode
->
i_blkbits
;
printk
(
"truncating existing extent, was %Lu "
,
btrfs_file_extent_num_blocks
(
extent
));
btrfs_set_file_extent_num_blocks
(
extent
,
new_num
);
printk
(
"now %Lu
\n
"
,
btrfs_file_extent_num_blocks
(
extent
));
mark_buffer_dirty
(
path
->
nodes
[
0
]);
}
if
(
!
keep
)
{
u64
disk_blocknr
;
u64
disk_num_blocks
;
printk
(
"del old
\n
"
);
disk_blocknr
=
btrfs_file_extent_disk_blocknr
(
extent
);
disk_num_blocks
=
btrfs_file_extent_disk_num_blocks
(
extent
);
search_start
=
key
.
offset
+
(
btrfs_file_extent_num_blocks
(
extent
)
<<
inode
->
i_blkbits
);
ret
=
btrfs_del_item
(
trans
,
root
,
path
);
BUG_ON
(
ret
);
btrfs_release_path
(
root
,
path
);
ret
=
btrfs_free_extent
(
trans
,
root
,
disk_blocknr
,
disk_num_blocks
,
0
);
BUG_ON
(
ret
);
if
(
!
bookend
&&
search_start
>=
end
)
{
ret
=
0
;
goto
out
;
}
if
(
!
bookend
)
goto
search_again
;
}
if
(
bookend
)
{
/* create bookend */
struct
btrfs_key
ins
;
printk
(
"bookend! extent end %Lu
\n
"
,
extent_end
);
ins
.
objectid
=
inode
->
i_ino
;
ins
.
offset
=
end
;
ins
.
flags
=
0
;
btrfs_set_key_type
(
&
ins
,
BTRFS_EXTENT_DATA_KEY
);
btrfs_release_path
(
root
,
path
);
ret
=
drop_csums
(
trans
,
root
,
inode
,
start
,
end
);
BUG_ON
(
ret
);
ret
=
btrfs_insert_empty_item
(
trans
,
root
,
path
,
&
ins
,
sizeof
(
*
extent
));
BUG_ON
(
ret
);
extent
=
btrfs_item_ptr
(
btrfs_buffer_leaf
(
path
->
nodes
[
0
]),
path
->
slots
[
0
],
struct
btrfs_file_extent_item
);
btrfs_set_file_extent_disk_blocknr
(
extent
,
btrfs_file_extent_disk_blocknr
(
&
old
));
btrfs_set_file_extent_disk_num_blocks
(
extent
,
btrfs_file_extent_disk_num_blocks
(
&
old
));
btrfs_set_file_extent_offset
(
extent
,
btrfs_file_extent_offset
(
&
old
)
+
((
end
-
key
.
offset
)
>>
inode
->
i_blkbits
));
WARN_ON
(
btrfs_file_extent_num_blocks
(
&
old
)
<
(
end
-
key
.
offset
)
>>
inode
->
i_blkbits
);
btrfs_set_file_extent_num_blocks
(
extent
,
btrfs_file_extent_num_blocks
(
&
old
)
-
((
end
-
key
.
offset
)
>>
inode
->
i_blkbits
));
btrfs_set_file_extent_generation
(
extent
,
btrfs_file_extent_generation
(
&
old
));
printk
(
"new bookend at offset %Lu, file_extent_offset %Lu, file_extent_num_blocks %Lu
\n
"
,
end
,
btrfs_file_extent_offset
(
extent
),
btrfs_file_extent_num_blocks
(
extent
));
btrfs_mark_buffer_dirty
(
path
->
nodes
[
0
]);
ret
=
0
;
goto
out_nocsum
;
}
next_leaf:
if
(
slot
>=
btrfs_header_nritems
(
&
leaf
->
header
)
-
1
)
{
ret
=
btrfs_next_leaf
(
root
,
path
);
if
(
ret
)
{
ret
=
0
;
goto
out
;
}
}
else
{
path
->
slots
[
0
]
++
;
}
}
out:
ret
=
drop_csums
(
trans
,
root
,
inode
,
start
,
end
);
BUG_ON
(
ret
);
out_nocsum:
btrfs_free_path
(
path
);
return
ret
;
}
static
int
prepare_pages
(
struct
btrfs_root
*
root
,
struct
file
*
file
,
struct
page
**
pages
,
size_t
num_pages
,
...
...
@@ -1289,7 +1527,6 @@ static int prepare_pages(struct btrfs_trans_handle *trans,
struct
inode
*
inode
=
file
->
f_path
.
dentry
->
d_inode
;
int
offset
;
int
err
=
0
;
int
ret
;
int
this_write
;
struct
buffer_head
*
bh
;
struct
buffer_head
*
head
;
...
...
@@ -1305,18 +1542,21 @@ static int prepare_pages(struct btrfs_trans_handle *trans,
}
offset
=
pos
&
(
PAGE_CACHE_SIZE
-
1
);
this_write
=
min
(
PAGE_CACHE_SIZE
-
offset
,
write_bytes
);
if
(
!
PageUptodate
(
pages
[
i
])
&&
(
pages
[
i
]
->
index
==
first_index
||
pages
[
i
]
->
index
==
last_index
)
&&
pos
<
isize
)
{
#if 0
if ((pages[i]->index == first_index ||
pages[i]->index == last_index) && pos < isize &&
!PageUptodate(pages[i])) {
ret = mpage_readpage(pages[i], btrfs_get_block);
BUG_ON(ret);
lock_page(pages[i]);
}
#endif
create_empty_buffers
(
pages
[
i
],
root
->
fs_info
->
sb
->
s_blocksize
,
(
1
<<
BH_Uptodate
));
head
=
page_buffers
(
pages
[
i
]);
bh
=
head
;
do
{
printk
(
"mapping page %lu to block %Lu
\n
"
,
pages
[
i
]
->
index
,
alloc_extent_start
);
err
=
btrfs_map_bh_to_logical
(
root
,
bh
,
alloc_extent_start
);
BUG_ON
(
err
);
...
...
@@ -1351,7 +1591,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
int
ret
=
0
;
struct
inode
*
inode
=
file
->
f_path
.
dentry
->
d_inode
;
struct
btrfs_root
*
root
=
BTRFS_I
(
inode
)
->
root
;
struct
page
*
pages
[
1
];
struct
page
*
pages
[
8
];
unsigned
long
first_index
;
unsigned
long
last_index
;
u64
start_pos
;
...
...
@@ -1359,6 +1599,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
u64
alloc_extent_start
;
u64
orig_extent_start
;
struct
btrfs_trans_handle
*
trans
;
struct
btrfs_key
ins
;
if
(
file
->
f_flags
&
O_DIRECT
)
return
-
EINVAL
;
...
...
@@ -1390,16 +1631,24 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
trans
=
btrfs_start_transaction
(
root
,
1
);
if
(
!
trans
)
{
err
=
-
ENOMEM
;
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
goto
out_unlock
;
}
ret
=
btrfs_alloc_file_extent
(
trans
,
root
,
inode
->
i_ino
,
start_pos
,
num_blocks
,
1
,
&
alloc_extent_start
);
BUG_ON
(
ret
);
if
(
start_pos
<
inode
->
i_size
)
{
ret
=
drop_extents
(
trans
,
root
,
inode
,
start_pos
,
(
pos
+
count
+
root
->
blocksize
-
1
)
&
~
(
root
->
blocksize
-
1
));
}
orig_extent_start
=
start_pos
;
ret
=
btrfs_end_transaction
(
trans
,
root
);
ret
=
btrfs_alloc_extent
(
trans
,
root
,
num_blocks
,
1
,
(
u64
)
-
1
,
&
ins
);
BUG_ON
(
ret
);
ret
=
btrfs_insert_file_extent
(
trans
,
root
,
inode
->
i_ino
,
start_pos
,
ins
.
objectid
,
ins
.
offset
);
BUG_ON
(
ret
);
alloc_extent_start
=
ins
.
objectid
;
ret
=
btrfs_end_transaction
(
trans
,
root
);
mutex_unlock
(
&
root
->
fs_info
->
fs_mutex
);
while
(
count
>
0
)
{
...
...
@@ -1407,16 +1656,21 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
size_t
write_bytes
=
min
(
count
,
PAGE_CACHE_SIZE
-
offset
);
size_t
num_pages
=
(
write_bytes
+
PAGE_CACHE_SIZE
-
1
)
>>
PAGE_CACHE_SHIFT
;
ret
=
prepare_pages
(
NULL
,
root
,
file
,
pages
,
num_pages
,
printk
(
"num_pages is %lu
\n
"
,
num_pages
);
memset
(
pages
,
0
,
sizeof
(
pages
));
ret
=
prepare_pages
(
root
,
file
,
pages
,
num_pages
,
pos
,
first_index
,
last_index
,
write_bytes
,
alloc_extent_start
);
BUG_ON
(
ret
);
/* FIXME blocks != pagesize */
alloc_extent_start
+=
num_pages
;
ret
=
btrfs_copy_from_user
(
pos
,
num_pages
,
write_bytes
,
pages
,
buf
);
BUG_ON
(
ret
);
printk
(
"2num_pages is %lu
\n
"
,
num_pages
);
ret
=
dirty_and_release_pages
(
NULL
,
root
,
file
,
pages
,
num_pages
,
orig_extent_start
,
pos
,
write_bytes
);
...
...
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