Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 307706
b: refs/heads/master
c: 193aec1
h: refs/heads/master
v: v3
  • Loading branch information
Christoph Hellwig authored and Ben Myers committed May 14, 2012
1 parent 05daacb commit 881f98c
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 103 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f38996f5768713fb60e1d2de66c097367d54bb6a
refs/heads/master: 193aec10504e4c24521449c46317282141fb36e8
163 changes: 63 additions & 100 deletions trunk/fs/xfs/xfs_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,114 +396,96 @@ xfs_file_splice_write(
}

/*
* This routine is called to handle zeroing any space in the last
* block of the file that is beyond the EOF. We do this since the
* size is being increased without writing anything to that block
* and we don't want anyone to read the garbage on the disk.
* This routine is called to handle zeroing any space in the last block of the
* file that is beyond the EOF. We do this since the size is being increased
* without writing anything to that block and we don't want to read the
* garbage on the disk.
*/
STATIC int /* error (positive) */
xfs_zero_last_block(
xfs_inode_t *ip,
xfs_fsize_t offset,
xfs_fsize_t isize)
struct xfs_inode *ip,
xfs_fsize_t offset,
xfs_fsize_t isize)
{
xfs_fileoff_t last_fsb;
xfs_mount_t *mp = ip->i_mount;
int nimaps;
int zero_offset;
int zero_len;
int error = 0;
xfs_bmbt_irec_t imap;

ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));

zero_offset = XFS_B_FSB_OFFSET(mp, isize);
if (zero_offset == 0) {
/*
* There are no extra bytes in the last block on disk to
* zero, so return.
*/
return 0;
}
struct xfs_mount *mp = ip->i_mount;
xfs_fileoff_t last_fsb = XFS_B_TO_FSBT(mp, isize);
int zero_offset = XFS_B_FSB_OFFSET(mp, isize);
int zero_len;
int nimaps = 1;
int error = 0;
struct xfs_bmbt_irec imap;

last_fsb = XFS_B_TO_FSBT(mp, isize);
nimaps = 1;
xfs_ilock(ip, XFS_ILOCK_EXCL);
error = xfs_bmapi_read(ip, last_fsb, 1, &imap, &nimaps, 0);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
if (error)
return error;

ASSERT(nimaps > 0);

/*
* If the block underlying isize is just a hole, then there
* is nothing to zero.
*/
if (imap.br_startblock == HOLESTARTBLOCK) {
if (imap.br_startblock == HOLESTARTBLOCK)
return 0;
}
/*
* Zero the part of the last block beyond the EOF, and write it
* out sync. We need to drop the ilock while we do this so we
* don't deadlock when the buffer cache calls back to us.
*/
xfs_iunlock(ip, XFS_ILOCK_EXCL);

zero_len = mp->m_sb.sb_blocksize - zero_offset;
if (isize + zero_len > offset)
zero_len = offset - isize;
error = xfs_iozero(ip, isize, zero_len);

xfs_ilock(ip, XFS_ILOCK_EXCL);
ASSERT(error >= 0);
return error;
return xfs_iozero(ip, isize, zero_len);
}

/*
* Zero any on disk space between the current EOF and the new,
* larger EOF. This handles the normal case of zeroing the remainder
* of the last block in the file and the unusual case of zeroing blocks
* out beyond the size of the file. This second case only happens
* with fixed size extents and when the system crashes before the inode
* size was updated but after blocks were allocated. If fill is set,
* then any holes in the range are filled and zeroed. If not, the holes
* are left alone as holes.
* Zero any on disk space between the current EOF and the new, larger EOF.
*
* This handles the normal case of zeroing the remainder of the last block in
* the file and the unusual case of zeroing blocks out beyond the size of the
* file. This second case only happens with fixed size extents and when the
* system crashes before the inode size was updated but after blocks were
* allocated.
*
* Expects the iolock to be held exclusive, and will take the ilock internally.
*/

