#include "xfs_refcache.h"
#include "xfs_trans_space.h"
#include "xfs_log_priv.h"
+#include "xfs_filestream.h"
STATIC int
xfs_open(
code = xfs_igrow_start(ip, vap->va_size, credp);
}
xfs_iunlock(ip, XFS_ILOCK_EXCL);
- vn_iowait(vp); /* wait for the completion of any pending DIOs */
+
+ /*
+ * We are going to log the inode size change in this
+ * transaction so any previous writes that are beyond the on
+ * disk EOF and the new EOF that have not been written out need
+ * to be written here. If we do not write the data out, we
+ * expose ourselves to the null files problem.
+ *
+ * Only flush from the on disk size to the smaller of the in
+ * memory file size or the new size as that's the range we
+ * really care about here and prevents waiting for other data
+ * not within the range we care about here.
+ */
+ if (!code &&
+ (ip->i_size != ip->i_d.di_size) &&
+ (vap->va_size > ip->i_d.di_size)) {
+ code = bhv_vop_flush_pages(XFS_ITOV(ip),
+ ip->i_d.di_size, vap->va_size,
+ XFS_B_ASYNC, FI_NONE);
+ }
+
+ /* wait for all I/O to complete */
+ vn_iowait(vp);
+
if (!code)
code = xfs_itruncate_data(ip, vap->va_size);
if (code) {
di_flags |= XFS_DIFLAG_PROJINHERIT;
if (vap->va_xflags & XFS_XFLAG_NODEFRAG)
di_flags |= XFS_DIFLAG_NODEFRAG;
+ if (vap->va_xflags & XFS_XFLAG_FILESTREAM)
+ di_flags |= XFS_DIFLAG_FILESTREAM;
if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
if (vap->va_xflags & XFS_XFLAG_RTINHERIT)
di_flags |= XFS_DIFLAG_RTINHERIT;
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return XFS_ERROR(EIO);
+ if (flag & FSYNC_DATA)
+ filemap_fdatawait(vn_to_inode(XFS_ITOV(ip))->i_mapping);
+
/*
* We always need to make sure that the required inode state
* is safe on disk. The vnode might be clean but because
if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
return 0;
- if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
+ if (!XFS_FORCED_SHUTDOWN(mp)) {
+ /*
+ * If we are using filestreams, and we have an unlinked
+ * file that we are processing the last close on, then nothing
+ * will be able to reopen and write to this file. Purge this
+ * inode from the filestreams cache so that it doesn't delay
+ * teardown of the inode.
+ */
+ if ((ip->i_d.di_nlink == 0) && xfs_inode_is_filestream(ip))
+ xfs_filestream_deassociate(ip);
+
/*
* If we previously truncated this file and removed old data
* in the process, we want to initiate "early" writeout on
bhv_vop_flush_pages(vp, 0, -1, XFS_B_ASYNC, FI_NONE);
}
-
#ifdef HAVE_REFCACHE
/* If we are in the NFS reference cache then don't do this now */
if (ip->i_refcache)
xfs_lock_inumorder(int lock_mode, int subclass)
{
if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
- lock_mode |= (subclass + XFS_IOLOCK_INUMORDER) << XFS_IOLOCK_SHIFT;
+ lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_IOLOCK_SHIFT;
if (lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL))
- lock_mode |= (subclass + XFS_ILOCK_INUMORDER) << XFS_ILOCK_SHIFT;
+ lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_ILOCK_SHIFT;
return lock_mode;
}
*/
xfs_refcache_purge_ip(ip);
+ /*
+ * If we are using filestreams, kill the stream association.
+ * If the file is still open it may get a new one but that
+ * will get killed on last close in xfs_close() so we don't
+ * have to worry about that.
+ */
+ if (link_zero && xfs_inode_is_filestream(ip))
+ xfs_filestream_deassociate(ip);
+
vn_trace_exit(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address);
/*
sync_lsn = log->l_last_sync_lsn;
GRANT_UNLOCK(log, s);
- if ((XFS_LSN_CMP(iip->ili_last_lsn, sync_lsn) <= 0))
- return 0;
+ if ((XFS_LSN_CMP(iip->ili_last_lsn, sync_lsn) > 0)) {
+ if (flags & FLUSH_SYNC)
+ log_flags |= XFS_LOG_SYNC;
+ error = xfs_log_force(mp, iip->ili_last_lsn, log_flags);
+ if (error)
+ return error;
+ }
- if (flags & FLUSH_SYNC)
- log_flags |= XFS_LOG_SYNC;
- return xfs_log_force(mp, iip->ili_last_lsn, log_flags);
+ if (ip->i_update_core == 0)
+ return 0;
}
}
if (flags & FLUSH_INODE) {
int flush_flags;
- if (xfs_ipincount(ip))
- return EAGAIN;
-
if (flags & FLUSH_SYNC) {
xfs_ilock(ip, XFS_ILOCK_SHARED);
xfs_iflock(ip);
while (!error && !done) {
/*
- * allocate and setup the transaction
+ * allocate and setup the transaction. Allow this
+ * transaction to dip into the reserve blocks to ensure
+ * the freeing of the space succeeds at ENOSPC.
*/
tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
+ tp->t_flags |= XFS_TRANS_RESERVE;
error = xfs_trans_reserve(tp,
resblks,
XFS_WRITE_LOG_RES(mp),