Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
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,
...
@@ -83,6 +83,7 @@ static int ext4_group_used_meta_blocks(struct super_block *sb,
}
}
return
used_blocks
;
return
used_blocks
;
}
}
/* Initializes an uninitialized block bitmap if given, and returns the
/* Initializes an uninitialized block bitmap if given, and returns the
* number of blocks free in the group. */
* number of blocks free in the group. */
unsigned
ext4_init_block_bitmap
(
struct
super_block
*
sb
,
struct
buffer_head
*
bh
,
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)
...
@@ -345,303 +346,6 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
*/
*/
return
bh
;
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
* ext4_free_blocks_sb() -- Free given blocks and update quota
...
@@ -650,6 +354,13 @@ void ext4_discard_reservation(struct inode *inode)
...
@@ -650,6 +354,13 @@ void ext4_discard_reservation(struct inode *inode)
* @block: start physcial block to free
* @block: start physcial block to free
* @count: number of blocks to free
* @count: number of blocks to free
* @pdquot_freed_blocks: pointer to quota
* @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
,
void
ext4_free_blocks_sb
(
handle_t
*
handle
,
struct
super_block
*
sb
,
ext4_fsblk_t
block
,
unsigned
long
count
,
ext4_fsblk_t
block
,
unsigned
long
count
,
...
@@ -861,747 +572,13 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
...
@@ -861,747 +572,13 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
sb
=
inode
->
i_sb
;
sb
=
inode
->
i_sb
;
if
(
!
test_opt
(
sb
,
MBALLOC
)
||
!
EXT4_SB
(
sb
)
->
s_group_info
)
ext4_mb_free_blocks
(
handle
,
inode
,
block
,
count
,
ext4_free_blocks_sb
(
handle
,
sb
,
block
,
count
,
metadata
,
&
dquot_freed_blocks
);
&
dquot_freed_blocks
);
else
ext4_mb_free_blocks
(
handle
,
inode
,
block
,
count
,
metadata
,
&
dquot_freed_blocks
);
if
(
dquot_freed_blocks
)
if
(
dquot_freed_blocks
)
DQUOT_FREE_BLOCK
(
inode
,
dquot_freed_blocks
);
DQUOT_FREE_BLOCK
(
inode
,
dquot_freed_blocks
);
return
;
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
,
int
ext4_claim_free_blocks
(
struct
ext4_sb_info
*
sbi
,
s64
nblocks
)
s64
nblocks
)
{
{
...
@@ -1702,313 +679,6 @@ int ext4_should_retry_alloc(struct super_block *sb, int *retries)
...
@@ -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
);
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
#define EXT4_META_BLOCK 0x1
static
ext4_fsblk_t
do_blk_alloc
(
handle_t
*
handle
,
struct
inode
*
inode
,
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,
...
@@ -2018,10 +688,6 @@ static ext4_fsblk_t do_blk_alloc(handle_t *handle, struct inode *inode,
struct
ext4_allocation_request
ar
;
struct
ext4_allocation_request
ar
;
ext4_fsblk_t
ret
;
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
));
memset
(
&
ar
,
0
,
sizeof
(
ar
));
/* Fill with neighbour allocated blocks */
/* Fill with neighbour allocated blocks */
...
@@ -2242,3 +908,4 @@ unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group)
...
@@ -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
);
return
ext4_bg_num_gdb_meta
(
sb
,
group
);
}
}
fs/ext4/ext4.h
View file @
c2ea3fde
...
@@ -539,7 +539,6 @@ do { \
...
@@ -539,7 +539,6 @@ do { \
#define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000
/* Journal checksums */
#define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000
/* Journal checksums */
#define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000
/* Journal Async Commit */
#define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000
/* Journal Async Commit */
#define EXT4_MOUNT_I_VERSION 0x2000000
/* i_version support */
#define EXT4_MOUNT_I_VERSION 0x2000000
/* i_version support */
#define EXT4_MOUNT_MBALLOC 0x4000000
/* Buddy allocation support */
#define EXT4_MOUNT_DELALLOC 0x8000000
/* Delalloc support */
#define EXT4_MOUNT_DELALLOC 0x8000000
/* Delalloc support */
/* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */
/* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */
#ifndef _LINUX_EXT2_FS_H
#ifndef _LINUX_EXT2_FS_H
...
@@ -1002,8 +1001,6 @@ extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
...
@@ -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
,
extern
ext4_fsblk_t
ext4_new_blocks
(
handle_t
*
handle
,
struct
inode
*
inode
,
ext4_lblk_t
iblock
,
ext4_fsblk_t
goal
,
ext4_lblk_t
iblock
,
ext4_fsblk_t
goal
,
unsigned
long
*
count
,
int
*
errp
);
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
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
,
extern
ext4_fsblk_t
ext4_has_free_blocks
(
struct
ext4_sb_info
*
sbi
,
s64
nblocks
);
s64
nblocks
);
...
@@ -1018,8 +1015,6 @@ extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
...
@@ -1018,8 +1015,6 @@ extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
ext4_group_t
block_group
,
ext4_group_t
block_group
,
struct
buffer_head
**
bh
);
struct
buffer_head
**
bh
);
extern
int
ext4_should_retry_alloc
(
struct
super_block
*
sb
,
int
*
retries
);
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 */
/* dir.c */
extern
int
ext4_check_dir_entry
(
const
char
*
,
struct
inode
*
,
extern
int
ext4_check_dir_entry
(
const
char
*
,
struct
inode
*
,
...
@@ -1054,7 +1049,7 @@ extern int ext4_mb_release(struct super_block *);
...
@@ -1054,7 +1049,7 @@ extern int ext4_mb_release(struct super_block *);
extern
ext4_fsblk_t
ext4_mb_new_blocks
(
handle_t
*
,
extern
ext4_fsblk_t
ext4_mb_new_blocks
(
handle_t
*
,
struct
ext4_allocation_request
*
,
int
*
);
struct
ext4_allocation_request
*
,
int
*
);
extern
int
ext4_mb_reserve_blocks
(
struct
super_block
*
,
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
int
__init
init_ext4_mballoc
(
void
);
extern
void
exit_ext4_mballoc
(
void
);
extern
void
exit_ext4_mballoc
(
void
);
extern
void
ext4_mb_free_blocks
(
handle_t
*
,
struct
inode
*
,
extern
void
ext4_mb_free_blocks
(
handle_t
*
,
struct
inode
*
,
...
@@ -1084,7 +1079,6 @@ extern int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
...
@@ -1084,7 +1079,6 @@ extern int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct
kstat
*
stat
);
struct
kstat
*
stat
);
extern
void
ext4_delete_inode
(
struct
inode
*
);
extern
void
ext4_delete_inode
(
struct
inode
*
);
extern
int
ext4_sync_inode
(
handle_t
*
,
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
void
ext4_dirty_inode
(
struct
inode
*
);
extern
int
ext4_change_inode_journal_flag
(
struct
inode
*
,
int
);
extern
int
ext4_change_inode_journal_flag
(
struct
inode
*
,
int
);
extern
int
ext4_get_inode_loc
(
struct
inode
*
,
struct
ext4_iloc
*
);
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;
...
@@ -33,38 +33,6 @@ typedef __u32 ext4_lblk_t;
/* data type for block group number */
/* data type for block group number */
typedef
unsigned
long
ext4_group_t
;
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_start rsv_window._rsv_start
#define rsv_end rsv_window._rsv_end
#define rsv_end rsv_window._rsv_end
...
@@ -97,9 +65,6 @@ struct ext4_inode_info {
...
@@ -97,9 +65,6 @@ struct ext4_inode_info {
ext4_group_t
i_block_group
;
ext4_group_t
i_block_group
;
__u32
i_state
;
/* Dynamic state flags for ext4 */
__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
;
ext4_lblk_t
i_dir_start_lookup
;
#ifdef CONFIG_EXT4DEV_FS_XATTR
#ifdef CONFIG_EXT4DEV_FS_XATTR
/*
/*
...
...
fs/ext4/ext4_sb.h
View file @
c2ea3fde
...
@@ -67,7 +67,6 @@ struct ext4_sb_info {
...
@@ -67,7 +67,6 @@ struct ext4_sb_info {
/* root of the per fs reservation window tree */
/* root of the per fs reservation window tree */
spinlock_t
s_rsv_window_lock
;
spinlock_t
s_rsv_window_lock
;
struct
rb_root
s_rsv_window_root
;
struct
rb_root
s_rsv_window_root
;
struct
ext4_reserve_window_node
s_rsv_window_head
;
/* Journaling */
/* Journaling */
struct
inode
*
s_journal_inode
;
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,
...
@@ -2697,11 +2697,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
goto
out2
;
goto
out2
;
}
}
/*
/*
* Okay, we need to do block allocation. Lazily initialize the block
* Okay, we need to do block allocation.
* allocation info here if necessary.
*/
*/
if
(
S_ISREG
(
inode
->
i_mode
)
&&
(
!
EXT4_I
(
inode
)
->
i_block_alloc_info
))
ext4_init_block_alloc_info
(
inode
);
/* find neighbour allocated blocks */
/* find neighbour allocated blocks */
ar
.
lleft
=
iblock
;
ar
.
lleft
=
iblock
;
...
@@ -2761,7 +2758,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
...
@@ -2761,7 +2758,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
/* free data blocks we just allocated */
/* free data blocks we just allocated */
/* not a good idea to call discard here directly,
/* not a good idea to call discard here directly,
* but otherwise we'd need to call it every free() */
* 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_free_blocks
(
handle
,
inode
,
ext_pblock
(
&
newex
),
ext4_ext_get_actual_len
(
&
newex
),
0
);
ext4_ext_get_actual_len
(
&
newex
),
0
);
goto
out2
;
goto
out2
;
...
@@ -2825,7 +2822,7 @@ void ext4_ext_truncate(struct inode *inode)
...
@@ -2825,7 +2822,7 @@ void ext4_ext_truncate(struct inode *inode)
down_write
(
&
EXT4_I
(
inode
)
->
i_data_sem
);
down_write
(
&
EXT4_I
(
inode
)
->
i_data_sem
);
ext4_ext_invalidate_cache
(
inode
);
ext4_ext_invalidate_cache
(
inode
);
ext4_discard_
reservation
(
inode
);
ext4_discard_
preallocations
(
inode
);
/*
/*
* TODO: optimization is possible here.
* 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)
...
@@ -38,7 +38,7 @@ static int ext4_release_file(struct inode *inode, struct file *filp)
(
atomic_read
(
&
inode
->
i_writecount
)
==
1
))
(
atomic_read
(
&
inode
->
i_writecount
)
==
1
))
{
{
down_write
(
&
EXT4_I
(
inode
)
->
i_data_sem
);
down_write
(
&
EXT4_I
(
inode
)
->
i_data_sem
);
ext4_discard_
reservation
(
inode
);
ext4_discard_
preallocations
(
inode
);
up_write
(
&
EXT4_I
(
inode
)
->
i_data_sem
);
up_write
(
&
EXT4_I
(
inode
)
->
i_data_sem
);
}
}
if
(
is_dx
(
inode
)
&&
filp
->
private_data
)
if
(
is_dx
(
inode
)
&&
filp
->
private_data
)
...
...
fs/ext4/ialloc.c
View file @
c2ea3fde
...
@@ -817,7 +817,6 @@ got:
...
@@ -817,7 +817,6 @@ got:
ei
->
i_flags
&=
~
EXT4_DIRSYNC_FL
;
ei
->
i_flags
&=
~
EXT4_DIRSYNC_FL
;
ei
->
i_file_acl
=
0
;
ei
->
i_file_acl
=
0
;
ei
->
i_dtime
=
0
;
ei
->
i_dtime
=
0
;
ei
->
i_block_alloc_info
=
NULL
;
ei
->
i_block_group
=
group
;
ei
->
i_block_group
=
group
;
ext4_set_inode_flags
(
inode
);
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)
...
@@ -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
,
static
ext4_fsblk_t
ext4_find_goal
(
struct
inode
*
inode
,
ext4_lblk_t
block
,
Indirect
*
partial
)
Indirect
*
partial
)
{
{
struct
ext4_block_alloc_info
*
block_i
;
block_i
=
EXT4_I
(
inode
)
->
i_block_alloc_info
;
/*
/*
* try the heuristic for sequential allocation,
* XXX need to get goal block from mballoc's data structures
* failing that at least try to get decent locality.
*/
*/
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
);
return
ext4_find_near
(
inode
,
partial
);
}
}
...
@@ -757,10 +748,8 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
...
@@ -757,10 +748,8 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
{
{
int
i
;
int
i
;
int
err
=
0
;
int
err
=
0
;
struct
ext4_block_alloc_info
*
block_i
;
ext4_fsblk_t
current_block
;
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
* 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
* 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,
...
@@ -786,17 +775,6 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
*
(
where
->
p
+
i
)
=
cpu_to_le32
(
current_block
++
);
*
(
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 */
/* We are done with atomic stuff, now do the rest of housekeeping */
inode
->
i_ctime
=
ext4_current_time
(
inode
);
inode
->
i_ctime
=
ext4_current_time
(
inode
);
...
@@ -914,12 +892,8 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
...
@@ -914,12 +892,8 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
goto
cleanup
;
goto
cleanup
;
/*
/*
* Okay, we need to do block allocation. Lazily initialize the block
* Okay, we need to do block allocation.
* allocation info here if necessary
*/
*/
if
(
S_ISREG
(
inode
->
i_mode
)
&&
(
!
ei
->
i_block_alloc_info
))
ext4_init_block_alloc_info
(
inode
);
goal
=
ext4_find_goal
(
inode
,
iblock
,
partial
);
goal
=
ext4_find_goal
(
inode
,
iblock
,
partial
);
/* the number of blocks need to allocate for [d,t]indirect blocks */
/* the number of blocks need to allocate for [d,t]indirect blocks */
...
@@ -3738,7 +3712,7 @@ void ext4_truncate(struct inode *inode)
...
@@ -3738,7 +3712,7 @@ void ext4_truncate(struct inode *inode)
*/
*/
down_write
(
&
ei
->
i_data_sem
);
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
* 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)
...
@@ -4071,7 +4045,6 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
ei
->
i_acl
=
EXT4_ACL_NOT_CACHED
;
ei
->
i_acl
=
EXT4_ACL_NOT_CACHED
;
ei
->
i_default_acl
=
EXT4_ACL_NOT_CACHED
;
ei
->
i_default_acl
=
EXT4_ACL_NOT_CACHED
;
#endif
#endif
ei
->
i_block_alloc_info
=
NULL
;
ret
=
__ext4_get_inode_loc
(
inode
,
&
iloc
,
0
);
ret
=
__ext4_get_inode_loc
(
inode
,
&
iloc
,
0
);
if
(
ret
<
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)
...
@@ -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
inode
*
inode
=
filp
->
f_dentry
->
d_inode
;
struct
ext4_inode_info
*
ei
=
EXT4_I
(
inode
);
struct
ext4_inode_info
*
ei
=
EXT4_I
(
inode
);
unsigned
int
flags
;
unsigned
int
flags
;
unsigned
short
rsv_window_size
;
ext4_debug
(
"cmd = %u, arg = %lu
\n
"
,
cmd
,
arg
);
ext4_debug
(
"cmd = %u, arg = %lu
\n
"
,
cmd
,
arg
);
...
@@ -190,49 +189,6 @@ setversion_out:
...
@@ -190,49 +189,6 @@ setversion_out:
return
ret
;
return
ret
;
}
}
#endif
#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
:
{
case
EXT4_IOC_GROUP_EXTEND
:
{
ext4_fsblk_t
n_blocks_count
;
ext4_fsblk_t
n_blocks_count
;
struct
super_block
*
sb
=
inode
->
i_sb
;
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,
...
@@ -534,9 +534,6 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file,
void
*
buddy
;
void
*
buddy
;
void
*
buddy2
;
void
*
buddy2
;
if
(
!
test_opt
(
sb
,
MBALLOC
))
return
0
;
{
{
static
int
mb_check_counter
;
static
int
mb_check_counter
;
if
(
mb_check_counter
++
%
100
!=
0
)
if
(
mb_check_counter
++
%
100
!=
0
)
...
@@ -2487,19 +2484,14 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
...
@@ -2487,19 +2484,14 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
unsigned
max
;
unsigned
max
;
int
ret
;
int
ret
;
if
(
!
test_opt
(
sb
,
MBALLOC
))
return
0
;
i
=
(
sb
->
s_blocksize_bits
+
2
)
*
sizeof
(
unsigned
short
);
i
=
(
sb
->
s_blocksize_bits
+
2
)
*
sizeof
(
unsigned
short
);
sbi
->
s_mb_offsets
=
kmalloc
(
i
,
GFP_KERNEL
);
sbi
->
s_mb_offsets
=
kmalloc
(
i
,
GFP_KERNEL
);
if
(
sbi
->
s_mb_offsets
==
NULL
)
{
if
(
sbi
->
s_mb_offsets
==
NULL
)
{
clear_opt
(
sbi
->
s_mount_opt
,
MBALLOC
);
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
sbi
->
s_mb_maxs
=
kmalloc
(
i
,
GFP_KERNEL
);
sbi
->
s_mb_maxs
=
kmalloc
(
i
,
GFP_KERNEL
);
if
(
sbi
->
s_mb_maxs
==
NULL
)
{
if
(
sbi
->
s_mb_maxs
==
NULL
)
{
clear_opt
(
sbi
->
s_mount_opt
,
MBALLOC
);
kfree
(
sbi
->
s_mb_maxs
);
kfree
(
sbi
->
s_mb_maxs
);
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
...
@@ -2522,7 +2514,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
...
@@ -2522,7 +2514,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
/* init file for buddy data */
/* init file for buddy data */
ret
=
ext4_mb_init_backend
(
sb
);
ret
=
ext4_mb_init_backend
(
sb
);
if
(
ret
!=
0
)
{
if
(
ret
!=
0
)
{
clear_opt
(
sbi
->
s_mount_opt
,
MBALLOC
);
kfree
(
sbi
->
s_mb_offsets
);
kfree
(
sbi
->
s_mb_offsets
);
kfree
(
sbi
->
s_mb_maxs
);
kfree
(
sbi
->
s_mb_maxs
);
return
ret
;
return
ret
;
...
@@ -2544,7 +2535,6 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery)
...
@@ -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
);
sbi
->
s_locality_groups
=
alloc_percpu
(
struct
ext4_locality_group
);
if
(
sbi
->
s_locality_groups
==
NULL
)
{
if
(
sbi
->
s_locality_groups
==
NULL
)
{
clear_opt
(
sbi
->
s_mount_opt
,
MBALLOC
);
kfree
(
sbi
->
s_mb_offsets
);
kfree
(
sbi
->
s_mb_offsets
);
kfree
(
sbi
->
s_mb_maxs
);
kfree
(
sbi
->
s_mb_maxs
);
return
-
ENOMEM
;
return
-
ENOMEM
;
...
@@ -2590,9 +2580,6 @@ int ext4_mb_release(struct super_block *sb)
...
@@ -2590,9 +2580,6 @@ int ext4_mb_release(struct super_block *sb)
struct
ext4_group_info
*
grinfo
;
struct
ext4_group_info
*
grinfo
;
struct
ext4_sb_info
*
sbi
=
EXT4_SB
(
sb
);
struct
ext4_sb_info
*
sbi
=
EXT4_SB
(
sb
);
if
(
!
test_opt
(
sb
,
MBALLOC
))
return
0
;
/* release freed, non-committed blocks */
/* release freed, non-committed blocks */
spin_lock
(
&
sbi
->
s_md_lock
);
spin_lock
(
&
sbi
->
s_md_lock
);
list_splice_init
(
&
sbi
->
s_closed_transaction
,
list_splice_init
(
&
sbi
->
s_closed_transaction
,
...
@@ -3805,7 +3792,7 @@ out:
...
@@ -3805,7 +3792,7 @@ out:
*
*
* FIXME!! Make sure it is valid at all the call sites
* 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
ext4_inode_info
*
ei
=
EXT4_I
(
inode
);
struct
super_block
*
sb
=
inode
->
i_sb
;
struct
super_block
*
sb
=
inode
->
i_sb
;
...
@@ -3817,7 +3804,7 @@ void ext4_mb_discard_inode_preallocations(struct inode *inode)
...
@@ -3817,7 +3804,7 @@ void ext4_mb_discard_inode_preallocations(struct inode *inode)
struct
ext4_buddy
e4b
;
struct
ext4_buddy
e4b
;
int
err
;
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));*/
/*BUG_ON(!list_empty(&ei->i_prealloc_list));*/
return
;
return
;
}
}
...
@@ -4300,11 +4287,6 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
...
@@ -4300,11 +4287,6 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
sb
=
ar
->
inode
->
i_sb
;
sb
=
ar
->
inode
->
i_sb
;
sbi
=
EXT4_SB
(
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
)
{
if
(
!
EXT4_I
(
ar
->
inode
)
->
i_delalloc_reserved_flag
)
{
/*
/*
* With delalloc we already reserved the blocks
* 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)
...
@@ -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
* We can allocate memory for mb_alloc based on the new group
* descriptor
* descriptor
*/
*/
if
(
test_opt
(
sb
,
MBALLOC
))
{
err
=
ext4_mb_add_more_groupinfo
(
sb
,
input
->
group
,
gdp
);
err
=
ext4_mb_add_more_groupinfo
(
sb
,
input
->
group
,
gdp
);
if
(
err
)
if
(
err
)
goto
exit_journal
;
goto
exit_journal
;
}
/*
/*
* Make the new blocks and inodes valid next. We do this before
* Make the new blocks and inodes valid next. We do this before
* increasing the group count so that once the group is enabled,
* 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,
...
@@ -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
* Mark mballoc pages as not up to date so that they will be updated
* next time they are loaded by ext4_mb_load_buddy.
* 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
ext4_sb_info
*
sbi
=
EXT4_SB
(
sb
);
struct
inode
*
inode
=
sbi
->
s_buddy_cache
;
struct
inode
*
inode
=
sbi
->
s_buddy_cache
;
int
blocks_per_page
;
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)
...
@@ -574,7 +574,6 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
ei
->
i_acl
=
EXT4_ACL_NOT_CACHED
;
ei
->
i_acl
=
EXT4_ACL_NOT_CACHED
;
ei
->
i_default_acl
=
EXT4_ACL_NOT_CACHED
;
ei
->
i_default_acl
=
EXT4_ACL_NOT_CACHED
;
#endif
#endif
ei
->
i_block_alloc_info
=
NULL
;
ei
->
vfs_inode
.
i_version
=
1
;
ei
->
vfs_inode
.
i_version
=
1
;
ei
->
vfs_inode
.
i_data
.
writeback_index
=
0
;
ei
->
vfs_inode
.
i_data
.
writeback_index
=
0
;
memset
(
&
ei
->
i_cached_extent
,
0
,
sizeof
(
struct
ext4_ext_cache
));
memset
(
&
ei
->
i_cached_extent
,
0
,
sizeof
(
struct
ext4_ext_cache
));
...
@@ -633,7 +632,6 @@ static void destroy_inodecache(void)
...
@@ -633,7 +632,6 @@ static void destroy_inodecache(void)
static
void
ext4_clear_inode
(
struct
inode
*
inode
)
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
#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
if
(
EXT4_I
(
inode
)
->
i_acl
&&
if
(
EXT4_I
(
inode
)
->
i_acl
&&
EXT4_I
(
inode
)
->
i_acl
!=
EXT4_ACL_NOT_CACHED
)
{
EXT4_I
(
inode
)
->
i_acl
!=
EXT4_ACL_NOT_CACHED
)
{
...
@@ -646,10 +644,7 @@ static void ext4_clear_inode(struct inode *inode)
...
@@ -646,10 +644,7 @@ static void ext4_clear_inode(struct inode *inode)
EXT4_I
(
inode
)
->
i_default_acl
=
EXT4_ACL_NOT_CACHED
;
EXT4_I
(
inode
)
->
i_default_acl
=
EXT4_ACL_NOT_CACHED
;
}
}
#endif
#endif
ext4_discard_reservation
(
inode
);
ext4_discard_preallocations
(
inode
);
EXT4_I
(
inode
)
->
i_block_alloc_info
=
NULL
;
if
(
unlikely
(
rsv
))
kfree
(
rsv
);
jbd2_journal_release_jbd_inode
(
EXT4_SB
(
inode
->
i_sb
)
->
s_journal
,
jbd2_journal_release_jbd_inode
(
EXT4_SB
(
inode
->
i_sb
)
->
s_journal
,
&
EXT4_I
(
inode
)
->
jinode
);
&
EXT4_I
(
inode
)
->
jinode
);
}
}
...
@@ -760,8 +755,6 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
...
@@ -760,8 +755,6 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
seq_puts
(
seq
,
",nobh"
);
seq_puts
(
seq
,
",nobh"
);
if
(
!
test_opt
(
sb
,
EXTENTS
))
if
(
!
test_opt
(
sb
,
EXTENTS
))
seq_puts
(
seq
,
",noextents"
);
seq_puts
(
seq
,
",noextents"
);
if
(
!
test_opt
(
sb
,
MBALLOC
))
seq_puts
(
seq
,
",nomballoc"
);
if
(
test_opt
(
sb
,
I_VERSION
))
if
(
test_opt
(
sb
,
I_VERSION
))
seq_puts
(
seq
,
",i_version"
);
seq_puts
(
seq
,
",i_version"
);
if
(
!
test_opt
(
sb
,
DELALLOC
))
if
(
!
test_opt
(
sb
,
DELALLOC
))
...
@@ -1373,12 +1366,6 @@ set_qf_format:
...
@@ -1373,12 +1366,6 @@ set_qf_format:
case
Opt_nodelalloc
:
case
Opt_nodelalloc
:
clear_opt
(
sbi
->
s_mount_opt
,
DELALLOC
);
clear_opt
(
sbi
->
s_mount_opt
,
DELALLOC
);
break
;
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
:
case
Opt_stripe
:
if
(
match_int
(
&
args
[
0
],
&
option
))
if
(
match_int
(
&
args
[
0
],
&
option
))
return
0
;
return
0
;
...
@@ -2040,11 +2027,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
...
@@ -2040,11 +2027,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
ext4_warning
(
sb
,
__func__
,
ext4_warning
(
sb
,
__func__
,
"extents feature not enabled on this filesystem, "
"extents feature not enabled on this filesystem, "
"use tune2fs.
\n
"
);
"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
* enable delayed allocation by default
...
@@ -2301,19 +2283,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
...
@@ -2301,19 +2283,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
goto
failed_mount3
;
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
);
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)
...
@@ -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
"
);
printk
(
KERN_INFO
"EXT4-fs: delayed allocation enabled
\n
"
);
ext4_ext_init
(
sb
);
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
();
lock_kernel
();
return
0
;
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