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
c2ea3fde
Commit
c2ea3fde
authored
Oct 10, 2008
by
Theodore Ts'o
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ext4: Remove old legacy block allocator
Signed-off-by:
"Theodore Ts'o"
<
tytso@mit.edu
>
parent
240799cd
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
40 additions
and
1528 deletions
+40
-1528
fs/ext4/balloc.c
fs/ext4/balloc.c
+11
-1344
fs/ext4/ext4.h
fs/ext4/ext4.h
+1
-7
fs/ext4/ext4_i.h
fs/ext4/ext4_i.h
+0
-35
fs/ext4/ext4_sb.h
fs/ext4/ext4_sb.h
+0
-1
fs/ext4/extents.c
fs/ext4/extents.c
+3
-6
fs/ext4/file.c
fs/ext4/file.c
+1
-1
fs/ext4/ialloc.c
fs/ext4/ialloc.c
+0
-1
fs/ext4/inode.c
fs/ext4/inode.c
+3
-30
fs/ext4/ioctl.c
fs/ext4/ioctl.c
+0
-44
fs/ext4/mballoc.c
fs/ext4/mballoc.c
+2
-20
fs/ext4/resize.c
fs/ext4/resize.c
+12
-6
fs/ext4/super.c
fs/ext4/super.c
+7
-33
No files found.
fs/ext4/balloc.c
View file @
c2ea3fde
...
...
@@ -83,6 +83,7 @@ static int ext4_group_used_meta_blocks(struct super_block *sb,
}
return
used_blocks
;
}
/* Initializes an uninitialized block bitmap if given, and returns the
* number of blocks free in the group. */
unsigned
ext4_init_block_bitmap
(
struct
super_block
*
sb
,
struct
buffer_head
*
bh
,
...
...
@@ -345,303 +346,6 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
*/
return
bh
;
}
/*
* The reservation window structure operations
* --------------------------------------------
* Operations include:
* dump, find, add, remove, is_empty, find_next_reservable_window, etc.
*
* We use a red-black tree to represent per-filesystem reservation
* windows.
*
*/
/**
* __rsv_window_dump() -- Dump the filesystem block allocation reservation map
* @rb_root: root of per-filesystem reservation rb tree
* @verbose: verbose mode
* @fn: function which wishes to dump the reservation map
*
* If verbose is turned on, it will print the whole block reservation
* windows(start, end). Otherwise, it will only print out the "bad" windows,
* those windows that overlap with their immediate neighbors.
*/
#if 1
static
void
__rsv_window_dump
(
struct
rb_root
*
root
,
int
verbose
,
const
char
*
fn
)
{
struct
rb_node
*
n
;
struct
ext4_reserve_window_node
*
rsv
,
*
prev
;
int
bad
;
restart:
n
=
rb_first
(
root
);
bad
=
0
;
prev
=
NULL
;
printk
(
KERN_DEBUG
"Block Allocation Reservation "
"Windows Map (%s):
\n
"
,
fn
);
while
(
n
)
{
rsv
=
rb_entry
(
n
,
struct
ext4_reserve_window_node
,
rsv_node
);
if
(
verbose
)
printk
(
KERN_DEBUG
"reservation window 0x%p "
"start: %llu, end: %llu
\n
"
,
rsv
,
rsv
->
rsv_start
,
rsv
->
rsv_end
);
if
(
rsv
->
rsv_start
&&
rsv
->
rsv_start
>=
rsv
->
rsv_end
)
{
printk
(
KERN_DEBUG
"Bad reservation %p (start >= end)
\n
"
,
rsv
);
bad
=
1
;
}
if
(
prev
&&
prev
->
rsv_end
>=
rsv
->
rsv_start
)
{
printk
(
KERN_DEBUG
"Bad reservation %p "
"(prev->end >= start)
\n
"
,
rsv
);
bad
=
1
;
}
if
(
bad
)
{
if
(
!
verbose
)
{
printk
(
KERN_DEBUG
"Restarting reservation "
"walk in verbose mode
\n
"
);
verbose
=
1
;
goto
restart
;
}
}
n
=
rb_next
(
n
);
prev
=
rsv
;
}
printk
(
KERN_DEBUG
"Window map complete.
\n
"
);
BUG_ON
(
bad
);
}
#define rsv_window_dump(root, verbose) \
__rsv_window_dump((root), (verbose), __func__)
#else
#define rsv_window_dump(root, verbose) do {} while (0)
#endif
/**
* goal_in_my_reservation()
* @rsv: inode's reservation window
* @grp_goal: given goal block relative to the allocation block group
* @group: the current allocation block group
* @sb: filesystem super block
*
* Test if the given goal block (group relative) is within the file's
* own block reservation window range.
*
* If the reservation window is outside the goal allocation group, return 0;
* grp_goal (given goal block) could be -1, which means no specific
* goal block. In this case, always return 1.
* If the goal block is within the reservation window, return 1;
* otherwise, return 0;
*/
static
int
goal_in_my_reservation
(
struct
ext4_reserve_window
*
rsv
,
ext4_grpblk_t
grp_goal
,
ext4_group_t
group
,
struct
super_block
*
sb
)
{
ext4_fsblk_t
group_first_block
,
group_last_block
;
group_first_block
=
ext4_group_first_block_no
(
sb
,
group
);
group_last_block
=
group_first_block
+
(
EXT4_BLOCKS_PER_GROUP
(
sb
)
-
1
);
if
((
rsv
->
_rsv_start
>
group_last_block
)
||
(
rsv
->
_rsv_end
<
group_first_block
))
return
0
;
if
((
grp_goal
>=
0
)
&&
((
grp_goal
+
group_first_block
<
rsv
->
_rsv_start
)
||
(
grp_goal
+
group_first_block
>
rsv
->
_rsv_end
)))
return
0
;
return
1
;
}
/**
* search_reserve_window()
* @rb_root: root of reservation tree
* @goal: target allocation block
*
* Find the reserved window which includes the goal, or the previous one
* if the goal is not in any window.
* Returns NULL if there are no windows or if all windows start after the goal.
*/
static
struct
ext4_reserve_window_node
*
search_reserve_window
(
struct
rb_root
*
root
,
ext4_fsblk_t
goal
)
{
struct
rb_node
*
n
=
root
->
rb_node
;
struct
ext4_reserve_window_node
*
rsv
;
if
(
!
n
)
return
NULL
;
do
{
rsv
=
rb_entry
(
n
,
struct
ext4_reserve_window_node
,
rsv_node
);
if
(
goal
<
rsv
->
rsv_start
)
n
=
n
->
rb_left
;
else
if
(
goal
>
rsv
->
rsv_end
)
n
=
n
->
rb_right
;
else
return
rsv
;
}
while
(
n
);
/*
* We've fallen off the end of the tree: the goal wasn't inside
* any particular node. OK, the previous node must be to one
* side of the interval containing the goal. If it's the RHS,
* we need to back up one.
*/
if
(
rsv
->
rsv_start
>
goal
)
{
n
=
rb_prev
(
&
rsv
->
rsv_node
);
rsv
=
rb_entry
(
n
,
struct
ext4_reserve_window_node
,
rsv_node
);
}
return
rsv
;
}
/**
* ext4_rsv_window_add() -- Insert a window to the block reservation rb tree.
* @sb: super block
* @rsv: reservation window to add
*
* Must be called with rsv_lock hold.
*/
void
ext4_rsv_window_add
(
struct
super_block
*
sb
,
struct
ext4_reserve_window_node
*
rsv
)
{
struct
rb_root
*
root
=
&
EXT4_SB
(
sb
)
->
s_rsv_window_root
;
struct
rb_node
*
node
=
&
rsv
->
rsv_node
;
ext4_fsblk_t
start
=
rsv
->
rsv_start
;
struct
rb_node
**
p
=
&
root
->
rb_node
;
struct
rb_node
*
parent
=
NULL
;
struct
ext4_reserve_window_node
*
this
;
while
(
*
p
)
{
parent
=
*
p
;
this
=
rb_entry
(
parent
,
struct
ext4_reserve_window_node
,
rsv_node
);
if
(
start
<
this
->
rsv_start
)
p
=
&
(
*
p
)
->
rb_left
;
else
if
(
start
>
this
->
rsv_end
)
p
=
&
(
*
p
)
->
rb_right
;
else
{
rsv_window_dump
(
root
,
1
);
BUG
();
}
}
rb_link_node
(
node
,
parent
,
p
);
rb_insert_color
(
node
,
root
);
}
/**
* ext4_rsv_window_remove() -- unlink a window from the reservation rb tree
* @sb: super block
* @rsv: reservation window to remove
*
* Mark the block reservation window as not allocated, and unlink it
* from the filesystem reservation window rb tree. Must be called with
* rsv_lock hold.
*/
static
void
rsv_window_remove
(
struct
super_block
*
sb
,
struct
ext4_reserve_window_node
*
rsv
)
{
rsv
->
rsv_start
=
EXT4_RESERVE_WINDOW_NOT_ALLOCATED
;
rsv
->
rsv_end
=
EXT4_RESERVE_WINDOW_NOT_ALLOCATED
;
rsv
->
rsv_alloc_hit
=
0
;
rb_erase
(
&
rsv
->
rsv_node
,
&
EXT4_SB
(
sb
)
->
s_rsv_window_root
);
}
/*
* rsv_is_empty() -- Check if the reservation window is allocated.
* @rsv: given reservation window to check
*
* returns 1 if the end block is EXT4_RESERVE_WINDOW_NOT_ALLOCATED.
*/
static
inline
int
rsv_is_empty
(
struct
ext4_reserve_window
*
rsv
)
{
/* a valid reservation end block could not be 0 */
return
rsv
->
_rsv_end
==
EXT4_RESERVE_WINDOW_NOT_ALLOCATED
;
}
/**
* ext4_init_block_alloc_info()
* @inode: file inode structure
*
* Allocate and initialize the reservation window structure, and
* link the window to the ext4 inode structure at last
*
* The reservation window structure is only dynamically allocated
* and linked to ext4 inode the first time the open file
* needs a new block. So, before every ext4_new_block(s) call, for
* regular files, we should check whether the reservation window
* structure exists or not. In the latter case, this function is called.
* Fail to do so will result in block reservation being turned off for that
* open file.
*
* This function is called from ext4_get_blocks_handle(), also called
* when setting the reservation window size through ioctl before the file
* is open for write (needs block allocation).
*
* Needs down_write(i_data_sem) protection prior to call this function.
*/
void
ext4_init_block_alloc_info
(
struct
inode
*
inode
)
{
struct
ext4_inode_info
*
ei
=
EXT4_I
(
inode
);
struct
ext4_block_alloc_info
*
block_i
=
ei
->
i_block_alloc_info
;
struct
super_block
*
sb
=
inode
->
i_sb
;
block_i
=
kmalloc
(
sizeof
(
*
block_i
),
GFP_NOFS
);
if
(
block_i
)
{
struct
ext4_reserve_window_node
*
rsv
=
&
block_i
->
rsv_window_node
;
rsv
->
rsv_start
=
EXT4_RESERVE_WINDOW_NOT_ALLOCATED
;
rsv
->
rsv_end
=
EXT4_RESERVE_WINDOW_NOT_ALLOCATED
;
/*
* if filesystem is mounted with NORESERVATION, the goal
* reservation window size is set to zero to indicate
* block reservation is off
*/
if
(
!
test_opt
(
sb
,
RESERVATION
))
rsv
->
rsv_goal_size
=
0
;
else
rsv
->
rsv_goal_size
=
EXT4_DEFAULT_RESERVE_BLOCKS
;
rsv
->
rsv_alloc_hit
=
0
;
block_i
->
last_alloc_logical_block
=
0
;
block_i
->
last_alloc_physical_block
=
0
;
}
ei
->
i_block_alloc_info
=
block_i
;
}
/**
* ext4_discard_reservation()
* @inode: inode
*
* Discard(free) block reservation window on last file close, or truncate
* or at last iput().
*
* It is being called in three cases:
* ext4_release_file(): last writer close the file
* ext4_clear_inode(): last iput(), when nobody link to this file.
* ext4_truncate(): when the block indirect map is about to change.
*
*/
void
ext4_discard_reservation
(
struct
inode
*
inode
)
{
struct
ext4_inode_info
*
ei
=
EXT4_I
(
inode
);
struct
ext4_block_alloc_info
*
block_i
=
ei
->
i_block_alloc_info
;
struct
ext4_reserve_window_node
*
rsv
;
spinlock_t
*
rsv_lock
=
&
EXT4_SB
(
inode
->
i_sb
)
->
s_rsv_window_lock
;
ext4_mb_discard_inode_preallocations
(
inode
);
if
(
!
block_i
)
return
;
rsv
=
&
block_i
->
rsv_window_node
;
if
(
!
rsv_is_empty
(
&
rsv
->
rsv_window
))
{
spin_lock
(
rsv_lock
);
if
(
!
rsv_is_empty
(
&
rsv
->
rsv_window
))
rsv_window_remove
(
inode
->
i_sb
,
rsv
);
spin_unlock
(
rsv_lock
);
}
}
/**
* ext4_free_blocks_sb() -- Free given blocks and update quota
...
...
@@ -650,6 +354,13 @@ void ext4_discard_reservation(struct inode *inode)
* @block: start physcial block to free
* @count: number of blocks to free
* @pdquot_freed_blocks: pointer to quota
*
* XXX This function is only used by the on-line resizing code, which
* should probably be fixed up to call the mballoc variant. There
* this needs to be cleaned up later; in fact, I'm not convinced this
* is 100% correct in the face of the mballoc code. The online resizing
* code needs to be fixed up to more tightly (and correctly) interlock
* with the mballoc code.
*/
void
ext4_free_blocks_sb
(
handle_t
*
handle
,
struct
super_block
*
sb
,
ext4_fsblk_t
block
,
unsigned
long
count
,
...
...
@@ -861,747 +572,13 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
sb
=
inode
->
i_sb
;
if
(
!
test_opt
(
sb
,
MBALLOC
)
||
!
EXT4_SB
(
sb
)
->
s_group_info
)
ext4_free_blocks_sb
(
handle
,
sb
,
block
,
count
,
&
dquot_freed_blocks
);
else
ext4_mb_free_blocks
(
handle
,
inode
,
block
,
count
,
metadata
,
&
dquot_freed_blocks
);
ext4_mb_free_blocks
(
handle
,
inode
,
block
,
count
,
metadata
,
&
dquot_freed_blocks
);
if
(
dquot_freed_blocks
)
DQUOT_FREE_BLOCK
(
inode
,
dquot_freed_blocks
);
return
;
}
/**
* ext4_test_allocatable()
* @nr: given allocation block group
* @bh: bufferhead contains the bitmap of the given block group
*
* For ext4 allocations, we must not reuse any blocks which are
* allocated in the bitmap buffer's "last committed data" copy. This
* prevents deletes from freeing up the page for reuse until we have
* committed the delete transaction.
*
* If we didn't do this, then deleting something and reallocating it as
* data would allow the old block to be overwritten before the
* transaction committed (because we force data to disk before commit).
* This would lead to corruption if we crashed between overwriting the
* data and committing the delete.
*
* @@@ We may want to make this allocation behaviour conditional on
* data-writes at some point, and disable it for metadata allocations or
* sync-data inodes.
*/
static
int
ext4_test_allocatable
(
ext4_grpblk_t
nr
,
struct
buffer_head
*
bh
)
{
int
ret
;
struct
journal_head
*
jh
=
bh2jh
(
bh
);
if
(
ext4_test_bit
(
nr
,
bh
->
b_data
))
return
0
;
jbd_lock_bh_state
(
bh
);
if
(
!
jh
->
b_committed_data
)
ret
=
1
;
else
ret
=
!
ext4_test_bit
(
nr
,
jh
->
b_committed_data
);
jbd_unlock_bh_state
(
bh
);
return
ret
;
}
/**
* bitmap_search_next_usable_block()
* @start: the starting block (group relative) of the search
* @bh: bufferhead contains the block group bitmap
* @maxblocks: the ending block (group relative) of the reservation
*
* The bitmap search --- search forward alternately through the actual
* bitmap on disk and the last-committed copy in journal, until we find a
* bit free in both bitmaps.
*/
static
ext4_grpblk_t
bitmap_search_next_usable_block
(
ext4_grpblk_t
start
,
struct
buffer_head
*
bh
,
ext4_grpblk_t
maxblocks
)
{
ext4_grpblk_t
next
;
struct
journal_head
*
jh
=
bh2jh
(
bh
);
while
(
start
<
maxblocks
)
{
next
=
ext4_find_next_zero_bit
(
bh
->
b_data
,
maxblocks
,
start
);
if
(
next
>=
maxblocks
)
return
-
1
;
if
(
ext4_test_allocatable
(
next
,
bh
))
return
next
;
jbd_lock_bh_state
(
bh
);
if
(
jh
->
b_committed_data
)
start
=
ext4_find_next_zero_bit
(
jh
->
b_committed_data
,
maxblocks
,
next
);
jbd_unlock_bh_state
(
bh
);
}
return
-
1
;
}
/**
* find_next_usable_block()
* @start: the starting block (group relative) to find next
* allocatable block in bitmap.
* @bh: bufferhead contains the block group bitmap
* @maxblocks: the ending block (group relative) for the search
*
* Find an allocatable block in a bitmap. We honor both the bitmap and
* its last-committed copy (if that exists), and perform the "most
* appropriate allocation" algorithm of looking for a free block near
* the initial goal; then for a free byte somewhere in the bitmap; then
* for any free bit in the bitmap.
*/
static
ext4_grpblk_t
find_next_usable_block
(
ext4_grpblk_t
start
,
struct
buffer_head
*
bh
,
ext4_grpblk_t
maxblocks
)
{
ext4_grpblk_t
here
,
next
;
char
*
p
,
*
r
;
if
(
start
>
0
)
{
/*
* The goal was occupied; search forward for a free
* block within the next XX blocks.
*
* end_goal is more or less random, but it has to be
* less than EXT4_BLOCKS_PER_GROUP. Aligning up to the
* next 64-bit boundary is simple..
*/
ext4_grpblk_t
end_goal
=
(
start
+
63
)
&
~
63
;
if
(
end_goal
>
maxblocks
)
end_goal
=
maxblocks
;
here
=
ext4_find_next_zero_bit
(
bh
->
b_data
,
end_goal
,
start
);
if
(
here
<
end_goal
&&
ext4_test_allocatable
(
here
,
bh
))
return
here
;
ext4_debug
(
"Bit not found near goal
\n
"
);
}
here
=
start
;
if
(
here
<
0
)
here
=
0
;
p
=
((
char
*
)
bh
->
b_data
)
+
(
here
>>
3
);
r
=
memscan
(
p
,
0
,
((
maxblocks
+
7
)
>>
3
)
-
(
here
>>
3
));
next
=
(
r
-
((
char
*
)
bh
->
b_data
))
<<
3
;
if
(
next
<
maxblocks
&&
next
>=
start
&&
ext4_test_allocatable
(
next
,
bh
))
return
next
;
/*
* The bitmap search --- search forward alternately through the actual
* bitmap and the last-committed copy until we find a bit free in
* both
*/
here
=
bitmap_search_next_usable_block
(
here
,
bh
,
maxblocks
);
return
here
;
}
/**
* claim_block()
* @block: the free block (group relative) to allocate
* @bh: the bufferhead containts the block group bitmap
*
* We think we can allocate this block in this bitmap. Try to set the bit.
* If that succeeds then check that nobody has allocated and then freed the
* block since we saw that is was not marked in b_committed_data. If it _was_
* allocated and freed then clear the bit in the bitmap again and return
* zero (failure).
*/
static
inline
int
claim_block
(
spinlock_t
*
lock
,
ext4_grpblk_t
block
,
struct
buffer_head
*
bh
)
{
struct
journal_head
*
jh
=
bh2jh
(
bh
);
int
ret
;
if
(
ext4_set_bit_atomic
(
lock
,
block
,
bh
->
b_data
))
return
0
;
jbd_lock_bh_state
(
bh
);
if
(
jh
->
b_committed_data
&&
ext4_test_bit
(
block
,
jh
->
b_committed_data
))
{
ext4_clear_bit_atomic
(
lock
,
block
,
bh
->
b_data
);
ret
=
0
;
}
else
{
ret
=
1
;
}
jbd_unlock_bh_state
(
bh
);
return
ret
;
}
/**
* ext4_try_to_allocate()
* @sb: superblock
* @handle: handle to this transaction
* @group: given allocation block group
* @bitmap_bh: bufferhead holds the block bitmap
* @grp_goal: given target block within the group
* @count: target number of blocks to allocate
* @my_rsv: reservation window
*
* Attempt to allocate blocks within a give range. Set the range of allocation
* first, then find the first free bit(s) from the bitmap (within the range),
* and at last, allocate the blocks by claiming the found free bit as allocated.
*
* To set the range of this allocation:
* if there is a reservation window, only try to allocate block(s) from the
* file's own reservation window;
* Otherwise, the allocation range starts from the give goal block, ends at
* the block group's last block.
*
* If we failed to allocate the desired block then we may end up crossing to a
* new bitmap. In that case we must release write access to the old one via
* ext4_journal_release_buffer(), else we'll run out of credits.
*/
static
ext4_grpblk_t
ext4_try_to_allocate
(
struct
super_block
*
sb
,
handle_t
*
handle
,
ext4_group_t
group
,
struct
buffer_head
*
bitmap_bh
,
ext4_grpblk_t
grp_goal
,
unsigned
long
*
count
,
struct
ext4_reserve_window
*
my_rsv
)
{
ext4_fsblk_t
group_first_block
;
ext4_grpblk_t
start
,
end
;
unsigned
long
num
=
0
;
/* we do allocation within the reservation window if we have a window */
if
(
my_rsv
)
{
group_first_block
=
ext4_group_first_block_no
(
sb
,
group
);
if
(
my_rsv
->
_rsv_start
>=
group_first_block
)
start
=
my_rsv
->
_rsv_start
-
group_first_block
;
else
/* reservation window cross group boundary */
start
=
0
;
end
=
my_rsv
->
_rsv_end
-
group_first_block
+
1
;
if
(
end
>
EXT4_BLOCKS_PER_GROUP
(
sb
))
/* reservation window crosses group boundary */
end
=
EXT4_BLOCKS_PER_GROUP
(
sb
);
if
((
start
<=
grp_goal
)
&&
(
grp_goal
<
end
))
start
=
grp_goal
;
else
grp_goal
=
-
1
;
}
else
{
if
(
grp_goal
>
0
)
start
=
grp_goal
;
else
start
=
0
;
end
=
EXT4_BLOCKS_PER_GROUP
(
sb
);
}
BUG_ON
(
start
>
EXT4_BLOCKS_PER_GROUP
(
sb
));
repeat:
if
(
grp_goal
<
0
||
!
ext4_test_allocatable
(
grp_goal
,
bitmap_bh
))
{
grp_goal
=
find_next_usable_block
(
start
,
bitmap_bh
,
end
);
if
(
grp_goal
<
0
)
goto
fail_access
;
if
(
!
my_rsv
)
{
int
i
;
for
(
i
=
0
;
i
<
7
&&
grp_goal
>
start
&&
ext4_test_allocatable
(
grp_goal
-
1
,
bitmap_bh
);
i
++
,
grp_goal
--
)
;
}
}
start
=
grp_goal
;
if
(
!
claim_block
(
sb_bgl_lock
(
EXT4_SB
(
sb
),
group
),
grp_goal
,
bitmap_bh
))
{
/*
* The block was allocated by another thread, or it was
* allocated and then freed by another thread
*/
start
++
;
grp_goal
++
;
if
(
start
>=
end
)
goto
fail_access
;
goto
repeat
;
}
num
++
;
grp_goal
++
;
while
(
num
<
*
count
&&
grp_goal
<
end
&&
ext4_test_allocatable
(
grp_goal
,
bitmap_bh
)
&&
claim_block
(
sb_bgl_lock
(
EXT4_SB
(
sb
),
group
),
grp_goal
,
bitmap_bh
))
{
num
++
;
grp_goal
++
;
}
*
count
=
num
;
return
grp_goal
-
num
;
fail_access:
*
count
=
num
;
return
-
1
;
}
/**
* find_next_reservable_window():
* find a reservable space within the given range.
* It does not allocate the reservation window for now:
* alloc_new_reservation() will do the work later.
*
* @search_head: the head of the searching list;
* This is not necessarily the list head of the whole filesystem
*
* We have both head and start_block to assist the search
* for the reservable space. The list starts from head,
* but we will shift to the place where start_block is,
* then start from there, when looking for a reservable space.
*
* @size: the target new reservation window size
*
* @group_first_block: the first block we consider to start
* the real search from
*
* @last_block:
* the maximum block number that our goal reservable space
* could start from. This is normally the last block in this
* group. The search will end when we found the start of next
* possible reservable space is out of this boundary.
* This could handle the cross boundary reservation window
* request.
*
* basically we search from the given range, rather than the whole
* reservation double linked list, (start_block, last_block)
* to find a free region that is of my size and has not
* been reserved.
*
*/
static
int
find_next_reservable_window
(
struct
ext4_reserve_window_node
*
search_head
,
struct
ext4_reserve_window_node
*
my_rsv
,
struct
super_block
*
sb
,
ext4_fsblk_t
start_block
,
ext4_fsblk_t
last_block
)
{
struct
rb_node
*
next
;
struct
ext4_reserve_window_node
*
rsv
,
*
prev
;
ext4_fsblk_t
cur
;
int
size
=
my_rsv
->
rsv_goal_size
;
/* TODO: make the start of the reservation window byte-aligned */
/* cur = *start_block & ~7;*/
cur
=
start_block
;
rsv
=
search_head
;
if
(
!
rsv
)
return
-
1
;
while
(
1
)
{
if
(
cur
<=
rsv
->
rsv_end
)
cur
=
rsv
->
rsv_end
+
1
;
/* TODO?
* in the case we could not find a reservable space
* that is what is expected, during the re-search, we could
* remember what's the largest reservable space we could have
* and return that one.
*
* For now it will fail if we could not find the reservable
* space with expected-size (or more)...
*/
if
(
cur
>
last_block
)
return
-
1
;
/* fail */
prev
=
rsv
;
next
=
rb_next
(
&
rsv
->
rsv_node
);
rsv
=
rb_entry
(
next
,
struct
ext4_reserve_window_node
,
rsv_node
);
/*
* Reached the last reservation, we can just append to the
* previous one.
*/
if
(
!
next
)
break
;
if
(
cur
+
size
<=
rsv
->
rsv_start
)
{
/*
* Found a reserveable space big enough. We could
* have a reservation across the group boundary here
*/
break
;
}
}
/*
* we come here either :
* when we reach the end of the whole list,
* and there is empty reservable space after last entry in the list.
* append it to the end of the list.
*
* or we found one reservable space in the middle of the list,
* return the reservation window that we could append to.
* succeed.
*/
if
((
prev
!=
my_rsv
)
&&
(
!
rsv_is_empty
(
&
my_rsv
->
rsv_window
)))
rsv_window_remove
(
sb
,
my_rsv
);
/*
* Let's book the whole avaliable window for now. We will check the
* disk bitmap later and then, if there are free blocks then we adjust
* the window size if it's larger than requested.
* Otherwise, we will remove this node from the tree next time
* call find_next_reservable_window.
*/
my_rsv
->
rsv_start
=
cur
;
my_rsv
->
rsv_end
=
cur
+
size
-
1
;
my_rsv
->
rsv_alloc_hit
=
0
;
if
(
prev
!=
my_rsv
)
ext4_rsv_window_add
(
sb
,
my_rsv
);
return
0
;
}
/**
* alloc_new_reservation()--allocate a new reservation window
*
* To make a new reservation, we search part of the filesystem
* reservation list (the list that inside the group). We try to
* allocate a new reservation window near the allocation goal,
* or the beginning of the group, if there is no goal.
*
* We first find a reservable space after the goal, then from
* there, we check the bitmap for the first free block after
* it. If there is no free block until the end of group, then the
* whole group is full, we failed. Otherwise, check if the free
* block is inside the expected reservable space, if so, we
* succeed.
* If the first free block is outside the reservable space, then
* start from the first free block, we search for next available
* space, and go on.
*
* on succeed, a new reservation will be found and inserted into the list
* It contains at least one free block, and it does not overlap with other
* reservation windows.
*
* failed: we failed to find a reservation window in this group
*
* @rsv: the reservation
*
* @grp_goal: The goal (group-relative). It is where the search for a
* free reservable space should start from.
* if we have a grp_goal(grp_goal >0 ), then start from there,
* no grp_goal(grp_goal = -1), we start from the first block
* of the group.
*
* @sb: the super block
* @group: the group we are trying to allocate in
* @bitmap_bh: the block group block bitmap
*
*/
static
int
alloc_new_reservation
(
struct
ext4_reserve_window_node
*
my_rsv
,
ext4_grpblk_t
grp_goal
,
struct
super_block
*
sb
,
ext4_group_t
group
,
struct
buffer_head
*
bitmap_bh
)
{
struct
ext4_reserve_window_node
*
search_head
;
ext4_fsblk_t
group_first_block
,
group_end_block
,
start_block
;
ext4_grpblk_t
first_free_block
;
struct
rb_root
*
fs_rsv_root
=
&
EXT4_SB
(
sb
)
->
s_rsv_window_root
;
unsigned
long
size
;
int
ret
;
spinlock_t
*
rsv_lock
=
&
EXT4_SB
(
sb
)
->
s_rsv_window_lock
;
group_first_block
=
ext4_group_first_block_no
(
sb
,
group
);
group_end_block
=
group_first_block
+
(
EXT4_BLOCKS_PER_GROUP
(
sb
)
-
1
);
if
(
grp_goal
<
0
)
start_block
=
group_first_block
;
else
start_block
=
grp_goal
+
group_first_block
;
size
=
my_rsv
->
rsv_goal_size
;
if
(
!
rsv_is_empty
(
&
my_rsv
->
rsv_window
))
{
/*
* if the old reservation is cross group boundary
* and if the goal is inside the old reservation window,
* we will come here when we just failed to allocate from
* the first part of the window. We still have another part
* that belongs to the next group. In this case, there is no
* point to discard our window and try to allocate a new one
* in this group(which will fail). we should
* keep the reservation window, just simply move on.
*
* Maybe we could shift the start block of the reservation
* window to the first block of next group.
*/
if
((
my_rsv
->
rsv_start
<=
group_end_block
)
&&
(
my_rsv
->
rsv_end
>
group_end_block
)
&&
(
start_block
>=
my_rsv
->
rsv_start
))
return
-
1
;
if
((
my_rsv
->
rsv_alloc_hit
>
(
my_rsv
->
rsv_end
-
my_rsv
->
rsv_start
+
1
)
/
2
))
{
/*
* if the previously allocation hit ratio is
* greater than 1/2, then we double the size of
* the reservation window the next time,
* otherwise we keep the same size window
*/
size
=
size
*
2
;
if
(
size
>
EXT4_MAX_RESERVE_BLOCKS
)
size
=
EXT4_MAX_RESERVE_BLOCKS
;
my_rsv
->
rsv_goal_size
=
size
;
}
}
spin_lock
(
rsv_lock
);
/*
* shift the search start to the window near the goal block
*/
search_head
=
search_reserve_window
(
fs_rsv_root
,
start_block
);
/*
* find_next_reservable_window() simply finds a reservable window
* inside the given range(start_block, group_end_block).
*
* To make sure the reservation window has a free bit inside it, we
* need to check the bitmap after we found a reservable window.
*/
retry:
ret
=
find_next_reservable_window
(
search_head
,
my_rsv
,
sb
,
start_block
,
group_end_block
);
if
(
ret
==
-
1
)
{
if
(
!
rsv_is_empty
(
&
my_rsv
->
rsv_window
))
rsv_window_remove
(
sb
,
my_rsv
);
spin_unlock
(
rsv_lock
);
return
-
1
;
}
/*
* On success, find_next_reservable_window() returns the
* reservation window where there is a reservable space after it.
* Before we reserve this reservable space, we need
* to make sure there is at least a free block inside this region.
*
* searching the first free bit on the block bitmap and copy of
* last committed bitmap alternatively, until we found a allocatable
* block. Search start from the start block of the reservable space
* we just found.
*/
spin_unlock
(
rsv_lock
);
first_free_block
=
bitmap_search_next_usable_block
(
my_rsv
->
rsv_start
-
group_first_block
,
bitmap_bh
,
group_end_block
-
group_first_block
+
1
);
if
(
first_free_block
<
0
)
{
/*
* no free block left on the bitmap, no point
* to reserve the space. return failed.
*/
spin_lock
(
rsv_lock
);
if
(
!
rsv_is_empty
(
&
my_rsv
->
rsv_window
))
rsv_window_remove
(
sb
,
my_rsv
);
spin_unlock
(
rsv_lock
);
return
-
1
;
/* failed */
}
start_block
=
first_free_block
+
group_first_block
;
/*
* check if the first free block is within the
* free space we just reserved
*/
if
(
start_block
>=
my_rsv
->
rsv_start
&&
start_block
<=
my_rsv
->
rsv_end
)
return
0
;
/* success */
/*
* if the first free bit we found is out of the reservable space
* continue search for next reservable space,
* start from where the free block is,
* we also shift the list head to where we stopped last time
*/
search_head
=
my_rsv
;
spin_lock
(
rsv_lock
);
goto
retry
;
}
/**
* try_to_extend_reservation()
* @my_rsv: given reservation window
* @sb: super block
* @size: the delta to extend
*
* Attempt to expand the reservation window large enough to have
* required number of free blocks
*
* Since ext4_try_to_allocate() will always allocate blocks within
* the reservation window range, if the window size is too small,
* multiple blocks allocation has to stop at the end of the reservation
* window. To make this more efficient, given the total number of
* blocks needed and the current size of the window, we try to
* expand the reservation window size if necessary on a best-effort
* basis before ext4_new_blocks() tries to allocate blocks,
*/
static
void
try_to_extend_reservation
(
struct
ext4_reserve_window_node
*
my_rsv
,
struct
super_block
*
sb
,
int
size
)
{
struct
ext4_reserve_window_node
*
next_rsv
;
struct
rb_node
*
next
;
spinlock_t
*
rsv_lock
=
&
EXT4_SB
(
sb
)
->
s_rsv_window_lock
;
if
(
!
spin_trylock
(
rsv_lock
))
return
;
next
=
rb_next
(
&
my_rsv
->
rsv_node
);
if
(
!
next
)
my_rsv
->
rsv_end
+=
size
;
else
{
next_rsv
=
rb_entry
(
next
,
struct
ext4_reserve_window_node
,
rsv_node
);
if
((
next_rsv
->
rsv_start
-
my_rsv
->
rsv_end
-
1
)
>=
size
)
my_rsv
->
rsv_end
+=
size
;
else
my_rsv
->
rsv_end
=
next_rsv
->
rsv_start
-
1
;
}
spin_unlock
(
rsv_lock
);
}
/**
* ext4_try_to_allocate_with_rsv()
* @sb: superblock
* @handle: handle to this transaction
* @group: given allocation block group
* @bitmap_bh: bufferhead holds the block bitmap
* @grp_goal: given target block within the group
* @count: target number of blocks to allocate
* @my_rsv: reservation window
* @errp: pointer to store the error code
*
* This is the main function used to allocate a new block and its reservation
* window.
*
* Each time when a new block allocation is need, first try to allocate from
* its own reservation. If it does not have a reservation window, instead of
* looking for a free bit on bitmap first, then look up the reservation list to
* see if it is inside somebody else's reservation window, we try to allocate a
* reservation window for it starting from the goal first. Then do the block
* allocation within the reservation window.
*
* This will avoid keeping on searching the reservation list again and
* again when somebody is looking for a free block (without
* reservation), and there are lots of free blocks, but they are all
* being reserved.
*
* We use a red-black tree for the per-filesystem reservation list.
*
*/
static
ext4_grpblk_t
ext4_try_to_allocate_with_rsv
(
struct
super_block
*
sb
,
handle_t
*
handle
,
ext4_group_t
group
,
struct
buffer_head
*
bitmap_bh
,
ext4_grpblk_t
grp_goal
,
struct
ext4_reserve_window_node
*
my_rsv
,
unsigned
long
*
count
,
int
*
errp
)
{
ext4_fsblk_t
group_first_block
,
group_last_block
;
ext4_grpblk_t
ret
=
0
;
int
fatal
;
unsigned
long
num
=
*
count
;
*
errp
=
0
;
/*
* Make sure we use undo access for the bitmap, because it is critical
* that we do the frozen_data COW on bitmap buffers in all cases even
* if the buffer is in BJ_Forget state in the committing transaction.
*/
BUFFER_TRACE
(
bitmap_bh
,
"get undo access for new block"
);
fatal
=
ext4_journal_get_undo_access
(
handle
,
bitmap_bh
);
if
(
fatal
)
{
*
errp
=
fatal
;
return
-
1
;
}
/*
* we don't deal with reservation when
* filesystem is mounted without reservation
* or the file is not a regular file
* or last attempt to allocate a block with reservation turned on failed
*/
if
(
my_rsv
==
NULL
)
{
ret
=
ext4_try_to_allocate
(
sb
,
handle
,
group
,
bitmap_bh
,
grp_goal
,
count
,
NULL
);
goto
out
;
}
/*
* grp_goal is a group relative block number (if there is a goal)
* 0 <= grp_goal < EXT4_BLOCKS_PER_GROUP(sb)
* first block is a filesystem wide block number
* first block is the block number of the first block in this group
*/
group_first_block
=
ext4_group_first_block_no
(
sb
,
group
);
group_last_block
=
group_first_block
+
(
EXT4_BLOCKS_PER_GROUP
(
sb
)
-
1
);
/*
* Basically we will allocate a new block from inode's reservation
* window.
*
* We need to allocate a new reservation window, if:
* a) inode does not have a reservation window; or
* b) last attempt to allocate a block from existing reservation
* failed; or
* c) we come here with a goal and with a reservation window
*
* We do not need to allocate a new reservation window if we come here
* at the beginning with a goal and the goal is inside the window, or
* we don't have a goal but already have a reservation window.
* then we could go to allocate from the reservation window directly.
*/
while
(
1
)
{
if
(
rsv_is_empty
(
&
my_rsv
->
rsv_window
)
||
(
ret
<
0
)
||
!
goal_in_my_reservation
(
&
my_rsv
->
rsv_window
,
grp_goal
,
group
,
sb
))
{
if
(
my_rsv
->
rsv_goal_size
<
*
count
)
my_rsv
->
rsv_goal_size
=
*
count
;
ret
=
alloc_new_reservation
(
my_rsv
,
grp_goal
,
sb
,
group
,
bitmap_bh
);
if
(
ret
<
0
)
break
;
/* failed */
if
(
!
goal_in_my_reservation
(
&
my_rsv
->
rsv_window
,
grp_goal
,
group
,
sb
))
grp_goal
=
-
1
;
}
else
if
(
grp_goal
>=
0
)
{
int
curr
=
my_rsv
->
rsv_end
-
(
grp_goal
+
group_first_block
)
+
1
;
if
(
curr
<
*
count
)
try_to_extend_reservation
(
my_rsv
,
sb
,
*
count
-
curr
);
}
if
((
my_rsv
->
rsv_start
>
group_last_block
)
||
(
my_rsv
->
rsv_end
<
group_first_block
))
{
rsv_window_dump
(
&
EXT4_SB
(
sb
)
->
s_rsv_window_root
,
1
);
BUG
();
}
ret
=
ext4_try_to_allocate
(
sb
,
handle
,
group
,
bitmap_bh
,
grp_goal
,
&
num
,
&
my_rsv
->
rsv_window
);
if
(
ret
>=
0
)
{
my_rsv
->
rsv_alloc_hit
+=
num
;
*
count
=
num
;
break
;
/* succeed */
}
num
=
*
count
;
}
out:
if
(
ret
>=
0
)
{
BUFFER_TRACE
(
bitmap_bh
,
"journal_dirty_metadata for "
"bitmap block"
);
fatal
=
ext4_journal_dirty_metadata
(
handle
,
bitmap_bh
);
if
(
fatal
)
{
*
errp
=
fatal
;
return
-
1
;
}
return
ret
;
}
BUFFER_TRACE
(
bitmap_bh
,
"journal_release_buffer"
);
ext4_journal_release_buffer
(
handle
,
bitmap_bh
);
return
ret
;
}
int
ext4_claim_free_blocks
(
struct
ext4_sb_info
*
sbi
,
s64
nblocks
)
{
...
...
@@ -1702,313 +679,6 @@ int ext4_should_retry_alloc(struct super_block *sb, int *retries)
return
jbd2_journal_force_commit_nested
(
EXT4_SB
(
sb
)
->
s_journal
);
}
/**
* ext4_old_new_blocks() -- core block bitmap based block allocation function
*
* @handle: handle to this transaction
* @inode: file inode
* @goal: given target block(filesystem wide)
* @count: target number of blocks to allocate
* @errp: error code
*
* ext4_old_new_blocks uses a goal block to assist allocation and look up
* the block bitmap directly to do block allocation. It tries to
* allocate block(s) from the block group contains the goal block first. If
* that fails, it will try to allocate block(s) from other block groups
* without any specific goal block.
*
* This function is called when -o nomballoc mount option is enabled
*
*/
ext4_fsblk_t
ext4_old_new_blocks
(
handle_t
*
handle
,
struct
inode
*
inode
,
ext4_fsblk_t
goal
,
unsigned
long
*
count
,
int
*
errp
)
{
struct
buffer_head
*
bitmap_bh
=
NULL
;
struct
buffer_head
*
gdp_bh
;
ext4_group_t
group_no
;
ext4_group_t
goal_group
;
ext4_grpblk_t
grp_target_blk
;
/* blockgroup relative goal block */
ext4_grpblk_t
grp_alloc_blk
;
/* blockgroup-relative allocated block*/
ext4_fsblk_t
ret_block
;
/* filesyetem-wide allocated block */
ext4_group_t
bgi
;
/* blockgroup iteration index */
int
fatal
=
0
,
err
;
int
performed_allocation
=
0
;
ext4_grpblk_t
free_blocks
;
/* number of free blocks in a group */
struct
super_block
*
sb
;
struct
ext4_group_desc
*
gdp
;
struct
ext4_super_block
*
es
;
struct
ext4_sb_info
*
sbi
;
struct
ext4_reserve_window_node
*
my_rsv
=
NULL
;
struct
ext4_block_alloc_info
*
block_i
;
unsigned
short
windowsz
=
0
;
ext4_group_t
ngroups
;
unsigned
long
num
=
*
count
;
sb
=
inode
->
i_sb
;
if
(
!
sb
)
{
*
errp
=
-
ENODEV
;
printk
(
KERN_ERR
"ext4_new_block: nonexistent superblock"
);
return
0
;
}
sbi
=
EXT4_SB
(
sb
);
if
(
!
EXT4_I
(
inode
)
->
i_delalloc_reserved_flag
)
{
/*
* With delalloc we already reserved the blocks
*/
while
(
*
count
&&
ext4_claim_free_blocks
(
sbi
,
*
count
))
{
/* let others to free the space */
yield
();
*
count
=
*
count
>>
1
;
}
if
(
!*
count
)
{
*
errp
=
-
ENOSPC
;
return
0
;
/*return with ENOSPC error */
}
num
=
*
count
;
}
/*
* Check quota for allocation of this block.
*/
if
(
DQUOT_ALLOC_BLOCK
(
inode
,
num
))
{
*
errp
=
-
EDQUOT
;
return
0
;
}
sbi
=
EXT4_SB
(
sb
);
es
=
EXT4_SB
(
sb
)
->
s_es
;
ext4_debug
(
"goal=%llu.
\n
"
,
goal
);
/*
* Allocate a block from reservation only when
* filesystem is mounted with reservation(default,-o reservation), and
* it's a regular file, and
* the desired window size is greater than 0 (One could use ioctl
* command EXT4_IOC_SETRSVSZ to set the window size to 0 to turn off
* reservation on that particular file)
*/
block_i
=
EXT4_I
(
inode
)
->
i_block_alloc_info
;
if
(
block_i
&&
((
windowsz
=
block_i
->
rsv_window_node
.
rsv_goal_size
)
>
0
))
my_rsv
=
&
block_i
->
rsv_window_node
;
/*
* First, test whether the goal block is free.
*/
if
(
goal
<
le32_to_cpu
(
es
->
s_first_data_block
)
||
goal
>=
ext4_blocks_count
(
es
))
goal
=
le32_to_cpu
(
es
->
s_first_data_block
);
ext4_get_group_no_and_offset
(
sb
,
goal
,
&
group_no
,
&
grp_target_blk
);
goal_group
=
group_no
;
retry_alloc:
gdp
=
ext4_get_group_desc
(
sb
,
group_no
,
&
gdp_bh
);
if
(
!
gdp
)
goto
io_error
;
free_blocks
=
le16_to_cpu
(
gdp
->
bg_free_blocks_count
);
if
(
free_blocks
>
0
)
{
/*
* try to allocate with group target block
* in the goal group. If we have low free_blocks
* count turn off reservation
*/
if
(
my_rsv
&&
(
free_blocks
<
windowsz
)
&&
(
rsv_is_empty
(
&
my_rsv
->
rsv_window
)))
my_rsv
=
NULL
;
bitmap_bh
=
ext4_read_block_bitmap
(
sb
,
group_no
);
if
(
!
bitmap_bh
)
goto
io_error
;
grp_alloc_blk
=
ext4_try_to_allocate_with_rsv
(
sb
,
handle
,
group_no
,
bitmap_bh
,
grp_target_blk
,
my_rsv
,
&
num
,
&
fatal
);
if
(
fatal
)
goto
out
;
if
(
grp_alloc_blk
>=
0
)
goto
allocated
;
}
ngroups
=
EXT4_SB
(
sb
)
->
s_groups_count
;
smp_rmb
();
/*
* Now search the rest of the groups. We assume that
* group_no and gdp correctly point to the last group visited.
*/
for
(
bgi
=
0
;
bgi
<
ngroups
;
bgi
++
)
{
group_no
++
;
if
(
group_no
>=
ngroups
)
group_no
=
0
;
gdp
=
ext4_get_group_desc
(
sb
,
group_no
,
&
gdp_bh
);
if
(
!
gdp
)
goto
io_error
;
free_blocks
=
le16_to_cpu
(
gdp
->
bg_free_blocks_count
);
/*
* skip this group if the number of
* free blocks is less than half of the reservation
* window size.
*/
if
(
my_rsv
&&
(
free_blocks
<=
(
windowsz
/
2
)))
continue
;
brelse
(
bitmap_bh
);
bitmap_bh
=
ext4_read_block_bitmap
(
sb
,
group_no
);
if
(
!
bitmap_bh
)
goto
io_error
;
/*
* try to allocate block(s) from this group, without a goal(-1).
*/
grp_alloc_blk
=
ext4_try_to_allocate_with_rsv
(
sb
,
handle
,
group_no
,
bitmap_bh
,
-
1
,
my_rsv
,
&
num
,
&
fatal
);
if
(
fatal
)
goto
out
;
if
(
grp_alloc_blk
>=
0
)
goto
allocated
;
}
/*
* We may end up a bogus ealier ENOSPC error due to
* filesystem is "full" of reservations, but
* there maybe indeed free blocks avaliable on disk
* In this case, we just forget about the reservations
* just do block allocation as without reservations.
*/
if
(
my_rsv
)
{
my_rsv
=
NULL
;
windowsz
=
0
;
group_no
=
goal_group
;
goto
retry_alloc
;
}
/* No space left on the device */
*
errp
=
-
ENOSPC
;
goto
out
;
allocated:
ext4_debug
(
"using block group %lu(%d)
\n
"
,
group_no
,
gdp
->
bg_free_blocks_count
);
BUFFER_TRACE
(
gdp_bh
,
"get_write_access"
);
fatal
=
ext4_journal_get_write_access
(
handle
,
gdp_bh
);
if
(
fatal
)
goto
out
;
ret_block
=
grp_alloc_blk
+
ext4_group_first_block_no
(
sb
,
group_no
);
if
(
in_range
(
ext4_block_bitmap
(
sb
,
gdp
),
ret_block
,
num
)
||
in_range
(
ext4_inode_bitmap
(
sb
,
gdp
),
ret_block
,
num
)
||
in_range
(
ret_block
,
ext4_inode_table
(
sb
,
gdp
),
EXT4_SB
(
sb
)
->
s_itb_per_group
)
||
in_range
(
ret_block
+
num
-
1
,
ext4_inode_table
(
sb
,
gdp
),
EXT4_SB
(
sb
)
->
s_itb_per_group
))
{
ext4_error
(
sb
,
"ext4_new_block"
,
"Allocating block in system zone - "
"blocks from %llu, length %lu"
,
ret_block
,
num
);
/*
* claim_block marked the blocks we allocated
* as in use. So we may want to selectively
* mark some of the blocks as free
*/
goto
retry_alloc
;
}
performed_allocation
=
1
;
#ifdef CONFIG_JBD2_DEBUG
{
struct
buffer_head
*
debug_bh
;
/* Record bitmap buffer state in the newly allocated block */
debug_bh
=
sb_find_get_block
(
sb
,
ret_block
);
if
(
debug_bh
)
{
BUFFER_TRACE
(
debug_bh
,
"state when allocated"
);
BUFFER_TRACE2
(
debug_bh
,
bitmap_bh
,
"bitmap state"
);
brelse
(
debug_bh
);
}
}
jbd_lock_bh_state
(
bitmap_bh
);
spin_lock
(
sb_bgl_lock
(
sbi
,
group_no
));
if
(
buffer_jbd
(
bitmap_bh
)
&&
bh2jh
(
bitmap_bh
)
->
b_committed_data
)
{
int
i
;
for
(
i
=
0
;
i
<
num
;
i
++
)
{
if
(
ext4_test_bit
(
grp_alloc_blk
+
i
,
bh2jh
(
bitmap_bh
)
->
b_committed_data
))
{
printk
(
KERN_ERR
"%s: block was unexpectedly "
"set in b_committed_data
\n
"
,
__func__
);
}
}
}
ext4_debug
(
"found bit %d
\n
"
,
grp_alloc_blk
);
spin_unlock
(
sb_bgl_lock
(
sbi
,
group_no
));
jbd_unlock_bh_state
(
bitmap_bh
);
#endif
if
(
ret_block
+
num
-
1
>=
ext4_blocks_count
(
es
))
{
ext4_error
(
sb
,
"ext4_new_block"
,
"block(%llu) >= blocks count(%llu) - "
"block_group = %lu, es == %p "
,
ret_block
,
ext4_blocks_count
(
es
),
group_no
,
es
);
goto
out
;
}
/*
* It is up to the caller to add the new buffer to a journal
* list of some description. We don't know in advance whether
* the caller wants to use it as metadata or data.
*/
spin_lock
(
sb_bgl_lock
(
sbi
,
group_no
));
if
(
gdp
->
bg_flags
&
cpu_to_le16
(
EXT4_BG_BLOCK_UNINIT
))
gdp
->
bg_flags
&=
cpu_to_le16
(
~
EXT4_BG_BLOCK_UNINIT
);
le16_add_cpu
(
&
gdp
->
bg_free_blocks_count
,
-
num
);
gdp
->
bg_checksum
=
ext4_group_desc_csum
(
sbi
,
group_no
,
gdp
);
spin_unlock
(
sb_bgl_lock
(
sbi
,
group_no
));
percpu_counter_sub
(
&
sbi
->
s_freeblocks_counter
,
num
);
/*
* Now reduce the dirty block count also. Should not go negative
*/
if
(
!
EXT4_I
(
inode
)
->
i_delalloc_reserved_flag
)
percpu_counter_sub
(
&
sbi
->
s_dirtyblocks_counter
,
*
count
);
else
percpu_counter_sub
(
&
sbi
->
s_dirtyblocks_counter
,
num
);
if
(
sbi
->
s_log_groups_per_flex
)
{
ext4_group_t
flex_group
=
ext4_flex_group
(
sbi
,
group_no
);
spin_lock
(
sb_bgl_lock
(
sbi
,
flex_group
));
sbi
->
s_flex_groups
[
flex_group
].
free_blocks
-=
num
;
spin_unlock
(
sb_bgl_lock
(
sbi
,
flex_group
));
}
BUFFER_TRACE
(
gdp_bh
,
"journal_dirty_metadata for group descriptor"
);
err
=
ext4_journal_dirty_metadata
(
handle
,
gdp_bh
);
if
(
!
fatal
)
fatal
=
err
;
sb
->
s_dirt
=
1
;
if
(
fatal
)
goto
out
;
*
errp
=
0
;
brelse
(
bitmap_bh
);
DQUOT_FREE_BLOCK
(
inode
,
*
count
-
num
);
*
count
=
num
;
return
ret_block
;
io_error:
*
errp
=
-
EIO
;
out:
if
(
fatal
)
{
*
errp
=
fatal
;
ext4_std_error
(
sb
,
fatal
);
}
/*
* Undo the block allocation
*/
if
(
!
performed_allocation
)
DQUOT_FREE_BLOCK
(
inode
,
*
count
);
brelse
(
bitmap_bh
);
return
0
;
}
#define EXT4_META_BLOCK 0x1
static
ext4_fsblk_t
do_blk_alloc
(
handle_t
*
handle
,
struct
inode
*
inode
,
...
...
@@ -2018,10 +688,6 @@ static ext4_fsblk_t do_blk_alloc(handle_t *handle, struct inode *inode,
struct
ext4_allocation_request
ar
;
ext4_fsblk_t
ret
;
if
(
!
test_opt
(
inode
->
i_sb
,
MBALLOC
))
{
return
ext4_old_new_blocks
(
handle
,
inode
,
goal
,
count
,
errp
);
}
memset
(
&
ar
,
0
,
sizeof
(
ar
));
/* Fill with neighbour allocated blocks */
...
...
@@ -2242,3 +908,4 @@ unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group)
return
ext4_bg_num_gdb_meta
(
sb
,
group
);
}
fs/ext4/ext4.h
View file @
c2ea3fde
...
...
@@ -539,7 +539,6 @@ do { \
#define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000
/* Journal checksums */
#define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000
/* Journal Async Commit */
#define EXT4_MOUNT_I_VERSION 0x2000000
/* i_version support */
#define EXT4_MOUNT_MBALLOC 0x4000000
/* Buddy allocation support */
#define EXT4_MOUNT_DELALLOC 0x8000000
/* Delalloc support */
/* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */
#ifndef _LINUX_EXT2_FS_H
...
...
@@ -1002,8 +1001,6 @@ extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
extern
ext4_fsblk_t
ext4_new_blocks
(
handle_t
*
handle
,
struct
inode
*
inode
,
ext4_lblk_t
iblock
,
ext4_fsblk_t
goal
,
unsigned
long
*
count
,
int
*
errp
);
extern
ext4_fsblk_t
ext4_old_new_blocks
(
handle_t
*
handle
,
struct
inode
*
inode
,
ext4_fsblk_t
goal
,
unsigned
long
*
count
,
int
*
errp
);
extern
int
ext4_claim_free_blocks
(
struct
ext4_sb_info
*
sbi
,
s64
nblocks
);
extern
ext4_fsblk_t
ext4_has_free_blocks
(
struct
ext4_sb_info
*
sbi
,
s64
nblocks
);
...
...
@@ -1018,8 +1015,6 @@ extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
ext4_group_t
block_group
,
struct
buffer_head
**
bh
);
extern
int
ext4_should_retry_alloc
(
struct
super_block
*
sb
,
int
*
retries
);
extern
void
ext4_init_block_alloc_info
(
struct
inode
*
);
extern
void
ext4_rsv_window_add
(
struct
super_block
*
sb
,
struct
ext4_reserve_window_node
*
rsv
);
/* dir.c */
extern
int
ext4_check_dir_entry
(
const
char
*
,
struct
inode
*
,
...
...
@@ -1054,7 +1049,7 @@ extern int ext4_mb_release(struct super_block *);
extern
ext4_fsblk_t
ext4_mb_new_blocks
(
handle_t
*
,
struct
ext4_allocation_request
*
,
int
*
);
extern
int
ext4_mb_reserve_blocks
(
struct
super_block
*
,
int
);
extern
void
ext4_
mb_discard_inode
_preallocations
(
struct
inode
*
);
extern
void
ext4_
discard
_preallocations
(
struct
inode
*
);
extern
int
__init
init_ext4_mballoc
(
void
);
extern
void
exit_ext4_mballoc
(
void
);
extern
void
ext4_mb_free_blocks
(
handle_t
*
,
struct
inode
*
,
...
...
@@ -1084,7 +1079,6 @@ extern int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct
kstat
*
stat
);
extern
void
ext4_delete_inode
(
struct
inode
*
);
extern
int
ext4_sync_inode
(
handle_t
*
,
struct
inode
*
);
extern
void
ext4_discard_reservation
(
struct
inode
*
);
extern
void
ext4_dirty_inode
(
struct
inode
*
);
extern
int
ext4_change_inode_journal_flag
(
struct
inode
*
,
int
);
extern
int
ext4_get_inode_loc
(
struct
inode
*
,
struct
ext4_iloc
*
);
...
...
fs/ext4/ext4_i.h
View file @
c2ea3fde
...
...
@@ -33,38 +33,6 @@ typedef __u32 ext4_lblk_t;
/* data type for block group number */
typedef
unsigned
long
ext4_group_t
;
struct
ext4_reserve_window
{
ext4_fsblk_t
_rsv_start
;
/* First byte reserved */
ext4_fsblk_t
_rsv_end
;
/* Last byte reserved or 0 */
};
struct
ext4_reserve_window_node
{
struct
rb_node
rsv_node
;
__u32
rsv_goal_size
;
__u32
rsv_alloc_hit
;
struct
ext4_reserve_window
rsv_window
;
};
struct
ext4_block_alloc_info
{
/* information about reservation window */
struct
ext4_reserve_window_node
rsv_window_node
;
/*
* was i_next_alloc_block in ext4_inode_info
* is the logical (file-relative) number of the
* most-recently-allocated block in this file.
* We use this for detecting linearly ascending allocation requests.
*/
ext4_lblk_t
last_alloc_logical_block
;
/*
* Was i_next_alloc_goal in ext4_inode_info
* is the *physical* companion to i_next_alloc_block.
* it the physical block number of the block which was most-recentl
* allocated to this file. This give us the goal (target) for the next
* allocation when we detect linearly ascending requests.
*/
ext4_fsblk_t
last_alloc_physical_block
;
};
#define rsv_start rsv_window._rsv_start
#define rsv_end rsv_window._rsv_end
...
...
@@ -97,9 +65,6 @@ struct ext4_inode_info {
ext4_group_t
i_block_group
;
__u32
i_state
;
/* Dynamic state flags for ext4 */
/* block reservation info */
struct
ext4_block_alloc_info
*
i_block_alloc_info
;
ext4_lblk_t
i_dir_start_lookup
;
#ifdef CONFIG_EXT4DEV_FS_XATTR
/*
...
...
fs/ext4/ext4_sb.h
View file @
c2ea3fde
...
...
@@ -67,7 +67,6 @@ struct ext4_sb_info {
/* root of the per fs reservation window tree */
spinlock_t
s_rsv_window_lock
;
struct
rb_root
s_rsv_window_root
;
struct
ext4_reserve_window_node
s_rsv_window_head
;
/* Journaling */
struct
inode
*
s_journal_inode
;
...
...
fs/ext4/extents.c
View file @
c2ea3fde
...
...
@@ -2697,11 +2697,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
goto
out2
;
}
/*
* Okay, we need to do block allocation. Lazily initialize the block
* allocation info here if necessary.
* Okay, we need to do block allocation.
*/
if
(
S_ISREG
(
inode
->
i_mode
)
&&
(
!
EXT4_I
(
inode
)
->
i_block_alloc_info
))
ext4_init_block_alloc_info
(
inode
);
/* find neighbour allocated blocks */
ar
.
lleft
=
iblock
;
...
...
@@ -2761,7 +2758,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
/* free data blocks we just allocated */
/* not a good idea to call discard here directly,
* but otherwise we'd need to call it every free() */
ext4_
mb_discard_inode
_preallocations
(
inode
);
ext4_
discard
_preallocations
(
inode
);
ext4_free_blocks
(
handle
,
inode
,
ext_pblock
(
&
newex
),
ext4_ext_get_actual_len
(
&
newex
),
0
);
goto
out2
;
...
...
@@ -2825,7 +2822,7 @@ void ext4_ext_truncate(struct inode *inode)
down_write
(
&
EXT4_I
(
inode
)
->
i_data_sem
);
ext4_ext_invalidate_cache
(
inode
);
ext4_discard_
reservation
(
inode
);
ext4_discard_
preallocations
(
inode
);
/*
* TODO: optimization is possible here.
...
...
fs/ext4/file.c
View file @
c2ea3fde
...
...
@@ -38,7 +38,7 @@ static int ext4_release_file(struct inode *inode, struct file *filp)
(
atomic_read
(
&
inode
->
i_writecount
)
==
1
))
{
down_write
(
&
EXT4_I
(
inode
)
->
i_data_sem
);
ext4_discard_
reservation
(
inode
);
ext4_discard_
preallocations
(
inode
);
up_write
(
&
EXT4_I
(
inode
)
->
i_data_sem
);
}
if
(
is_dx
(
inode
)
&&
filp
->
private_data
)
...
...
fs/ext4/ialloc.c
View file @
c2ea3fde
...
...
@@ -817,7 +817,6 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
ei
->
i_flags
&=
~
EXT4_DIRSYNC_FL
;
ei
->
i_file_acl
=
0
;
ei
->
i_dtime
=
0
;
ei
->
i_block_alloc_info
=
NULL
;
ei
->
i_block_group
=
group
;
ext4_set_inode_flags
(
inode
);
...
...
fs/ext4/inode.c
View file @
c2ea3fde
...
...
@@ -486,18 +486,9 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
static
ext4_fsblk_t
ext4_find_goal
(
struct
inode
*
inode
,
ext4_lblk_t
block
,
Indirect
*
partial
)
{
struct
ext4_block_alloc_info
*
block_i
;
block_i
=
EXT4_I
(
inode
)
->
i_block_alloc_info
;
/*
* try the heuristic for sequential allocation,
* failing that at least try to get decent locality.
* XXX need to get goal block from mballoc's data structures
*/
if
(
block_i
&&
(
block
==
block_i
->
last_alloc_logical_block
+
1
)
&&
(
block_i
->
last_alloc_physical_block
!=
0
))
{
return
block_i
->
last_alloc_physical_block
+
1
;
}
return
ext4_find_near
(
inode
,
partial
);
}
...
...
@@ -757,10 +748,8 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
{
int
i
;
int
err
=
0
;
struct
ext4_block_alloc_info
*
block_i
;
ext4_fsblk_t
current_block
;
block_i
=
EXT4_I
(
inode
)
->
i_block_alloc_info
;
/*
* If we're splicing into a [td]indirect block (as opposed to the
* inode) then we need to get write access to the [td]indirect block
...
...
@@ -786,17 +775,6 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
*
(
where
->
p
+
i
)
=
cpu_to_le32
(
current_block
++
);
}
/*
* update the most recently allocated logical & physical block
* in i_block_alloc_info, to assist find the proper goal block for next
* allocation
*/
if
(
block_i
)
{
block_i
->
last_alloc_logical_block
=
block
+
blks
-
1
;
block_i
->
last_alloc_physical_block
=
le32_to_cpu
(
where
[
num
].
key
)
+
blks
-
1
;
}
/* We are done with atomic stuff, now do the rest of housekeeping */
inode
->
i_ctime
=
ext4_current_time
(
inode
);
...
...
@@ -914,12 +892,8 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
goto
cleanup
;
/*
* Okay, we need to do block allocation. Lazily initialize the block
* allocation info here if necessary
* Okay, we need to do block allocation.
*/
if
(
S_ISREG
(
inode
->
i_mode
)
&&
(
!
ei
->
i_block_alloc_info
))
ext4_init_block_alloc_info
(
inode
);
goal
=
ext4_find_goal
(
inode
,
iblock
,
partial
);
/* the number of blocks need to allocate for [d,t]indirect blocks */
...
...
@@ -3738,7 +3712,7 @@ void ext4_truncate(struct inode *inode)
*/
down_write
(
&
ei
->
i_data_sem
);
ext4_discard_
reservation
(
inode
);
ext4_discard_
preallocations
(
inode
);
/*
* The orphan list entry will now protect us from any crash which
...
...
@@ -4071,7 +4045,6 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
ei
->
i_acl
=
EXT4_ACL_NOT_CACHED
;
ei
->
i_default_acl
=
EXT4_ACL_NOT_CACHED
;
#endif
ei
->
i_block_alloc_info
=
NULL
;
ret
=
__ext4_get_inode_loc
(
inode
,
&
iloc
,
0
);
if
(
ret
<
0
)
...
...
fs/ext4/ioctl.c
View file @
c2ea3fde
...
...
@@ -23,7 +23,6 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
struct
inode
*
inode
=
filp
->
f_dentry
->
d_inode
;
struct
ext4_inode_info
*
ei
=
EXT4_I
(
inode
);
unsigned
int
flags
;
unsigned
short
rsv_window_size
;
ext4_debug
(
"cmd = %u, arg = %lu
\n
"
,
cmd
,
arg
);
...
...
@@ -190,49 +189,6 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return
ret
;
}
#endif
case
EXT4_IOC_GETRSVSZ
:
if
(
test_opt
(
inode
->
i_sb
,
RESERVATION
)
&&
S_ISREG
(
inode
->
i_mode
)
&&
ei
->
i_block_alloc_info
)
{
rsv_window_size
=
ei
->
i_block_alloc_info
->
rsv_window_node
.
rsv_goal_size
;
return
put_user
(
rsv_window_size
,
(
int
__user
*
)
arg
);
}
return
-
ENOTTY
;
case
EXT4_IOC_SETRSVSZ
:
{
int
err
;
if
(
!
test_opt
(
inode
->
i_sb
,
RESERVATION
)
||
!
S_ISREG
(
inode
->
i_mode
))
return
-
ENOTTY
;
if
(
!
is_owner_or_cap
(
inode
))
return
-
EACCES
;
if
(
get_user
(
rsv_window_size
,
(
int
__user
*
)
arg
))
return
-
EFAULT
;
err
=
mnt_want_write
(
filp
->
f_path
.
mnt
);
if
(
err
)
return
err
;
if
(
rsv_window_size
>
EXT4_MAX_RESERVE_BLOCKS
)
rsv_window_size
=
EXT4_MAX_RESERVE_BLOCKS
;
/*
* need to allocate reservation structure for this inode
* before set the window size
*/
down_write
(
&
ei
->
i_data_sem
);
if
(
!
ei
->
i_block_alloc_info
)
ext4_init_block_alloc_info
(
inode
);
if
(
ei
->
i_block_alloc_info
){
struct
ext4_reserve_window_node
*
rsv
=
&
ei
->
i_block_alloc_info
->
rsv_window_node
;
rsv
->
rsv_goal_size
=
rsv_window_size
;
}
up_write
(
&
ei
->
i_data_sem
);
mnt_drop_write
(
filp
->
f_path
.
mnt
);
return
0
;
}
case
EXT4_IOC_GROUP_EXTEND
:
{
ext4_fsblk_t
n_blocks_count
;
struct
super_block
*
sb
=
inode
->
i_sb
;
...
...
fs/ext4/mballoc.c
View file @
c2ea3fde
...
...
@@ -534,9 +534,6 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file,
void
*
buddy
;
void
*
buddy2
;
if
(
!
test_opt
(
sb
,
MBALLOC
))
return
0
;
{
static
int
mb_check_counter
;
if
(
mb_check_counter
++
%
100
!=
0
)
...
...
@@ -2487,19 +2484,14 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
unsigned
max
;
int
ret
;
if
(
!
test_opt
(
sb
,
MBALLOC
))
return
0
;
i
=
(
sb
->
s_blocksize_bits
+
2
)
*
sizeof
(
unsigned
short
);
sbi
->
s_mb_offsets
=
kmalloc
(
i
,
GFP_KERNEL
);
if
(
sbi
->
s_mb_offsets
==
NULL
)
{
clear_opt
(
sbi
->
s_mount_opt
,
MBALLOC
);
return
-
ENOMEM
;
}
sbi
->
s_mb_maxs
=
kmalloc
(
i
,
GFP_KERNEL
);
if
(
sbi
->
s_mb_maxs
==
NULL
)
{
clear_opt
(
sbi
->
s_mount_opt
,
MBALLOC
);
kfree
(
sbi
->
s_mb_maxs
);
return
-
ENOMEM
;
}
...
...
@@ -2522,7 +2514,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
/* init file for buddy data */
ret
=
ext4_mb_init_backend
(
sb
);
if
(
ret
!=
0
)
{
clear_opt
(
sbi
->
s_mount_opt
,
MBALLOC
);
kfree
(
sbi
->
s_mb_offsets
);
kfree
(
sbi
->
s_mb_maxs
);
return
ret
;
...
...
@@ -2544,7 +2535,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
sbi
->
s_locality_groups
=
alloc_percpu
(
struct
ext4_locality_group
);
if
(
sbi
->
s_locality_groups
==
NULL
)
{
clear_opt
(
sbi
->
s_mount_opt
,
MBALLOC
);
kfree
(
sbi
->
s_mb_offsets
);
kfree
(
sbi
->
s_mb_maxs
);
return
-
ENOMEM
;
...
...
@@ -2590,9 +2580,6 @@ int ext4_mb_release(struct super_block *sb)
struct
ext4_group_info
*
grinfo
;
struct
ext4_sb_info
*
sbi
=
EXT4_SB
(
sb
);
if
(
!
test_opt
(
sb
,
MBALLOC
))
return
0
;
/* release freed, non-committed blocks */
spin_lock
(
&
sbi
->
s_md_lock
);
list_splice_init
(
&
sbi
->
s_closed_transaction
,
...
...
@@ -3805,7 +3792,7 @@ ext4_mb_discard_group_preallocations(struct super_block *sb,
*
* FIXME!! Make sure it is valid at all the call sites
*/
void
ext4_
mb_discard_inode
_preallocations
(
struct
inode
*
inode
)
void
ext4_
discard
_preallocations
(
struct
inode
*
inode
)
{
struct
ext4_inode_info
*
ei
=
EXT4_I
(
inode
);
struct
super_block
*
sb
=
inode
->
i_sb
;
...
...
@@ -3817,7 +3804,7 @@ void ext4_mb_discard_inode_preallocations(struct inode *inode)
struct
ext4_buddy
e4b
;
int
err
;
if
(
!
test_opt
(
sb
,
MBALLOC
)
||
!
S_ISREG
(
inode
->
i_mode
))
{
if
(
!
S_ISREG
(
inode
->
i_mode
))
{
/*BUG_ON(!list_empty(&ei->i_prealloc_list));*/
return
;
}
...
...
@@ -4300,11 +4287,6 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
sb
=
ar
->
inode
->
i_sb
;
sbi
=
EXT4_SB
(
sb
);
if
(
!
test_opt
(
sb
,
MBALLOC
))
{
block
=
ext4_old_new_blocks
(
handle
,
ar
->
inode
,
ar
->
goal
,
&
(
ar
->
len
),
errp
);
return
block
;
}
if
(
!
EXT4_I
(
ar
->
inode
)
->
i_delalloc_reserved_flag
)
{
/*
* With delalloc we already reserved the blocks
...
...
fs/ext4/resize.c
View file @
c2ea3fde
...
...
@@ -870,11 +870,10 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
* We can allocate memory for mb_alloc based on the new group
* descriptor
*/
if
(
test_opt
(
sb
,
MBALLOC
))
{
err
=
ext4_mb_add_more_groupinfo
(
sb
,
input
->
group
,
gdp
);
if
(
err
)
goto
exit_journal
;
}
err
=
ext4_mb_add_more_groupinfo
(
sb
,
input
->
group
,
gdp
);
if
(
err
)
goto
exit_journal
;
/*
* Make the new blocks and inodes valid next. We do this before
* increasing the group count so that once the group is enabled,
...
...
@@ -1086,8 +1085,15 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
/*
* Mark mballoc pages as not up to date so that they will be updated
* next time they are loaded by ext4_mb_load_buddy.
*
* XXX Bad, Bad, BAD!!! We should not be overloading the
* Uptodate flag, particularly on thte bitmap bh, as way of
* hinting to ext4_mb_load_buddy() that it needs to be
* overloaded. A user could take a LVM snapshot, then do an
* on-line fsck, and clear the uptodate flag, and this would
* not be a bug in userspace, but a bug in the kernel. FIXME!!!
*/
if
(
test_opt
(
sb
,
MBALLOC
))
{
{
struct
ext4_sb_info
*
sbi
=
EXT4_SB
(
sb
);
struct
inode
*
inode
=
sbi
->
s_buddy_cache
;
int
blocks_per_page
;
...
...
fs/ext4/super.c
View file @
c2ea3fde
...
...
@@ -574,7 +574,6 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
ei
->
i_acl
=
EXT4_ACL_NOT_CACHED
;
ei
->
i_default_acl
=
EXT4_ACL_NOT_CACHED
;
#endif
ei
->
i_block_alloc_info
=
NULL
;
ei
->
vfs_inode
.
i_version
=
1
;
ei
->
vfs_inode
.
i_data
.
writeback_index
=
0
;
memset
(
&
ei
->
i_cached_extent
,
0
,
sizeof
(
struct
ext4_ext_cache
));
...
...
@@ -633,7 +632,6 @@ static void destroy_inodecache(void)
static
void
ext4_clear_inode
(
struct
inode
*
inode
)
{
struct
ext4_block_alloc_info
*
rsv
=
EXT4_I
(
inode
)
->
i_block_alloc_info
;
#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
if
(
EXT4_I
(
inode
)
->
i_acl
&&
EXT4_I
(
inode
)
->
i_acl
!=
EXT4_ACL_NOT_CACHED
)
{
...
...
@@ -646,10 +644,7 @@ static void ext4_clear_inode(struct inode *inode)
EXT4_I
(
inode
)
->
i_default_acl
=
EXT4_ACL_NOT_CACHED
;
}
#endif
ext4_discard_reservation
(
inode
);
EXT4_I
(
inode
)
->
i_block_alloc_info
=
NULL
;
if
(
unlikely
(
rsv
))
kfree
(
rsv
);
ext4_discard_preallocations
(
inode
);
jbd2_journal_release_jbd_inode
(
EXT4_SB
(
inode
->
i_sb
)
->
s_journal
,
&
EXT4_I
(
inode
)
->
jinode
);
}
...
...
@@ -760,8 +755,6 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
seq_puts
(
seq
,
",nobh"
);
if
(
!
test_opt
(
sb
,
EXTENTS
))
seq_puts
(
seq
,
",noextents"
);
if
(
!
test_opt
(
sb
,
MBALLOC
))
seq_puts
(
seq
,
",nomballoc"
);
if
(
test_opt
(
sb
,
I_VERSION
))
seq_puts
(
seq
,
",i_version"
);
if
(
!
test_opt
(
sb
,
DELALLOC
))
...
...
@@ -1373,12 +1366,6 @@ static int parse_options(char *options, struct super_block *sb,
case
Opt_nodelalloc
:
clear_opt
(
sbi
->
s_mount_opt
,
DELALLOC
);
break
;
case
Opt_mballoc
:
set_opt
(
sbi
->
s_mount_opt
,
MBALLOC
);
break
;
case
Opt_nomballoc
:
clear_opt
(
sbi
->
s_mount_opt
,
MBALLOC
);
break
;
case
Opt_stripe
:
if
(
match_int
(
&
args
[
0
],
&
option
))
return
0
;
...
...
@@ -2040,11 +2027,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
ext4_warning
(
sb
,
__func__
,
"extents feature not enabled on this filesystem, "
"use tune2fs.
\n
"
);
/*
* turn on mballoc code by default in ext4 filesystem
* Use -o nomballoc to turn it off
*/
set_opt
(
sbi
->
s_mount_opt
,
MBALLOC
);
/*
* enable delayed allocation by default
...
...
@@ -2301,19 +2283,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
goto
failed_mount3
;
}
/* per fileystem reservation list head & lock */
spin_lock_init
(
&
sbi
->
s_rsv_window_lock
);
sbi
->
s_rsv_window_root
=
RB_ROOT
;
/* Add a single, static dummy reservation to the start of the
* reservation window list --- it gives us a placeholder for
* append-at-start-of-list which makes the allocation logic
* _much_ simpler. */
sbi
->
s_rsv_window_head
.
rsv_start
=
EXT4_RESERVE_WINDOW_NOT_ALLOCATED
;
sbi
->
s_rsv_window_head
.
rsv_end
=
EXT4_RESERVE_WINDOW_NOT_ALLOCATED
;
sbi
->
s_rsv_window_head
.
rsv_alloc_hit
=
0
;
sbi
->
s_rsv_window_head
.
rsv_goal_size
=
0
;
ext4_rsv_window_add
(
sb
,
&
sbi
->
s_rsv_window_head
);
sbi
->
s_stripe
=
ext4_get_stripe_size
(
sbi
);
/*
...
...
@@ -2510,7 +2479,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
printk
(
KERN_INFO
"EXT4-fs: delayed allocation enabled
\n
"
);
ext4_ext_init
(
sb
);
ext4_mb_init
(
sb
,
needs_recovery
);
err
=
ext4_mb_init
(
sb
,
needs_recovery
);
if
(
err
)
{
printk
(
KERN_ERR
"EXT4-fs: failed to initalize mballoc (%d)
\n
"
,
err
);
goto
failed_mount4
;
}
lock_kernel
();
return
0
;
...
...
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