mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-10 23:29:46 +00:00
xfs: kill xfs_itruncate_start
xfs_itruncate_start is a rather length wrapper that evaluates to a call to xfs_ioend_wait and xfs_tosspages, and only has two callers. Instead of using the complicated checks left over from IRIX where we can to truncate the pagecache just call xfs_tosspages (aka truncate_inode_pages) directly as we want to get rid of all data after i_size, and truncate_inode_pages handles incorrect alignments and too large offsets just fine. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Alex Elder <aelder@sgi.com> Reviewed-by: Dave Chinner <dchinner@redhat.com>
This commit is contained in:
parent
681b120018
commit
857b9778d8
@ -1029,40 +1029,6 @@ DEFINE_SIMPLE_IO_EVENT(xfs_delalloc_enospc);
|
|||||||
DEFINE_SIMPLE_IO_EVENT(xfs_unwritten_convert);
|
DEFINE_SIMPLE_IO_EVENT(xfs_unwritten_convert);
|
||||||
DEFINE_SIMPLE_IO_EVENT(xfs_get_blocks_notfound);
|
DEFINE_SIMPLE_IO_EVENT(xfs_get_blocks_notfound);
|
||||||
|
|
||||||
|
|
||||||
TRACE_EVENT(xfs_itruncate_start,
|
|
||||||
TP_PROTO(struct xfs_inode *ip, xfs_fsize_t new_size, int flag,
|
|
||||||
xfs_off_t toss_start, xfs_off_t toss_finish),
|
|
||||||
TP_ARGS(ip, new_size, flag, toss_start, toss_finish),
|
|
||||||
TP_STRUCT__entry(
|
|
||||||
__field(dev_t, dev)
|
|
||||||
__field(xfs_ino_t, ino)
|
|
||||||
__field(xfs_fsize_t, size)
|
|
||||||
__field(xfs_fsize_t, new_size)
|
|
||||||
__field(xfs_off_t, toss_start)
|
|
||||||
__field(xfs_off_t, toss_finish)
|
|
||||||
__field(int, flag)
|
|
||||||
),
|
|
||||||
TP_fast_assign(
|
|
||||||
__entry->dev = VFS_I(ip)->i_sb->s_dev;
|
|
||||||
__entry->ino = ip->i_ino;
|
|
||||||
__entry->size = ip->i_d.di_size;
|
|
||||||
__entry->new_size = new_size;
|
|
||||||
__entry->toss_start = toss_start;
|
|
||||||
__entry->toss_finish = toss_finish;
|
|
||||||
__entry->flag = flag;
|
|
||||||
),
|
|
||||||
TP_printk("dev %d:%d ino 0x%llx %s size 0x%llx new_size 0x%llx "
|
|
||||||
"toss start 0x%llx toss finish 0x%llx",
|
|
||||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
|
||||||
__entry->ino,
|
|
||||||
__print_flags(__entry->flag, "|", XFS_ITRUNC_FLAGS),
|
|
||||||
__entry->size,
|
|
||||||
__entry->new_size,
|
|
||||||
__entry->toss_start,
|
|
||||||
__entry->toss_finish)
|
|
||||||
);
|
|
||||||
|
|
||||||
DECLARE_EVENT_CLASS(xfs_itrunc_class,
|
DECLARE_EVENT_CLASS(xfs_itrunc_class,
|
||||||
TP_PROTO(struct xfs_inode *ip, xfs_fsize_t new_size),
|
TP_PROTO(struct xfs_inode *ip, xfs_fsize_t new_size),
|
||||||
TP_ARGS(ip, new_size),
|
TP_ARGS(ip, new_size),
|
||||||
|
@ -1217,165 +1217,8 @@ xfs_isize_check(
|
|||||||
#endif /* DEBUG */
|
#endif /* DEBUG */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate the last possible buffered byte in a file. This must
|
* Free up the underlying blocks past new_size. The new size must be
|
||||||
* include data that was buffered beyond the EOF by the write code.
|
* smaller than the current size.
|
||||||
* This also needs to deal with overflowing the xfs_fsize_t type
|
|
||||||
* which can happen for sizes near the limit.
|
|
||||||
*
|
|
||||||
* We also need to take into account any blocks beyond the EOF. It
|
|
||||||
* may be the case that they were buffered by a write which failed.
|
|
||||||
* In that case the pages will still be in memory, but the inode size
|
|
||||||
* will never have been updated.
|
|
||||||
*/
|
|
||||||
STATIC xfs_fsize_t
|
|
||||||
xfs_file_last_byte(
|
|
||||||
xfs_inode_t *ip)
|
|
||||||
{
|
|
||||||
xfs_mount_t *mp;
|
|
||||||
xfs_fsize_t last_byte;
|
|
||||||
xfs_fileoff_t last_block;
|
|
||||||
xfs_fileoff_t size_last_block;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED));
|
|
||||||
|
|
||||||
mp = ip->i_mount;
|
|
||||||
/*
|
|
||||||
* Only check for blocks beyond the EOF if the extents have
|
|
||||||
* been read in. This eliminates the need for the inode lock,
|
|
||||||
* and it also saves us from looking when it really isn't
|
|
||||||
* necessary.
|
|
||||||
*/
|
|
||||||
if (ip->i_df.if_flags & XFS_IFEXTENTS) {
|
|
||||||
xfs_ilock(ip, XFS_ILOCK_SHARED);
|
|
||||||
error = xfs_bmap_last_offset(NULL, ip, &last_block,
|
|
||||||
XFS_DATA_FORK);
|
|
||||||
xfs_iunlock(ip, XFS_ILOCK_SHARED);
|
|
||||||
if (error) {
|
|
||||||
last_block = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
last_block = 0;
|
|
||||||
}
|
|
||||||
size_last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)ip->i_size);
|
|
||||||
last_block = XFS_FILEOFF_MAX(last_block, size_last_block);
|
|
||||||
|
|
||||||
last_byte = XFS_FSB_TO_B(mp, last_block);
|
|
||||||
if (last_byte < 0) {
|
|
||||||
return XFS_MAXIOFFSET(mp);
|
|
||||||
}
|
|
||||||
last_byte += (1 << mp->m_writeio_log);
|
|
||||||
if (last_byte < 0) {
|
|
||||||
return XFS_MAXIOFFSET(mp);
|
|
||||||
}
|
|
||||||
return last_byte;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start the truncation of the file to new_size. The new size
|
|
||||||
* must be smaller than the current size. This routine will
|
|
||||||
* clear the buffer and page caches of file data in the removed
|
|
||||||
* range, and xfs_itruncate_finish() will remove the underlying
|
|
||||||
* disk blocks.
|
|
||||||
*
|
|
||||||
* The inode must have its I/O lock locked EXCLUSIVELY, and it
|
|
||||||
* must NOT have the inode lock held at all. This is because we're
|
|
||||||
* calling into the buffer/page cache code and we can't hold the
|
|
||||||
* inode lock when we do so.
|
|
||||||
*
|
|
||||||
* We need to wait for any direct I/Os in flight to complete before we
|
|
||||||
* proceed with the truncate. This is needed to prevent the extents
|
|
||||||
* being read or written by the direct I/Os from being removed while the
|
|
||||||
* I/O is in flight as there is no other method of synchronising
|
|
||||||
* direct I/O with the truncate operation. Also, because we hold
|
|
||||||
* the IOLOCK in exclusive mode, we prevent new direct I/Os from being
|
|
||||||
* started until the truncate completes and drops the lock. Essentially,
|
|
||||||
* the xfs_ioend_wait() call forms an I/O barrier that provides strict
|
|
||||||
* ordering between direct I/Os and the truncate operation.
|
|
||||||
*
|
|
||||||
* The flags parameter can have either the value XFS_ITRUNC_DEFINITE
|
|
||||||
* or XFS_ITRUNC_MAYBE. The XFS_ITRUNC_MAYBE value should be used
|
|
||||||
* in the case that the caller is locking things out of order and
|
|
||||||
* may not be able to call xfs_itruncate_finish() with the inode lock
|
|
||||||
* held without dropping the I/O lock. If the caller must drop the
|
|
||||||
* I/O lock before calling xfs_itruncate_finish(), then xfs_itruncate_start()
|
|
||||||
* must be called again with all the same restrictions as the initial
|
|
||||||
* call.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
xfs_itruncate_start(
|
|
||||||
xfs_inode_t *ip,
|
|
||||||
uint flags,
|
|
||||||
xfs_fsize_t new_size)
|
|
||||||
{
|
|
||||||
xfs_fsize_t last_byte;
|
|
||||||
xfs_off_t toss_start;
|
|
||||||
xfs_mount_t *mp;
|
|
||||||
int error = 0;
|
|
||||||
|
|
||||||
ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
|
|
||||||
ASSERT((new_size == 0) || (new_size <= ip->i_size));
|
|
||||||
ASSERT((flags == XFS_ITRUNC_DEFINITE) ||
|
|
||||||
(flags == XFS_ITRUNC_MAYBE));
|
|
||||||
|
|
||||||
mp = ip->i_mount;
|
|
||||||
|
|
||||||
/* wait for the completion of any pending DIOs */
|
|
||||||
if (new_size == 0 || new_size < ip->i_size)
|
|
||||||
xfs_ioend_wait(ip);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Call toss_pages or flushinval_pages to get rid of pages
|
|
||||||
* overlapping the region being removed. We have to use
|
|
||||||
* the less efficient flushinval_pages in the case that the
|
|
||||||
* caller may not be able to finish the truncate without
|
|
||||||
* dropping the inode's I/O lock. Make sure
|
|
||||||
* to catch any pages brought in by buffers overlapping
|
|
||||||
* the EOF by searching out beyond the isize by our
|
|
||||||
* block size. We round new_size up to a block boundary
|
|
||||||
* so that we don't toss things on the same block as
|
|
||||||
* new_size but before it.
|
|
||||||
*
|
|
||||||
* Before calling toss_page or flushinval_pages, make sure to
|
|
||||||
* call remapf() over the same region if the file is mapped.
|
|
||||||
* This frees up mapped file references to the pages in the
|
|
||||||
* given range and for the flushinval_pages case it ensures
|
|
||||||
* that we get the latest mapped changes flushed out.
|
|
||||||
*/
|
|
||||||
toss_start = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size);
|
|
||||||
toss_start = XFS_FSB_TO_B(mp, toss_start);
|
|
||||||
if (toss_start < 0) {
|
|
||||||
/*
|
|
||||||
* The place to start tossing is beyond our maximum
|
|
||||||
* file size, so there is no way that the data extended
|
|
||||||
* out there.
|
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
last_byte = xfs_file_last_byte(ip);
|
|
||||||
trace_xfs_itruncate_start(ip, new_size, flags, toss_start, last_byte);
|
|
||||||
if (last_byte > toss_start) {
|
|
||||||
if (flags & XFS_ITRUNC_DEFINITE) {
|
|
||||||
xfs_tosspages(ip, toss_start,
|
|
||||||
-1, FI_REMAPF_LOCKED);
|
|
||||||
} else {
|
|
||||||
error = xfs_flushinval_pages(ip, toss_start,
|
|
||||||
-1, FI_REMAPF_LOCKED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (new_size == 0) {
|
|
||||||
ASSERT(VN_CACHED(VFS_I(ip)) == 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Shrink the file to the given new_size. The new size must be smaller than
|
|
||||||
* the current size. This will free up the underlying blocks in the removed
|
|
||||||
* range after a call to xfs_itruncate_start() or xfs_atruncate_start().
|
|
||||||
*
|
*
|
||||||
* The transaction passed to this routine must have made a permanent log
|
* The transaction passed to this routine must have made a permanent log
|
||||||
* reservation of at least XFS_ITRUNCATE_LOG_RES. This routine may commit the
|
* reservation of at least XFS_ITRUNCATE_LOG_RES. This routine may commit the
|
||||||
@ -1387,7 +1230,7 @@ xfs_itruncate_start(
|
|||||||
* will be "held" within the returned transaction. This routine does NOT
|
* will be "held" within the returned transaction. This routine does NOT
|
||||||
* require any disk space to be reserved for it within the transaction.
|
* require any disk space to be reserved for it within the transaction.
|
||||||
*
|
*
|
||||||
* The fork parameter must be either xfs_attr_fork or xfs_data_fork, and it
|
* The fork parameter must be either XFS_ATTR_FORK or XFS_DATA_FORK, and it
|
||||||
* indicates the fork which is to be truncated. For the attribute fork we only
|
* indicates the fork which is to be truncated. For the attribute fork we only
|
||||||
* support truncation to size 0.
|
* support truncation to size 0.
|
||||||
*
|
*
|
||||||
|
@ -457,16 +457,6 @@ static inline void xfs_ifunlock(xfs_inode_t *ip)
|
|||||||
|
|
||||||
extern struct lock_class_key xfs_iolock_reclaimable;
|
extern struct lock_class_key xfs_iolock_reclaimable;
|
||||||
|
|
||||||
/*
|
|
||||||
* Flags for xfs_itruncate_start().
|
|
||||||
*/
|
|
||||||
#define XFS_ITRUNC_DEFINITE 0x1
|
|
||||||
#define XFS_ITRUNC_MAYBE 0x2
|
|
||||||
|
|
||||||
#define XFS_ITRUNC_FLAGS \
|
|
||||||
{ XFS_ITRUNC_DEFINITE, "DEFINITE" }, \
|
|
||||||
{ XFS_ITRUNC_MAYBE, "MAYBE" }
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For multiple groups support: if S_ISGID bit is set in the parent
|
* For multiple groups support: if S_ISGID bit is set in the parent
|
||||||
* directory, group of new file is set to that of the parent, and
|
* directory, group of new file is set to that of the parent, and
|
||||||
@ -501,7 +491,6 @@ uint xfs_ip2xflags(struct xfs_inode *);
|
|||||||
uint xfs_dic2xflags(struct xfs_dinode *);
|
uint xfs_dic2xflags(struct xfs_dinode *);
|
||||||
int xfs_ifree(struct xfs_trans *, xfs_inode_t *,
|
int xfs_ifree(struct xfs_trans *, xfs_inode_t *,
|
||||||
struct xfs_bmap_free *);
|
struct xfs_bmap_free *);
|
||||||
int xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t);
|
|
||||||
int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *,
|
int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *,
|
||||||
xfs_fsize_t, int, int);
|
xfs_fsize_t, int, int);
|
||||||
int xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
|
int xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
|
||||||
|
@ -197,13 +197,6 @@ xfs_free_eofblocks(
|
|||||||
*/
|
*/
|
||||||
tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
|
tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
|
||||||
|
|
||||||
/*
|
|
||||||
* Do the xfs_itruncate_start() call before
|
|
||||||
* reserving any log space because
|
|
||||||
* itruncate_start will call into the buffer
|
|
||||||
* cache and we can't
|
|
||||||
* do that within a transaction.
|
|
||||||
*/
|
|
||||||
if (flags & XFS_FREE_EOF_TRYLOCK) {
|
if (flags & XFS_FREE_EOF_TRYLOCK) {
|
||||||
if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
|
if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
|
||||||
xfs_trans_cancel(tp, 0);
|
xfs_trans_cancel(tp, 0);
|
||||||
@ -212,13 +205,6 @@ xfs_free_eofblocks(
|
|||||||
} else {
|
} else {
|
||||||
xfs_ilock(ip, XFS_IOLOCK_EXCL);
|
xfs_ilock(ip, XFS_IOLOCK_EXCL);
|
||||||
}
|
}
|
||||||
error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
|
|
||||||
ip->i_size);
|
|
||||||
if (error) {
|
|
||||||
xfs_trans_cancel(tp, 0);
|
|
||||||
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = xfs_trans_reserve(tp, 0,
|
error = xfs_trans_reserve(tp, 0,
|
||||||
XFS_ITRUNCATE_LOG_RES(mp),
|
XFS_ITRUNCATE_LOG_RES(mp),
|
||||||
@ -660,20 +646,9 @@ xfs_inactive(
|
|||||||
|
|
||||||
tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
|
tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
|
||||||
if (truncate) {
|
if (truncate) {
|
||||||
/*
|
|
||||||
* Do the xfs_itruncate_start() call before
|
|
||||||
* reserving any log space because itruncate_start
|
|
||||||
* will call into the buffer cache and we can't
|
|
||||||
* do that within a transaction.
|
|
||||||
*/
|
|
||||||
xfs_ilock(ip, XFS_IOLOCK_EXCL);
|
xfs_ilock(ip, XFS_IOLOCK_EXCL);
|
||||||
|
|
||||||
error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0);
|
xfs_ioend_wait(ip);
|
||||||
if (error) {
|
|
||||||
xfs_trans_cancel(tp, 0);
|
|
||||||
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
|
|
||||||
return VN_INACTIVE_CACHE;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = xfs_trans_reserve(tp, 0,
|
error = xfs_trans_reserve(tp, 0,
|
||||||
XFS_ITRUNCATE_LOG_RES(mp),
|
XFS_ITRUNCATE_LOG_RES(mp),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user