Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
a89b3f97
Commit
a89b3f97
authored
Oct 03, 2016
by
Dave Chinner
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'xfs-4.9-delalloc-rework' into for-next
parents
79ad5761
51446f5b
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
242 additions
and
350 deletions
+242
-350
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_bmap.c
+2
-87
fs/xfs/libxfs/xfs_bmap.h
fs/xfs/libxfs/xfs_bmap.h
+7
-3
fs/xfs/xfs_icache.c
fs/xfs/xfs_icache.c
+14
-0
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode.h
+1
-0
fs/xfs/xfs_iomap.c
fs/xfs/xfs_iomap.c
+218
-258
fs/xfs/xfs_iomap.h
fs/xfs/xfs_iomap.h
+0
-2
No files found.
fs/xfs/libxfs/xfs_bmap.c
View file @
a89b3f97
...
...
@@ -1389,7 +1389,7 @@ xfs_bmap_search_multi_extents(
* Else, *lastxp will be set to the index of the found
* entry; *gotp will contain the entry.
*/
STATIC
xfs_bmbt_rec_host_t
*
/* pointer to found extent entry */
xfs_bmbt_rec_host_t
*
/* pointer to found extent entry */
xfs_bmap_search_extents
(
xfs_inode_t
*
ip
,
/* incore inode pointer */
xfs_fileoff_t
bno
,
/* block number searched for */
...
...
@@ -4076,7 +4076,7 @@ xfs_bmapi_read(
return
0
;
}
STATIC
int
int
xfs_bmapi_reserve_delalloc
(
struct
xfs_inode
*
ip
,
xfs_fileoff_t
aoff
,
...
...
@@ -4172,91 +4172,6 @@ xfs_bmapi_reserve_delalloc(
return
error
;
}
/*
* Map file blocks to filesystem blocks, adding delayed allocations as needed.
*/
int
xfs_bmapi_delay
(
struct
xfs_inode
*
ip
,
/* incore inode */
xfs_fileoff_t
bno
,
/* starting file offs. mapped */
xfs_filblks_t
len
,
/* length to map in file */
struct
xfs_bmbt_irec
*
mval
,
/* output: map values */
int
*
nmap
,
/* i/o: mval size/count */
int
flags
)
/* XFS_BMAPI_... */
{
struct
xfs_mount
*
mp
=
ip
->
i_mount
;
struct
xfs_ifork
*
ifp
=
XFS_IFORK_PTR
(
ip
,
XFS_DATA_FORK
);
struct
xfs_bmbt_irec
got
;
/* current file extent record */
struct
xfs_bmbt_irec
prev
;
/* previous file extent record */
xfs_fileoff_t
obno
;
/* old block number (offset) */
xfs_fileoff_t
end
;
/* end of mapped file region */
xfs_extnum_t
lastx
;
/* last useful extent number */
int
eof
;
/* we've hit the end of extents */
int
n
=
0
;
/* current extent index */
int
error
=
0
;
ASSERT
(
*
nmap
>=
1
);
ASSERT
(
*
nmap
<=
XFS_BMAP_MAX_NMAP
);
ASSERT
(
!
(
flags
&
~
XFS_BMAPI_ENTIRE
));
ASSERT
(
xfs_isilocked
(
ip
,
XFS_ILOCK_EXCL
));
if
(
unlikely
(
XFS_TEST_ERROR
(
(
XFS_IFORK_FORMAT
(
ip
,
XFS_DATA_FORK
)
!=
XFS_DINODE_FMT_EXTENTS
&&
XFS_IFORK_FORMAT
(
ip
,
XFS_DATA_FORK
)
!=
XFS_DINODE_FMT_BTREE
),
mp
,
XFS_ERRTAG_BMAPIFORMAT
,
XFS_RANDOM_BMAPIFORMAT
)))
{
XFS_ERROR_REPORT
(
"xfs_bmapi_delay"
,
XFS_ERRLEVEL_LOW
,
mp
);
return
-
EFSCORRUPTED
;
}
if
(
XFS_FORCED_SHUTDOWN
(
mp
))
return
-
EIO
;
XFS_STATS_INC
(
mp
,
xs_blk_mapw
);
if
(
!
(
ifp
->
if_flags
&
XFS_IFEXTENTS
))
{
error
=
xfs_iread_extents
(
NULL
,
ip
,
XFS_DATA_FORK
);
if
(
error
)
return
error
;
}
xfs_bmap_search_extents
(
ip
,
bno
,
XFS_DATA_FORK
,
&
eof
,
&
lastx
,
&
got
,
&
prev
);
end
=
bno
+
len
;
obno
=
bno
;
while
(
bno
<
end
&&
n
<
*
nmap
)
{
if
(
eof
||
got
.
br_startoff
>
bno
)
{
error
=
xfs_bmapi_reserve_delalloc
(
ip
,
bno
,
len
,
&
got
,
&
prev
,
&
lastx
,
eof
);
if
(
error
)
{
if
(
n
==
0
)
{
*
nmap
=
0
;
return
error
;
}
break
;
}
}
/* set up the extent map to return. */
xfs_bmapi_trim_map
(
mval
,
&
got
,
&
bno
,
len
,
obno
,
end
,
n
,
flags
);
xfs_bmapi_update_map
(
&
mval
,
&
bno
,
&
len
,
obno
,
end
,
&
n
,
flags
);
/* If we're done, stop now. */
if
(
bno
>=
end
||
n
>=
*
nmap
)
break
;
/* Else go on to the next record. */
prev
=
got
;
if
(
++
lastx
<
ifp
->
if_bytes
/
sizeof
(
xfs_bmbt_rec_t
))
xfs_bmbt_get_all
(
xfs_iext_get_ext
(
ifp
,
lastx
),
&
got
);
else
eof
=
1
;
}
*
nmap
=
n
;
return
0
;
}
static
int
xfs_bmapi_allocate
(
struct
xfs_bmalloca
*
bma
)
...
...
fs/xfs/libxfs/xfs_bmap.h
View file @
a89b3f97
...
...
@@ -181,9 +181,6 @@ int xfs_bmap_read_extents(struct xfs_trans *tp, struct xfs_inode *ip,
int
xfs_bmapi_read
(
struct
xfs_inode
*
ip
,
xfs_fileoff_t
bno
,
xfs_filblks_t
len
,
struct
xfs_bmbt_irec
*
mval
,
int
*
nmap
,
int
flags
);
int
xfs_bmapi_delay
(
struct
xfs_inode
*
ip
,
xfs_fileoff_t
bno
,
xfs_filblks_t
len
,
struct
xfs_bmbt_irec
*
mval
,
int
*
nmap
,
int
flags
);
int
xfs_bmapi_write
(
struct
xfs_trans
*
tp
,
struct
xfs_inode
*
ip
,
xfs_fileoff_t
bno
,
xfs_filblks_t
len
,
int
flags
,
xfs_fsblock_t
*
firstblock
,
xfs_extlen_t
total
,
...
...
@@ -202,5 +199,12 @@ int xfs_bmap_shift_extents(struct xfs_trans *tp, struct xfs_inode *ip,
struct
xfs_defer_ops
*
dfops
,
enum
shift_direction
direction
,
int
num_exts
);
int
xfs_bmap_split_extent
(
struct
xfs_inode
*
ip
,
xfs_fileoff_t
split_offset
);
struct
xfs_bmbt_rec_host
*
xfs_bmap_search_extents
(
struct
xfs_inode
*
ip
,
xfs_fileoff_t
bno
,
int
fork
,
int
*
eofp
,
xfs_extnum_t
*
lastxp
,
struct
xfs_bmbt_irec
*
gotp
,
struct
xfs_bmbt_irec
*
prevp
);
int
xfs_bmapi_reserve_delalloc
(
struct
xfs_inode
*
ip
,
xfs_fileoff_t
aoff
,
xfs_filblks_t
len
,
struct
xfs_bmbt_irec
*
got
,
struct
xfs_bmbt_irec
*
prev
,
xfs_extnum_t
*
lastx
,
int
eof
);
#endif
/* __XFS_BMAP_H__ */
fs/xfs/xfs_icache.c
View file @
a89b3f97
...
...
@@ -1414,6 +1414,16 @@ xfs_inode_set_eofblocks_tag(
struct
xfs_perag
*
pag
;
int
tagged
;
/*
* Don't bother locking the AG and looking up in the radix trees
* if we already know that we have the tag set.
*/
if
(
ip
->
i_flags
&
XFS_IEOFBLOCKS
)
return
;
spin_lock
(
&
ip
->
i_flags_lock
);
ip
->
i_flags
|=
XFS_IEOFBLOCKS
;
spin_unlock
(
&
ip
->
i_flags_lock
);
pag
=
xfs_perag_get
(
mp
,
XFS_INO_TO_AGNO
(
mp
,
ip
->
i_ino
));
spin_lock
(
&
pag
->
pag_ici_lock
);
trace_xfs_inode_set_eofblocks_tag
(
ip
);
...
...
@@ -1449,6 +1459,10 @@ xfs_inode_clear_eofblocks_tag(
struct
xfs_mount
*
mp
=
ip
->
i_mount
;
struct
xfs_perag
*
pag
;
spin_lock
(
&
ip
->
i_flags_lock
);
ip
->
i_flags
&=
~
XFS_IEOFBLOCKS
;
spin_unlock
(
&
ip
->
i_flags_lock
);
pag
=
xfs_perag_get
(
mp
,
XFS_INO_TO_AGNO
(
mp
,
ip
->
i_ino
));
spin_lock
(
&
pag
->
pag_ici_lock
);
trace_xfs_inode_clear_eofblocks_tag
(
ip
);
...
...
fs/xfs/xfs_inode.h
View file @
a89b3f97
...
...
@@ -216,6 +216,7 @@ xfs_get_initial_prid(struct xfs_inode *dp)
#define __XFS_IPINNED_BIT 8
/* wakeup key for zero pin count */
#define XFS_IPINNED (1 << __XFS_IPINNED_BIT)
#define XFS_IDONTCACHE (1 << 9)
/* don't cache the inode long term */
#define XFS_IEOFBLOCKS (1 << 10)
/* has the preallocblocks tag set */
/*
* Per-lifetime flags need to be reset when re-using a reclaimable inode during
...
...
fs/xfs/xfs_iomap.c
View file @
a89b3f97
/*
* Copyright (c) 2000-2006 Silicon Graphics, Inc.
* Copyright (c) 2016 Christoph Hellwig.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
...
...
@@ -42,17 +43,40 @@
#define XFS_WRITEIO_ALIGN(mp,off) (((off) >> mp->m_writeio_log) \
<< mp->m_writeio_log)
#define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAP
STATIC
int
xfs_iomap_eof_align_last_fsb
(
xfs_mount_t
*
mp
,
xfs_inode_t
*
ip
,
xfs_extlen_t
extsize
,
xfs_fileoff_t
*
last_fsb
)
void
xfs_bmbt_to_iomap
(
struct
xfs_inode
*
ip
,
struct
iomap
*
iomap
,
struct
xfs_bmbt_irec
*
imap
)
{
struct
xfs_mount
*
mp
=
ip
->
i_mount
;
if
(
imap
->
br_startblock
==
HOLESTARTBLOCK
)
{
iomap
->
blkno
=
IOMAP_NULL_BLOCK
;
iomap
->
type
=
IOMAP_HOLE
;
}
else
if
(
imap
->
br_startblock
==
DELAYSTARTBLOCK
)
{
iomap
->
blkno
=
IOMAP_NULL_BLOCK
;
iomap
->
type
=
IOMAP_DELALLOC
;
}
else
{
iomap
->
blkno
=
xfs_fsb_to_db
(
ip
,
imap
->
br_startblock
);
if
(
imap
->
br_state
==
XFS_EXT_UNWRITTEN
)
iomap
->
type
=
IOMAP_UNWRITTEN
;
else
iomap
->
type
=
IOMAP_MAPPED
;
}
iomap
->
offset
=
XFS_FSB_TO_B
(
mp
,
imap
->
br_startoff
);
iomap
->
length
=
XFS_FSB_TO_B
(
mp
,
imap
->
br_blockcount
);
iomap
->
bdev
=
xfs_find_bdev_for_inode
(
VFS_I
(
ip
));
}
static
xfs_extlen_t
xfs_eof_alignment
(
struct
xfs_inode
*
ip
,
xfs_extlen_t
extsize
)
{
xfs_extlen_t
align
=
0
;
int
eof
,
error
;
struct
xfs_mount
*
mp
=
ip
->
i_mount
;
xfs_extlen_t
align
=
0
;
if
(
!
XFS_IS_REALTIME_INODE
(
ip
))
{
/*
...
...
@@ -83,8 +107,21 @@ xfs_iomap_eof_align_last_fsb(
align
=
extsize
;
}
return
align
;
}
STATIC
int
xfs_iomap_eof_align_last_fsb
(
struct
xfs_inode
*
ip
,
xfs_extlen_t
extsize
,
xfs_fileoff_t
*
last_fsb
)
{
xfs_extlen_t
align
=
xfs_eof_alignment
(
ip
,
extsize
);
if
(
align
)
{
xfs_fileoff_t
new_last_fsb
=
roundup_64
(
*
last_fsb
,
align
);
int
eof
,
error
;
error
=
xfs_bmap_eof
(
ip
,
new_last_fsb
,
XFS_DATA_FORK
,
&
eof
);
if
(
error
)
return
error
;
...
...
@@ -154,7 +191,7 @@ xfs_iomap_write_direct(
*/
ASSERT
(
XFS_IFORK_PTR
(
ip
,
XFS_DATA_FORK
)
->
if_flags
&
XFS_IFEXTENTS
);
error
=
xfs_iomap_eof_align_last_fsb
(
mp
,
ip
,
extsz
,
&
last_fsb
);
error
=
xfs_iomap_eof_align_last_fsb
(
ip
,
extsz
,
&
last_fsb
);
if
(
error
)
goto
out_unlock
;
}
else
{
...
...
@@ -274,130 +311,6 @@ xfs_iomap_write_direct(
goto
out_unlock
;
}
/*
* If the caller is doing a write at the end of the file, then extend the
* allocation out to the file system's write iosize. We clean up any extra
* space left over when the file is closed in xfs_inactive().
*
* If we find we already have delalloc preallocation beyond EOF, don't do more
* preallocation as it it not needed.
*/
STATIC
int
xfs_iomap_eof_want_preallocate
(
xfs_mount_t
*
mp
,
xfs_inode_t
*
ip
,
xfs_off_t
offset
,
size_t
count
,
xfs_bmbt_irec_t
*
imap
,
int
nimaps
,
int
*
prealloc
)
{
xfs_fileoff_t
start_fsb
;
xfs_filblks_t
count_fsb
;
int
n
,
error
,
imaps
;
int
found_delalloc
=
0
;
*
prealloc
=
0
;
if
(
offset
+
count
<=
XFS_ISIZE
(
ip
))
return
0
;
/*
* If the file is smaller than the minimum prealloc and we are using
* dynamic preallocation, don't do any preallocation at all as it is
* likely this is the only write to the file that is going to be done.
*/
if
(
!
(
mp
->
m_flags
&
XFS_MOUNT_DFLT_IOSIZE
)
&&
XFS_ISIZE
(
ip
)
<
XFS_FSB_TO_B
(
mp
,
mp
->
m_writeio_blocks
))
return
0
;
/*
* If there are any real blocks past eof, then don't
* do any speculative allocation.
*/
start_fsb
=
XFS_B_TO_FSBT
(
mp
,
((
xfs_ufsize_t
)(
offset
+
count
-
1
)));
count_fsb
=
XFS_B_TO_FSB
(
mp
,
mp
->
m_super
->
s_maxbytes
);
while
(
count_fsb
>
0
)
{
imaps
=
nimaps
;
error
=
xfs_bmapi_read
(
ip
,
start_fsb
,
count_fsb
,
imap
,
&
imaps
,
0
);
if
(
error
)
return
error
;
for
(
n
=
0
;
n
<
imaps
;
n
++
)
{
if
((
imap
[
n
].
br_startblock
!=
HOLESTARTBLOCK
)
&&
(
imap
[
n
].
br_startblock
!=
DELAYSTARTBLOCK
))
return
0
;
start_fsb
+=
imap
[
n
].
br_blockcount
;
count_fsb
-=
imap
[
n
].
br_blockcount
;
if
(
imap
[
n
].
br_startblock
==
DELAYSTARTBLOCK
)
found_delalloc
=
1
;
}
}
if
(
!
found_delalloc
)
*
prealloc
=
1
;
return
0
;
}
/*
* Determine the initial size of the preallocation. We are beyond the current
* EOF here, but we need to take into account whether this is a sparse write or
* an extending write when determining the preallocation size. Hence we need to
* look up the extent that ends at the current write offset and use the result
* to determine the preallocation size.
*
* If the extent is a hole, then preallocation is essentially disabled.
* Otherwise we take the size of the preceeding data extent as the basis for the
* preallocation size. If the size of the extent is greater than half the
* maximum extent length, then use the current offset as the basis. This ensures
* that for large files the preallocation size always extends to MAXEXTLEN
* rather than falling short due to things like stripe unit/width alignment of
* real extents.
*/
STATIC
xfs_fsblock_t
xfs_iomap_eof_prealloc_initial_size
(
struct
xfs_mount
*
mp
,
struct
xfs_inode
*
ip
,
xfs_off_t
offset
,
xfs_bmbt_irec_t
*
imap
,
int
nimaps
)
{
xfs_fileoff_t
start_fsb
;
int
imaps
=
1
;
int
error
;
ASSERT
(
nimaps
>=
imaps
);
/* if we are using a specific prealloc size, return now */
if
(
mp
->
m_flags
&
XFS_MOUNT_DFLT_IOSIZE
)
return
0
;
/* If the file is small, then use the minimum prealloc */
if
(
XFS_ISIZE
(
ip
)
<
XFS_FSB_TO_B
(
mp
,
mp
->
m_dalign
))
return
0
;
/*
* As we write multiple pages, the offset will always align to the
* start of a page and hence point to a hole at EOF. i.e. if the size is
* 4096 bytes, we only have one block at FSB 0, but XFS_B_TO_FSB(4096)
* will return FSB 1. Hence if there are blocks in the file, we want to
* point to the block prior to the EOF block and not the hole that maps
* directly at @offset.
*/
start_fsb
=
XFS_B_TO_FSB
(
mp
,
offset
);
if
(
start_fsb
)
start_fsb
--
;
error
=
xfs_bmapi_read
(
ip
,
start_fsb
,
1
,
imap
,
&
imaps
,
XFS_BMAPI_ENTIRE
);
if
(
error
)
return
0
;
ASSERT
(
imaps
==
1
);
if
(
imap
[
0
].
br_startblock
==
HOLESTARTBLOCK
)
return
0
;
if
(
imap
[
0
].
br_blockcount
<=
(
MAXEXTLEN
>>
1
))
return
imap
[
0
].
br_blockcount
<<
1
;
return
XFS_B_TO_FSB
(
mp
,
offset
);
}
STATIC
bool
xfs_quota_need_throttle
(
struct
xfs_inode
*
ip
,
...
...
@@ -459,27 +372,76 @@ xfs_quota_calc_throttle(
}
/*
* If we are doing a write at the end of the file and there are no allocations
* past this one, then extend the allocation out to the file system's write
* iosize.
*
* If we don't have a user specified preallocation size, dynamically increase
* the preallocation size as the size of the file grows. Cap the maximum size
* the preallocation size as the size of the file grows.
Cap the maximum size
* at a single extent or less if the filesystem is near full. The closer the
* filesystem is to full, the smaller the maximum prealocation.
*
* As an exception we don't do any preallocation at all if the file is smaller
* than the minimum preallocation and we are using the default dynamic
* preallocation scheme, as it is likely this is the only write to the file that
* is going to be done.
*
* We clean up any extra space left over when the file is closed in
* xfs_inactive().
*/
STATIC
xfs_fsblock_t
xfs_iomap_prealloc_size
(
struct
xfs_mount
*
mp
,
struct
xfs_inode
*
ip
,
xfs_off_t
offset
,
struct
xfs_bmbt_irec
*
imap
,
int
nimaps
)
loff_t
offset
,
loff_t
count
,
xfs_extnum_t
idx
,
struct
xfs_bmbt_irec
*
prev
)
{
xfs_fsblock_t
alloc_blocks
=
0
;
struct
xfs_mount
*
mp
=
ip
->
i_mount
;
xfs_fileoff_t
offset_fsb
=
XFS_B_TO_FSBT
(
mp
,
offset
);
int
shift
=
0
;
int64_t
freesp
;
xfs_fsblock_t
qblocks
;
int
qshift
=
0
;
xfs_fsblock_t
alloc_blocks
=
0
;
alloc_blocks
=
xfs_iomap_eof_prealloc_initial_size
(
mp
,
ip
,
offset
,
imap
,
nimaps
);
if
(
offset
+
count
<=
XFS_ISIZE
(
ip
))
return
0
;
if
(
!
(
mp
->
m_flags
&
XFS_MOUNT_DFLT_IOSIZE
)
&&
(
XFS_ISIZE
(
ip
)
<
XFS_FSB_TO_B
(
mp
,
mp
->
m_writeio_blocks
)))
return
0
;
/*
* If an explicit allocsize is set, the file is small, or we
* are writing behind a hole, then use the minimum prealloc:
*/
if
((
mp
->
m_flags
&
XFS_MOUNT_DFLT_IOSIZE
)
||
XFS_ISIZE
(
ip
)
<
XFS_FSB_TO_B
(
mp
,
mp
->
m_dalign
)
||
idx
==
0
||
prev
->
br_startoff
+
prev
->
br_blockcount
<
offset_fsb
)
return
mp
->
m_writeio_blocks
;
/*
* Determine the initial size of the preallocation. We are beyond the
* current EOF here, but we need to take into account whether this is
* a sparse write or an extending write when determining the
* preallocation size. Hence we need to look up the extent that ends
* at the current write offset and use the result to determine the
* preallocation size.
*
* If the extent is a hole, then preallocation is essentially disabled.
* Otherwise we take the size of the preceding data extent as the basis
* for the preallocation size. If the size of the extent is greater than
* half the maximum extent length, then use the current offset as the
* basis. This ensures that for large files the preallocation size
* always extends to MAXEXTLEN rather than falling short due to things
* like stripe unit/width alignment of real extents.
*/
if
(
prev
->
br_blockcount
<=
(
MAXEXTLEN
>>
1
))
alloc_blocks
=
prev
->
br_blockcount
<<
1
;
else
alloc_blocks
=
XFS_B_TO_FSB
(
mp
,
offset
);
if
(
!
alloc_blocks
)
goto
check_writeio
;
qblocks
=
alloc_blocks
;
...
...
@@ -550,120 +512,145 @@ xfs_iomap_prealloc_size(
*/
while
(
alloc_blocks
&&
alloc_blocks
>=
freesp
)
alloc_blocks
>>=
4
;
check_writeio:
if
(
alloc_blocks
<
mp
->
m_writeio_blocks
)
alloc_blocks
=
mp
->
m_writeio_blocks
;
trace_xfs_iomap_prealloc_size
(
ip
,
alloc_blocks
,
shift
,
mp
->
m_writeio_blocks
);
return
alloc_blocks
;
}
int
xfs_iomap_write_delay
(
xfs_inode_t
*
ip
,
xfs_off_t
offset
,
size_t
count
,
xfs_bmbt_irec_t
*
ret_imap
)
static
int
xfs_file_iomap_begin_delay
(
struct
inode
*
inode
,
loff_t
offset
,
loff_t
count
,
unsigned
flags
,
struct
iomap
*
iomap
)
{
xfs_mount_t
*
mp
=
ip
->
i_mount
;
xfs_fileoff_t
offset_fsb
;
xfs_fileoff_t
last_fsb
;
xfs_off_t
aligned_offset
;
xfs_fileoff_t
ioalign
;
xfs_extlen_t
extsz
;
int
nimaps
;
xfs_bmbt_irec_t
imap
[
XFS_WRITE_IMAPS
];
int
prealloc
;
int
error
;
ASSERT
(
xfs_isilocked
(
ip
,
XFS_ILOCK_EXCL
));
/*
* Make sure that the dquots are there. This doesn't hold
* the ilock across a disk read.
*/
error
=
xfs_qm_dqattach_locked
(
ip
,
0
);
if
(
error
)
return
error
;
struct
xfs_inode
*
ip
=
XFS_I
(
inode
);
struct
xfs_mount
*
mp
=
ip
->
i_mount
;
struct
xfs_ifork
*
ifp
=
XFS_IFORK_PTR
(
ip
,
XFS_DATA_FORK
);
xfs_fileoff_t
offset_fsb
=
XFS_B_TO_FSBT
(
mp
,
offset
);
xfs_fileoff_t
maxbytes_fsb
=
XFS_B_TO_FSB
(
mp
,
mp
->
m_super
->
s_maxbytes
);
xfs_fileoff_t
end_fsb
,
orig_end_fsb
;
int
error
=
0
,
eof
=
0
;
struct
xfs_bmbt_irec
got
;
struct
xfs_bmbt_irec
prev
;
xfs_extnum_t
idx
;
extsz
=
xfs_get_extsz_hint
(
ip
);
offset_fsb
=
XFS_B_TO_FSBT
(
mp
,
offset
);
ASSERT
(
!
XFS_IS_REALTIME_INODE
(
ip
)
);
ASSERT
(
!
xfs_get_extsz_hint
(
ip
)
);
error
=
xfs_iomap_eof_want_preallocate
(
mp
,
ip
,
offset
,
count
,
imap
,
XFS_WRITE_IMAPS
,
&
prealloc
);
if
(
error
)
return
error
;
xfs_ilock
(
ip
,
XFS_ILOCK_EXCL
);
retry:
if
(
prealloc
)
{
xfs_fsblock_t
alloc_blocks
;
if
(
unlikely
(
XFS_TEST_ERROR
(
(
XFS_IFORK_FORMAT
(
ip
,
XFS_DATA_FORK
)
!=
XFS_DINODE_FMT_EXTENTS
&&
XFS_IFORK_FORMAT
(
ip
,
XFS_DATA_FORK
)
!=
XFS_DINODE_FMT_BTREE
),
mp
,
XFS_ERRTAG_BMAPIFORMAT
,
XFS_RANDOM_BMAPIFORMAT
)))
{
XFS_ERROR_REPORT
(
__func__
,
XFS_ERRLEVEL_LOW
,
mp
);
error
=
-
EFSCORRUPTED
;
goto
out_unlock
;
}
alloc_blocks
=
xfs_iomap_prealloc_size
(
mp
,
ip
,
offset
,
imap
,
XFS_WRITE_IMAPS
);
XFS_STATS_INC
(
mp
,
xs_blk_mapw
);
aligned_offset
=
XFS_WRITEIO_ALIGN
(
mp
,
(
offset
+
count
-
1
));
ioalign
=
XFS_B_TO_FSBT
(
mp
,
aligned_offset
);
last_fsb
=
ioalign
+
alloc_blocks
;
}
else
{
last_fsb
=
XFS_B_TO_FSB
(
mp
,
((
xfs_ufsize_t
)(
offset
+
count
)));
if
(
!
(
ifp
->
if_flags
&
XFS_IFEXTENTS
))
{
error
=
xfs_iread_extents
(
NULL
,
ip
,
XFS_DATA_FORK
);
if
(
error
)
goto
out_unlock
;
}
if
(
prealloc
||
extsz
)
{
error
=
xfs_iomap_eof_align_last_fsb
(
mp
,
ip
,
extsz
,
&
last_fsb
);
if
(
error
)
return
error
;
xfs_bmap_search_extents
(
ip
,
offset_fsb
,
XFS_DATA_FORK
,
&
eof
,
&
idx
,
&
got
,
&
prev
);
if
(
!
eof
&&
got
.
br_startoff
<=
offset_fsb
)
{
trace_xfs_iomap_found
(
ip
,
offset
,
count
,
0
,
&
got
);
goto
done
;
}
error
=
xfs_qm_dqattach_locked
(
ip
,
0
);
if
(
error
)
goto
out_unlock
;
/*
* Make sure preallocation does not create extents beyond the range we
* actually support in this filesystem.
* We cap the maximum length we map here to MAX_WRITEBACK_PAGES pages
* to keep the chunks of work done where somewhat symmetric with the
* work writeback does. This is a completely arbitrary number pulled
* out of thin air as a best guess for initial testing.
*
* Note that the values needs to be less than 32-bits wide until
* the lower level functions are updated.
*/
if
(
last_fsb
>
XFS_B_TO_FSB
(
mp
,
mp
->
m_super
->
s_maxbytes
))
last_fsb
=
XFS_B_TO_FSB
(
mp
,
mp
->
m_super
->
s_maxbytes
);
count
=
min_t
(
loff_t
,
count
,
1024
*
PAGE_SIZE
);
end_fsb
=
orig_end_fsb
=
min
(
XFS_B_TO_FSB
(
mp
,
offset
+
count
),
maxbytes_fsb
);
if
(
eof
)
{
xfs_fsblock_t
prealloc_blocks
;
ASSERT
(
last_fsb
>
offset_fsb
);
prealloc_blocks
=
xfs_iomap_prealloc_size
(
ip
,
offset
,
count
,
idx
,
&
prev
);
if
(
prealloc_blocks
)
{
xfs_extlen_t
align
;
xfs_off_t
end_offset
;
nimaps
=
XFS_WRITE_IMAPS
;
error
=
xfs_bmapi_delay
(
ip
,
offset_fsb
,
last_fsb
-
offset_fsb
,
imap
,
&
nimaps
,
XFS_BMAPI_ENTIRE
);
end_offset
=
XFS_WRITEIO_ALIGN
(
mp
,
offset
+
count
-
1
);
end_fsb
=
XFS_B_TO_FSBT
(
mp
,
end_offset
)
+
prealloc_blocks
;
align
=
xfs_eof_alignment
(
ip
,
0
);
if
(
align
)
end_fsb
=
roundup_64
(
end_fsb
,
align
);
end_fsb
=
min
(
end_fsb
,
maxbytes_fsb
);
ASSERT
(
end_fsb
>
offset_fsb
);
}
}
retry:
error
=
xfs_bmapi_reserve_delalloc
(
ip
,
offset_fsb
,
end_fsb
-
offset_fsb
,
&
got
,
&
prev
,
&
idx
,
eof
);
switch
(
error
)
{
case
0
:
break
;
case
-
ENOSPC
:
case
-
EDQUOT
:
break
;
default:
return
error
;
}
/*
* If bmapi returned us nothing, we got either ENOSPC or EDQUOT. Retry
* without EOF preallocation.
*/
if
(
nimaps
==
0
)
{
/* retry without any preallocation */
trace_xfs_delalloc_enospc
(
ip
,
offset
,
count
);
if
(
prealloc
)
{
prealloc
=
0
;
error
=
0
;
if
(
end_fsb
!=
orig_end_fsb
)
{
end_fsb
=
orig_end_fsb
;
goto
retry
;
}
return
error
?
error
:
-
ENOSPC
;
/*FALLTHRU*/
default:
goto
out_unlock
;
}
if
(
!
(
imap
[
0
].
br_startblock
||
XFS_IS_REALTIME_INODE
(
ip
)))
return
xfs_alert_fsblock_zero
(
ip
,
&
imap
[
0
]);
/*
* Tag the inode as speculatively preallocated so we can reclaim this
* space on demand, if necessary.
*/
if
(
prealloc
)
if
(
end_fsb
!=
orig_end_fsb
)
xfs_inode_set_eofblocks_tag
(
ip
);
*
ret_imap
=
imap
[
0
];
return
0
;
trace_xfs_iomap_alloc
(
ip
,
offset
,
count
,
0
,
&
got
);
done:
if
(
isnullstartblock
(
got
.
br_startblock
))
got
.
br_startblock
=
DELAYSTARTBLOCK
;
if
(
!
got
.
br_startblock
)
{
error
=
xfs_alert_fsblock_zero
(
ip
,
&
got
);
if
(
error
)
goto
out_unlock
;
}
xfs_bmbt_to_iomap
(
ip
,
iomap
,
&
got
);
out_unlock:
xfs_iunlock
(
ip
,
XFS_ILOCK_EXCL
);
return
error
;
}
/*
...
...
@@ -947,32 +934,6 @@ xfs_iomap_write_unwritten(
return
error
;
}
void
xfs_bmbt_to_iomap
(
struct
xfs_inode
*
ip
,
struct
iomap
*
iomap
,
struct
xfs_bmbt_irec
*
imap
)
{
struct
xfs_mount
*
mp
=
ip
->
i_mount
;
if
(
imap
->
br_startblock
==
HOLESTARTBLOCK
)
{
iomap
->
blkno
=
IOMAP_NULL_BLOCK
;
iomap
->
type
=
IOMAP_HOLE
;
}
else
if
(
imap
->
br_startblock
==
DELAYSTARTBLOCK
)
{
iomap
->
blkno
=
IOMAP_NULL_BLOCK
;
iomap
->
type
=
IOMAP_DELALLOC
;
}
else
{
iomap
->
blkno
=
xfs_fsb_to_db
(
ip
,
imap
->
br_startblock
);
if
(
imap
->
br_state
==
XFS_EXT_UNWRITTEN
)
iomap
->
type
=
IOMAP_UNWRITTEN
;
else
iomap
->
type
=
IOMAP_MAPPED
;
}
iomap
->
offset
=
XFS_FSB_TO_B
(
mp
,
imap
->
br_startoff
);
iomap
->
length
=
XFS_FSB_TO_B
(
mp
,
imap
->
br_blockcount
);
iomap
->
bdev
=
xfs_find_bdev_for_inode
(
VFS_I
(
ip
));
}
static
inline
bool
imap_needs_alloc
(
struct
xfs_bmbt_irec
*
imap
,
int
nimaps
)
{
return
!
nimaps
||
...
...
@@ -997,6 +958,11 @@ xfs_file_iomap_begin(
if
(
XFS_FORCED_SHUTDOWN
(
mp
))
return
-
EIO
;
if
((
flags
&
IOMAP_WRITE
)
&&
!
xfs_get_extsz_hint
(
ip
))
{
return
xfs_file_iomap_begin_delay
(
inode
,
offset
,
length
,
flags
,
iomap
);
}
xfs_ilock
(
ip
,
XFS_ILOCK_EXCL
);
ASSERT
(
offset
<=
mp
->
m_super
->
s_maxbytes
);
...
...
@@ -1024,19 +990,13 @@ xfs_file_iomap_begin(
* the lower level functions are updated.
*/
length
=
min_t
(
loff_t
,
length
,
1024
*
PAGE_SIZE
);
if
(
xfs_get_extsz_hint
(
ip
))
{
/*
* xfs_iomap_write_direct() expects the shared lock. It
* is unlocked on return.
*/
xfs_ilock_demote
(
ip
,
XFS_ILOCK_EXCL
);
error
=
xfs_iomap_write_direct
(
ip
,
offset
,
length
,
&
imap
,
nimaps
);
}
else
{
error
=
xfs_iomap_write_delay
(
ip
,
offset
,
length
,
&
imap
);
xfs_iunlock
(
ip
,
XFS_ILOCK_EXCL
);
}
/*
* xfs_iomap_write_direct() expects the shared lock. It
* is unlocked on return.
*/
xfs_ilock_demote
(
ip
,
XFS_ILOCK_EXCL
);
error
=
xfs_iomap_write_direct
(
ip
,
offset
,
length
,
&
imap
,
nimaps
);
if
(
error
)
return
error
;
...
...
fs/xfs/xfs_iomap.h
View file @
a89b3f97
...
...
@@ -25,8 +25,6 @@ struct xfs_bmbt_irec;
int
xfs_iomap_write_direct
(
struct
xfs_inode
*
,
xfs_off_t
,
size_t
,
struct
xfs_bmbt_irec
*
,
int
);
int
xfs_iomap_write_delay
(
struct
xfs_inode
*
,
xfs_off_t
,
size_t
,
struct
xfs_bmbt_irec
*
);
int
xfs_iomap_write_allocate
(
struct
xfs_inode
*
,
xfs_off_t
,
struct
xfs_bmbt_irec
*
);
int
xfs_iomap_write_unwritten
(
struct
xfs_inode
*
,
xfs_off_t
,
xfs_off_t
);
...
...
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