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
5906f819
Commit
5906f819
authored
Feb 19, 2003
by
Stephen Lord
Committed by
Christoph Hellwig
Feb 19, 2003
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[XFS] cleanup delayed allocate write path a little and fix some
small bugs in there. SGI Modid: 2.5.x-xfs:slinx:138445a
parent
7685cc34
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
168 additions
and
82 deletions
+168
-82
fs/xfs/linux/xfs_aops.c
fs/xfs/linux/xfs_aops.c
+161
-81
fs/xfs/linux/xfs_iomap.c
fs/xfs/linux/xfs_iomap.c
+7
-1
No files found.
fs/xfs/linux/xfs_aops.c
View file @
5906f819
...
@@ -53,12 +53,15 @@ map_blocks(
...
@@ -53,12 +53,15 @@ map_blocks(
count
=
max_t
(
ssize_t
,
count
,
XFS_WRITE_IO_LOG
);
count
=
max_t
(
ssize_t
,
count
,
XFS_WRITE_IO_LOG
);
retry:
retry:
VOP_BMAP
(
vp
,
offset
,
count
,
flags
,
pbmapp
,
&
nmaps
,
error
);
VOP_BMAP
(
vp
,
offset
,
count
,
flags
,
pbmapp
,
&
nmaps
,
error
);
if
(
flags
&
PBF_WRITE
)
{
if
(
error
==
EAGAIN
)
if
(
unlikely
((
flags
&
PBF_DIRECT
)
&&
nmaps
&&
return
-
error
;
(
pbmapp
->
pbm_flags
&
PBMF_DELAY
)))
{
if
(
unlikely
((
flags
&
(
PBF_WRITE
|
PBF_DIRECT
))
==
flags
=
PBF_FILE_ALLOCATE
;
(
PBF_WRITE
|
PBF_DIRECT
)
&&
nmaps
&&
goto
retry
;
(
pbmapp
->
pbm_flags
&
PBMF_DELAY
)))
{
}
flags
=
PBF_FILE_ALLOCATE
;
goto
retry
;
}
if
(
flags
&
(
PBF_WRITE
|
PBF_FILE_ALLOCATE
))
{
VMODIFY
(
vp
);
VMODIFY
(
vp
);
}
}
return
-
error
;
return
-
error
;
...
@@ -309,6 +312,7 @@ convert_page(
...
@@ -309,6 +312,7 @@ convert_page(
if
(
startio
&&
(
offset
<
end
))
{
if
(
startio
&&
(
offset
<
end
))
{
bh_arr
[
index
++
]
=
bh
;
bh_arr
[
index
++
]
=
bh
;
}
else
{
}
else
{
set_buffer_dirty
(
bh
);
unlock_buffer
(
bh
);
unlock_buffer
(
bh
);
}
}
}
while
(
i
++
,
(
bh
=
bh
->
b_this_page
)
!=
head
);
}
while
(
i
++
,
(
bh
=
bh
->
b_this_page
)
!=
head
);
...
@@ -365,9 +369,9 @@ cluster_write(
...
@@ -365,9 +369,9 @@ cluster_write(
STATIC
int
STATIC
int
delalloc_convert
(
delalloc_convert
(
struct
page
*
page
,
struct
page
*
page
,
int
startio
,
int
startio
,
int
allocate_space
)
int
unmapped
)
/* also implies page uptodate */
{
{
struct
inode
*
inode
=
page
->
mapping
->
host
;
struct
inode
*
inode
=
page
->
mapping
->
host
;
struct
buffer_head
*
bh_arr
[
MAX_BUF_PER_PAGE
],
*
bh
,
*
head
;
struct
buffer_head
*
bh_arr
[
MAX_BUF_PER_PAGE
],
*
bh
,
*
head
;
...
@@ -375,6 +379,9 @@ delalloc_convert(
...
@@ -375,6 +379,9 @@ delalloc_convert(
unsigned
long
p_offset
=
0
,
end_index
;
unsigned
long
p_offset
=
0
,
end_index
;
loff_t
offset
,
end_offset
;
loff_t
offset
,
end_offset
;
int
len
,
err
,
i
,
cnt
=
0
,
uptodate
=
1
;
int
len
,
err
,
i
,
cnt
=
0
,
uptodate
=
1
;
int
flags
=
startio
?
0
:
PBF_TRYLOCK
;
int
page_dirty
=
1
;
/* Are we off the end of the file ? */
/* Are we off the end of the file ? */
end_index
=
inode
->
i_size
>>
PAGE_CACHE_SHIFT
;
end_index
=
inode
->
i_size
>>
PAGE_CACHE_SHIFT
;
...
@@ -390,9 +397,6 @@ delalloc_convert(
...
@@ -390,9 +397,6 @@ delalloc_convert(
if
(
end_offset
>
inode
->
i_size
)
if
(
end_offset
>
inode
->
i_size
)
end_offset
=
inode
->
i_size
;
end_offset
=
inode
->
i_size
;
if
(
startio
&&
!
page_has_buffers
(
page
))
create_empty_buffers
(
page
,
1
<<
inode
->
i_blkbits
,
0
);
bh
=
head
=
page_buffers
(
page
);
bh
=
head
=
page_buffers
(
page
);
mp
=
NULL
;
mp
=
NULL
;
...
@@ -406,10 +410,14 @@ delalloc_convert(
...
@@ -406,10 +410,14 @@ delalloc_convert(
mp
=
match_offset_to_mapping
(
page
,
&
map
,
p_offset
);
mp
=
match_offset_to_mapping
(
page
,
&
map
,
p_offset
);
}
}
/*
* First case, allocate space for delalloc buffer head
* we can return EAGAIN here in the release page case.
*/
if
(
buffer_delay
(
bh
))
{
if
(
buffer_delay
(
bh
))
{
if
(
!
mp
)
{
if
(
!
mp
)
{
err
=
map_blocks
(
inode
,
offset
,
len
,
&
map
,
err
=
map_blocks
(
inode
,
offset
,
len
,
&
map
,
PBF_FILE_ALLOCATE
);
PBF_FILE_ALLOCATE
|
flags
);
if
(
err
)
{
if
(
err
)
{
goto
error
;
goto
error
;
}
}
...
@@ -422,14 +430,17 @@ delalloc_convert(
...
@@ -422,14 +430,17 @@ delalloc_convert(
if
(
startio
)
{
if
(
startio
)
{
bh_arr
[
cnt
++
]
=
bh
;
bh_arr
[
cnt
++
]
=
bh
;
}
else
{
}
else
{
set_buffer_dirty
(
bh
);
unlock_buffer
(
bh
);
unlock_buffer
(
bh
);
}
}
page_dirty
=
0
;
}
}
}
else
if
((
buffer_uptodate
(
bh
)
||
PageUptodate
(
page
))
&&
}
else
if
((
buffer_uptodate
(
bh
)
||
PageUptodate
(
page
))
&&
(
allocate_space
||
startio
))
{
(
unmapped
||
startio
))
{
if
(
!
buffer_mapped
(
bh
))
{
if
(
!
buffer_mapped
(
bh
))
{
int
size
;
int
size
;
/*
/*
* Getting here implies an unmapped buffer
* Getting here implies an unmapped buffer
* was found, and we are in a path where we
* was found, and we are in a path where we
...
@@ -454,13 +465,16 @@ delalloc_convert(
...
@@ -454,13 +465,16 @@ delalloc_convert(
if
(
startio
)
{
if
(
startio
)
{
bh_arr
[
cnt
++
]
=
bh
;
bh_arr
[
cnt
++
]
=
bh
;
}
else
{
}
else
{
set_buffer_dirty
(
bh
);
unlock_buffer
(
bh
);
unlock_buffer
(
bh
);
}
}
page_dirty
=
0
;
}
}
}
else
if
(
startio
&&
buffer_mapped
(
bh
)
)
{
}
else
if
(
startio
)
{
if
(
buffer_uptodate
(
bh
)
&&
allocate_space
)
{
if
(
buffer_uptodate
(
bh
))
{
lock_buffer
(
bh
);
lock_buffer
(
bh
);
bh_arr
[
cnt
++
]
=
bh
;
bh_arr
[
cnt
++
]
=
bh
;
page_dirty
=
0
;
}
}
}
}
}
}
...
@@ -482,10 +496,10 @@ delalloc_convert(
...
@@ -482,10 +496,10 @@ delalloc_convert(
if
(
mp
)
{
if
(
mp
)
{
cluster_write
(
inode
,
page
->
index
+
1
,
mp
,
cluster_write
(
inode
,
page
->
index
+
1
,
mp
,
startio
,
allocate_space
);
startio
,
unmapped
);
}
}
return
0
;
return
page_dirty
;
error:
error:
for
(
i
=
0
;
i
<
cnt
;
i
++
)
{
for
(
i
=
0
;
i
<
cnt
;
i
++
)
{
...
@@ -494,12 +508,15 @@ delalloc_convert(
...
@@ -494,12 +508,15 @@ delalloc_convert(
/*
/*
* If it's delalloc and we have nowhere to put it,
* If it's delalloc and we have nowhere to put it,
* throw it away.
* throw it away, unless the lower layers told
* us to try again.
*/
*/
if
(
!
allocate_space
)
{
if
(
err
!=
-
EAGAIN
)
{
block_invalidatepage
(
page
,
0
);
if
(
!
unmapped
)
{
block_invalidatepage
(
page
,
0
);
}
ClearPageUptodate
(
page
);
}
}
ClearPageUptodate
(
page
);
return
err
;
return
err
;
}
}
...
@@ -679,109 +696,172 @@ linvfs_readpages(
...
@@ -679,109 +696,172 @@ linvfs_readpages(
}
}
STATIC
int
STATIC
void
count_page_state
(
count_page_state
(
struct
page
*
page
,
struct
page
*
page
,
int
*
nr_
delalloc
,
int
*
delalloc
,
int
*
nr_
unmapped
)
int
*
unmapped
)
{
{
*
nr_delalloc
=
*
nr_unmapped
=
0
;
struct
buffer_head
*
bh
,
*
head
;
if
(
page_has_buffers
(
page
))
{
struct
buffer_head
*
bh
,
*
head
;
bh
=
head
=
page_buffers
(
page
);
*
delalloc
=
*
unmapped
=
0
;
do
{
if
(
buffer_uptodate
(
bh
)
&&
!
buffer_mapped
(
bh
))
(
*
nr_unmapped
)
++
;
else
if
(
buffer_delay
(
bh
))
(
*
nr_delalloc
)
++
;
}
while
((
bh
=
bh
->
b_this_page
)
!=
head
);
return
1
;
bh
=
head
=
page_buffers
(
page
);
}
do
{
if
(
buffer_uptodate
(
bh
)
&&
!
buffer_mapped
(
bh
))
return
0
;
(
*
unmapped
)
=
1
;
else
if
(
buffer_delay
(
bh
))
(
*
delalloc
)
=
1
;
}
while
((
bh
=
bh
->
b_this_page
)
!=
head
);
}
}
/*
* writepage: Called from one of two places:
*
* 1. we are flushing a delalloc buffer head.
*
* 2. we are writing out a dirty page. Typically the page dirty
* state is cleared before we get here. In this case is it
* conceivable we have no buffer heads.
*
* For delalloc space on the page we need to allocate space and
* flush it. For unmapped buffer heads on the page we should
* allocate space if the page is uptodate. For any other dirty
* buffer heads on the page we should flush them.
*
* If we detect that a transaction would be required to flush
* the page, we have to check the process flags first, if we
* are already in a transaction or disk I/O during allocations
* is off, we need to fail the writepage and redirty the page.
* We also need to set PF_NOIO ourselves.
*/
STATIC
int
STATIC
int
linvfs_writepage
(
linvfs_writepage
(
struct
page
*
page
,
struct
page
*
page
,
struct
writeback_control
*
wbc
)
struct
writeback_control
*
wbc
)
{
{
int
error
;
int
error
;
int
need_trans
=
1
;
int
need_trans
;
int
nr_delalloc
,
nr_unmapped
;
int
delalloc
,
unmapped
;
struct
inode
*
inode
=
page
->
mapping
->
host
;
if
(
count_page_state
(
page
,
&
nr_delalloc
,
&
nr_unmapped
))
/*
need_trans
=
nr_delalloc
+
nr_unmapped
;
* We need a transaction if:
* 1. There are delalloc buffers on the page
* 2. The page is upto date and we have unmapped buffers
* 3. The page is upto date and we have no buffers
*/
if
(
!
page_has_buffers
(
page
))
{
unmapped
=
1
;
need_trans
=
1
;
}
else
{
count_page_state
(
page
,
&
delalloc
,
&
unmapped
);
if
(
!
PageUptodate
(
page
))
unmapped
=
0
;
need_trans
=
delalloc
+
unmapped
;
}
/*
* If we need a transaction and the process flags say
* we are already in a transaction, or no IO is allowed
* then mark the page dirty again and leave the page
* as is.
*/
if
((
current
->
flags
&
(
PF_FSTRANS
))
&&
need_trans
)
if
((
current
->
flags
&
(
PF_FSTRANS
))
&&
need_trans
)
goto
out_fail
;
goto
out_fail
;
/*
* Delay hooking up buffer heads until we have
* made our go/no-go decision.
*/
if
(
!
page_has_buffers
(
page
))
{
create_empty_buffers
(
page
,
1
<<
inode
->
i_blkbits
,
0
);
}
/*
/*
* Convert delalloc or unmapped space to real space and flush out
* Convert delalloc or unmapped space to real space and flush out
* to disk.
* to disk.
*/
*/
error
=
delalloc_convert
(
page
,
1
,
nr_delalloc
==
0
);
error
=
delalloc_convert
(
page
,
1
,
unmapped
);
if
(
unlikely
(
error
))
if
(
error
==
-
EAGAIN
)
unlock_page
(
page
);
goto
out_fail
;
return
error
;
if
(
unlikely
(
error
<
0
))
goto
out_unlock
;
return
0
;
out_fail:
out_fail:
set_page_dirty
(
page
);
set_page_dirty
(
page
);
unlock_page
(
page
);
unlock_page
(
page
);
return
0
;
return
0
;
}
out_unlock:
unlock_page
(
page
);
STATIC
int
return
error
;
linvfs_prepare_write
(
struct
file
*
file
,
struct
page
*
page
,
unsigned
int
from
,
unsigned
int
to
)
{
if
(
file
&&
(
file
->
f_flags
&
O_SYNC
))
{
return
block_prepare_write
(
page
,
from
,
to
,
linvfs_get_block_sync
);
}
else
{
return
block_prepare_write
(
page
,
from
,
to
,
linvfs_get_block
);
}
}
}
/*
/*
* This gets a page into cleanable state - page locked on entry
* Called to move a page into cleanable state - and from there
* kept locked on exit. If the page is marked dirty we should
* to be released. Possibly the page is already clean. We always
* not come this way.
* have buffer heads in this call.
*
* Returns 0 if the page is ok to release, 1 otherwise.
*
* Possible scenarios are:
*
* 1. We are being called to release a page which has been written
* to via regular I/O. buffer heads will be dirty and possibly
* delalloc. If no delalloc buffer heads in this case then we
* can just return zero.
*
* 2. We are called to release a page which has been written via
* mmap, all we need to do is ensure there is no delalloc
* state in the buffer heads, if not we can let the caller
* free them and we should come back later via writepage.
*/
*/
STATIC
int
STATIC
int
linvfs_release_page
(
linvfs_release_page
(
struct
page
*
page
,
struct
page
*
page
,
int
gfp_mask
)
int
gfp_mask
)
{
{
int
nr_delalloc
,
nr_
unmapped
;
int
delalloc
,
unmapped
;
if
(
count_page_state
(
page
,
&
nr_delalloc
,
&
nr_unmapped
))
{
count_page_state
(
page
,
&
delalloc
,
&
unmapped
);
if
(
!
nr_delalloc
)
if
(
!
delalloc
)
goto
free_buffers
;
goto
free_buffers
;
}
if
(
gfp_mask
&
__GFP_FS
)
{
if
(
!
(
gfp_mask
&
__GFP_FS
))
/*
return
0
;
* Convert delalloc space to real space, do not flush the
* data out to disk, that will be done by the caller.
*/
if
(
delalloc_convert
(
page
,
0
,
0
)
==
0
)
goto
free_buffers
;
}
/*
* Convert delalloc space to real space, do not flush the
* data out to disk, that will be done by the caller.
* Never need to allocate space here - we will always
* come back to writepage in that case.
*/
if
(
delalloc_convert
(
page
,
0
,
0
)
==
0
)
goto
free_buffers
;
return
0
;
return
0
;
free_buffers:
free_buffers:
return
try_to_free_buffers
(
page
);
return
try_to_free_buffers
(
page
);
}
}
STATIC
int
linvfs_prepare_write
(
struct
file
*
file
,
struct
page
*
page
,
unsigned
int
from
,
unsigned
int
to
)
{
if
(
file
&&
(
file
->
f_flags
&
O_SYNC
))
{
return
block_prepare_write
(
page
,
from
,
to
,
linvfs_get_block_sync
);
}
else
{
return
block_prepare_write
(
page
,
from
,
to
,
linvfs_get_block
);
}
}
struct
address_space_operations
linvfs_aops
=
{
struct
address_space_operations
linvfs_aops
=
{
.
readpage
=
linvfs_readpage
,
.
readpage
=
linvfs_readpage
,
...
...
fs/xfs/linux/xfs_iomap.c
View file @
5906f819
...
@@ -120,7 +120,13 @@ xfs_iomap(
...
@@ -120,7 +120,13 @@ xfs_iomap(
case
PBF_FILE_ALLOCATE
:
case
PBF_FILE_ALLOCATE
:
lockmode
=
XFS_ILOCK_SHARED
|
XFS_EXTSIZE_RD
;
lockmode
=
XFS_ILOCK_SHARED
|
XFS_EXTSIZE_RD
;
bmap_flags
=
XFS_BMAPI_ENTIRE
;
bmap_flags
=
XFS_BMAPI_ENTIRE
;
XFS_ILOCK
(
mp
,
io
,
lockmode
);
/* Attempt non-blocking lock */
if
(
flags
&
PBF_TRYLOCK
)
{
if
(
!
XFS_ILOCK_NOWAIT
(
mp
,
io
,
lockmode
))
return
XFS_ERROR
(
EAGAIN
);
}
else
{
XFS_ILOCK
(
mp
,
io
,
lockmode
);
}
break
;
break
;
case
PBF_FILE_UNWRITTEN
:
case
PBF_FILE_UNWRITTEN
:
lockmode
=
XFS_ILOCK_EXCL
|
XFS_EXTSIZE_WR
;
lockmode
=
XFS_ILOCK_EXCL
|
XFS_EXTSIZE_WR
;
...
...
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