mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 07:01:32 +00:00
ba87ea699e
The problem that has been addressed is that of synchronising updates of the file size with writes that extend a file. Without the fix the update of a file's size, as a result of a write beyond eof, is independent of when the cached data is flushed to disk. Often the file size update would be written to the filesystem log before the data is flushed to disk. When a system crashes between these two events and the filesystem log is replayed on mount the file's size will be set but since the contents never made it to disk the file is full of holes. If some of the cached data was flushed to disk then it may just be a section of the file at the end that has holes. There are existing fixes to help alleviate this problem, particularly in the case where a file has been truncated, that force cached data to be flushed to disk when the file is closed. If the system crashes while the file(s) are still open then this flushing will never occur. The fix that we have implemented is to introduce a second file size, called the in-memory file size, that represents the current file size as viewed by the user. The existing file size, called the on-disk file size, is the one that get's written to the filesystem log and we only update it when it is safe to do so. When we write to a file beyond eof we only update the in- memory file size in the write operation. Later when the I/O operation, that flushes the cached data to disk completes, an I/O completion routine will update the on-disk file size. The on-disk file size will be updated to the maximum offset of the I/O or to the value of the in-memory file size if the I/O includes eof. SGI-PV: 958522 SGI-Modid: xfs-linux-melb:xfs-kern:28322a Signed-off-by: Lachlan McIlroy <lachlan@sgi.com> Signed-off-by: David Chinner <dgc@sgi.com> Signed-off-by: Tim Shimmin <tes@sgi.com>
120 lines
3.1 KiB
C
120 lines
3.1 KiB
C
/*
|
|
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it would be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
#include "xfs.h"
|
|
#include "xfs_fs.h"
|
|
#include "xfs_types.h"
|
|
#include "xfs_bit.h"
|
|
#include "xfs_log.h"
|
|
#include "xfs_inum.h"
|
|
#include "xfs_trans.h"
|
|
#include "xfs_sb.h"
|
|
#include "xfs_ag.h"
|
|
#include "xfs_dir2.h"
|
|
#include "xfs_dfrag.h"
|
|
#include "xfs_dmapi.h"
|
|
#include "xfs_mount.h"
|
|
#include "xfs_bmap_btree.h"
|
|
#include "xfs_alloc_btree.h"
|
|
#include "xfs_ialloc_btree.h"
|
|
#include "xfs_dir2_sf.h"
|
|
#include "xfs_attr_sf.h"
|
|
#include "xfs_dinode.h"
|
|
#include "xfs_inode.h"
|
|
#include "xfs_inode_item.h"
|
|
#include "xfs_itable.h"
|
|
#include "xfs_btree.h"
|
|
#include "xfs_alloc.h"
|
|
#include "xfs_ialloc.h"
|
|
#include "xfs_bmap.h"
|
|
#include "xfs_error.h"
|
|
#include "xfs_rw.h"
|
|
#include "xfs_quota.h"
|
|
#include "xfs_trans_space.h"
|
|
#include "xfs_iomap.h"
|
|
|
|
|
|
STATIC xfs_fsize_t
|
|
xfs_size_fn(
|
|
xfs_inode_t *ip)
|
|
{
|
|
return XFS_ISIZE(ip);
|
|
}
|
|
|
|
STATIC int
|
|
xfs_ioinit(
|
|
struct bhv_vfs *vfsp,
|
|
struct xfs_mount_args *mntargs,
|
|
int flags)
|
|
{
|
|
return xfs_mountfs(vfsp, XFS_VFSTOM(vfsp), flags);
|
|
}
|
|
|
|
xfs_ioops_t xfs_iocore_xfs = {
|
|
.xfs_ioinit = (xfs_ioinit_t) xfs_ioinit,
|
|
.xfs_bmapi_func = (xfs_bmapi_t) xfs_bmapi,
|
|
.xfs_bunmapi_func = (xfs_bunmapi_t) xfs_bunmapi,
|
|
.xfs_bmap_eof_func = (xfs_bmap_eof_t) xfs_bmap_eof,
|
|
.xfs_iomap_write_direct =
|
|
(xfs_iomap_write_direct_t) xfs_iomap_write_direct,
|
|
.xfs_iomap_write_delay =
|
|
(xfs_iomap_write_delay_t) xfs_iomap_write_delay,
|
|
.xfs_iomap_write_allocate =
|
|
(xfs_iomap_write_allocate_t) xfs_iomap_write_allocate,
|
|
.xfs_iomap_write_unwritten =
|
|
(xfs_iomap_write_unwritten_t) xfs_iomap_write_unwritten,
|
|
.xfs_ilock = (xfs_lock_t) xfs_ilock,
|
|
.xfs_lck_map_shared = (xfs_lck_map_shared_t) xfs_ilock_map_shared,
|
|
.xfs_ilock_demote = (xfs_lock_demote_t) xfs_ilock_demote,
|
|
.xfs_ilock_nowait = (xfs_lock_nowait_t) xfs_ilock_nowait,
|
|
.xfs_unlock = (xfs_unlk_t) xfs_iunlock,
|
|
.xfs_size_func = (xfs_size_t) xfs_size_fn,
|
|
.xfs_iodone = (xfs_iodone_t) fs_noerr,
|
|
.xfs_swap_extents_func = (xfs_swap_extents_t) xfs_swap_extents,
|
|
};
|
|
|
|
void
|
|
xfs_iocore_inode_reinit(
|
|
xfs_inode_t *ip)
|
|
{
|
|
xfs_iocore_t *io = &ip->i_iocore;
|
|
|
|
io->io_flags = 0;
|
|
if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)
|
|
io->io_flags |= XFS_IOCORE_RT;
|
|
io->io_dmevmask = ip->i_d.di_dmevmask;
|
|
io->io_dmstate = ip->i_d.di_dmstate;
|
|
}
|
|
|
|
void
|
|
xfs_iocore_inode_init(
|
|
xfs_inode_t *ip)
|
|
{
|
|
xfs_iocore_t *io = &ip->i_iocore;
|
|
xfs_mount_t *mp = ip->i_mount;
|
|
|
|
io->io_mount = mp;
|
|
#ifdef DEBUG
|
|
io->io_lock = &ip->i_lock;
|
|
io->io_iolock = &ip->i_iolock;
|
|
#endif
|
|
|
|
io->io_obj = (void *)ip;
|
|
|
|
xfs_iocore_inode_reinit(ip);
|
|
}
|