int /* error (positive) */
xfs_zero_eof(
xfs_inode_t *ip,
xfs_off_t offset, /* starting I/O offset */
xfs_fsize_t isize) /* current inode size */
struct xfs_inode *ip,
xfs_off_t offset, /* starting I/O offset */
xfs_fsize_t isize) /* current inode size */
{
xfs_mount_t *mp = ip->i_mount;
xfs_fileoff_t start_zero_fsb;
xfs_fileoff_t end_zero_fsb;
xfs_fileoff_t zero_count_fsb;
xfs_fileoff_t last_fsb;
xfs_fileoff_t zero_off;
xfs_fsize_t zero_len;
int nimaps;
int error = 0;
xfs_bmbt_irec_t imap;

ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
struct xfs_mount *mp = ip->i_mount;
xfs_fileoff_t start_zero_fsb;
xfs_fileoff_t end_zero_fsb;
xfs_fileoff_t zero_count_fsb;
xfs_fileoff_t last_fsb;
xfs_fileoff_t zero_off;
xfs_fsize_t zero_len;
int nimaps;
int error = 0;
struct xfs_bmbt_irec imap;

ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
ASSERT(offset > isize);

/*
* First handle zeroing the block on which isize resides.
*
* We only zero a part of that block so it is handled specially.
*/
error = xfs_zero_last_block(ip, offset, isize);
if (error) {
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
return error;
if (XFS_B_FSB_OFFSET(mp, isize) != 0) {
error = xfs_zero_last_block(ip, offset, isize);
if (error)
return error;
}

/*
* Calculate the range between the new size and the old
* where blocks needing to be zeroed may exist. To get the
* block where the last byte in the file currently resides,
* we need to subtract one from the size and truncate back
* to a block boundary. We subtract 1 in case the size is
* exactly on a block boundary.
* Calculate the range between the new size and the old where blocks
* needing to be zeroed may exist.
*
* To get the block where the last byte in the file currently resides,
* we need to subtract one from the size and truncate back to a block
* boundary. We subtract 1 in case the size is exactly on a block
* boundary.
*/
last_fsb = isize ? XFS_B_TO_FSBT(mp, isize - 1) : (xfs_fileoff_t)-1;
start_zero_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize);
Expand All @@ -521,58 +503,41 @@ xfs_zero_eof(
while (start_zero_fsb <= end_zero_fsb) {
nimaps = 1;
zero_count_fsb = end_zero_fsb - start_zero_fsb + 1;

xfs_ilock(ip, XFS_ILOCK_EXCL);
error = xfs_bmapi_read(ip, start_zero_fsb, zero_count_fsb,
&imap, &nimaps, 0);
if (error) {
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
xfs_iunlock(ip, XFS_ILOCK_EXCL);
if (error)
return error;
}

ASSERT(nimaps > 0);

if (imap.br_state == XFS_EXT_UNWRITTEN ||
imap.br_startblock == HOLESTARTBLOCK) {
/*
* This loop handles initializing pages that were
* partially initialized by the code below this
* loop. It basically zeroes the part of the page
* that sits on a hole and sets the page as P_HOLE
* and calls remapf if it is a mapped file.
*/
start_zero_fsb = imap.br_startoff + imap.br_blockcount;
ASSERT(start_zero_fsb <= (end_zero_fsb + 1));
continue;
}

/*
* There are blocks we need to zero.
* Drop the inode lock while we're doing the I/O.
* We'll still have the iolock to protect us.
*/
xfs_iunlock(ip, XFS_ILOCK_EXCL);

zero_off = XFS_FSB_TO_B(mp, start_zero_fsb);
zero_len = XFS_FSB_TO_B(mp, imap.br_blockcount);

if ((zero_off + zero_len) > offset)
zero_len = offset - zero_off;

error = xfs_iozero(ip, zero_off, zero_len);
if (error) {
goto out_lock;
}
if (error)
return error;

start_zero_fsb = imap.br_startoff + imap.br_blockcount;
ASSERT(start_zero_fsb <= (end_zero_fsb + 1));

xfs_ilock(ip, XFS_ILOCK_EXCL);
}

return 0;

out_lock:
xfs_ilock(ip, XFS_ILOCK_EXCL);
ASSERT(error >= 0);
return error;
}

/*
Expand Down Expand Up @@ -612,9 +577,7 @@ xfs_file_aio_write_checks(
xfs_rw_ilock(ip, *iolock);
goto restart;
}
xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
error = -xfs_zero_eof(ip, *pos, i_size_read(inode));
xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
if (error)
return error;
}
Expand Down
2 changes: 0 additions & 2 deletions trunk/fs/xfs/xfs_iops.c
Original file line number Diff line number Diff line change
Expand Up @@ -764,9 +764,7 @@ xfs_setattr_size(
* before the inode is joined to the transaction to modify
* i_size.
*/
xfs_ilock(ip, XFS_ILOCK_EXCL);
error = xfs_zero_eof(ip, newsize, oldsize);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
if (error)
goto out_unlock;
}
Expand Down

0 comments on commit 881f98c

Please sign in to comment.