[XFS] Fix callers of xfs_iozero() to zero the correct range.
authorLachlan McIlroy <lachlan@sgi.com>
Sat, 10 Feb 2007 07:36:47 +0000 (18:36 +1100)
committerTim Shimmin <tes@sgi.com>
Sat, 10 Feb 2007 07:36:47 +0000 (18:36 +1100)
The problem is the two callers of xfs_iozero() are rounding out the range
to be zeroed to the end of a fsb and in some cases this extends past the
new eof. The call to commit_write() in xfs_iozero() will cause the Linux
inode's file size to be set too high.

SGI-PV: 960788
SGI-Modid: xfs-linux-melb:xfs-kern:28013a

Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Signed-off-by: David Chinner <dgc@sgi.com>
Signed-off-by: Tim Shimmin <tes@sgi.com>
fs/xfs/linux-2.6/xfs_lrw.c
fs/xfs/linux-2.6/xfs_lrw.h
fs/xfs/xfs_inode.c

index 65e79b471d49570f825033d31843327e2d7c50f2..50ba4794f19fe0120921668f28b094e10f830079 100644 (file)
@@ -134,8 +134,7 @@ STATIC int
 xfs_iozero(
        struct inode            *ip,    /* inode                        */
        loff_t                  pos,    /* offset in file               */
-       size_t                  count,  /* size of data to zero         */
-       loff_t                  end_size)       /* max file size to set */
+       size_t                  count)  /* size of data to zero         */
 {
        unsigned                bytes;
        struct page             *page;
@@ -172,8 +171,6 @@ xfs_iozero(
                if (!status) {
                        pos += bytes;
                        count -= bytes;
-                       if (pos > i_size_read(ip))
-                               i_size_write(ip, pos < end_size ? pos : end_size);
                }
 
 unlock:
@@ -449,8 +446,8 @@ STATIC int                          /* error (positive) */
 xfs_zero_last_block(
        struct inode    *ip,
        xfs_iocore_t    *io,
-       xfs_fsize_t     isize,
-       xfs_fsize_t     end_size)
+       xfs_fsize_t     offset,
+       xfs_fsize_t     isize)
 {
        xfs_fileoff_t   last_fsb;
        xfs_mount_t     *mp = io->io_mount;
@@ -459,7 +456,6 @@ xfs_zero_last_block(
        int             zero_len;
        int             error = 0;
        xfs_bmbt_irec_t imap;
-       loff_t          loff;
 
        ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0);
 
@@ -494,9 +490,10 @@ xfs_zero_last_block(
         */
        XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD);
 
-       loff = XFS_FSB_TO_B(mp, last_fsb);
        zero_len = mp->m_sb.sb_blocksize - zero_offset;
-       error = xfs_iozero(ip, loff + zero_offset, zero_len, end_size);
+       if (isize + zero_len > offset)
+               zero_len = offset - isize;
+       error = xfs_iozero(ip, isize, zero_len);
 
        XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
        ASSERT(error >= 0);
@@ -519,14 +516,15 @@ xfs_zero_eof(
        bhv_vnode_t     *vp,
        xfs_iocore_t    *io,
        xfs_off_t       offset,         /* starting I/O offset */
-       xfs_fsize_t     isize,          /* current inode size */
-       xfs_fsize_t     end_size)       /* terminal inode size */
+       xfs_fsize_t     isize)          /* current inode size */
 {
        struct inode    *ip = vn_to_inode(vp);
        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;
        xfs_mount_t     *mp = io->io_mount;
        int             nimaps;
        int             error = 0;
@@ -540,7 +538,7 @@ xfs_zero_eof(
         * 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, io, isize, end_size);
+       error = xfs_zero_last_block(ip, io, offset, isize);
        if (error) {
                ASSERT(ismrlocked(io->io_lock, MR_UPDATE));
                ASSERT(ismrlocked(io->io_iolock, MR_UPDATE));
@@ -601,10 +599,13 @@ xfs_zero_eof(
                 */
                XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
 
-               error = xfs_iozero(ip,
-                                  XFS_FSB_TO_B(mp, start_zero_fsb),
-                                  XFS_FSB_TO_B(mp, imap.br_blockcount),
-                                  end_size);
+               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;
                }
@@ -783,8 +784,7 @@ start:
         */
 
        if (pos > isize) {
-               error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos,
-                                       isize, pos + count);
+               error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, isize);
                if (error) {
                        xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
                        goto out_unlock_mutex;
index c77e62efb7420d1bebd3445e55409d426d72fb20..7ac51b1d2161c6b9d2033dc3d3ea96d3e1ff38d7 100644 (file)
@@ -83,7 +83,7 @@ extern int xfs_bdstrat_cb(struct xfs_buf *);
 extern int xfs_dev_is_read_only(struct xfs_mount *, char *);
 
 extern int xfs_zero_eof(struct bhv_vnode *, struct xfs_iocore *, xfs_off_t,
-                               xfs_fsize_t, xfs_fsize_t);
+                               xfs_fsize_t);
 extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *,
                                const struct iovec *, unsigned int,
                                loff_t *, int, struct cred *);
index e42418f922157bc2f93314cfe356ef0b7cae38f0..295577d67ea0fb4c63c638150e6b32ca8db235fc 100644 (file)
@@ -1810,7 +1810,7 @@ xfs_igrow_start(
         * and any blocks between the old and new file sizes.
         */
        error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size,
-                            ip->i_d.di_size, new_size);
+                            ip->i_d.di_size);
        return error;
 }