]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/xfs/xfs_vnodeops.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6-omap-h63xx.git] / fs / xfs / xfs_vnodeops.c
index 2067d0b0a10e2d1a0b08d772ec8d4aabab2e0d52..603459229904e0b6701b4a883b262041967e9a0a 100644 (file)
@@ -51,6 +51,7 @@
 #include "xfs_refcache.h"
 #include "xfs_trans_space.h"
 #include "xfs_log_priv.h"
+#include "xfs_filestream.h"
 
 STATIC int
 xfs_open(
@@ -588,7 +589,30 @@ xfs_setattr(
                        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) {
@@ -783,6 +807,8 @@ xfs_setattr(
                                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;
@@ -1056,6 +1082,9 @@ xfs_fsync(
        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
@@ -1536,7 +1565,17 @@ xfs_release(
        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
@@ -1551,7 +1590,6 @@ xfs_release(
                        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)
@@ -2212,9 +2250,9 @@ static inline int
 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;
 }
@@ -2541,6 +2579,15 @@ xfs_remove(
         */
        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);
 
        /*
@@ -3725,12 +3772,16 @@ xfs_inode_flush(
                        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;
                }
        }
 
@@ -3744,9 +3795,6 @@ xfs_inode_flush(
        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);
@@ -4413,9 +4461,12 @@ xfs_free_file_space(
        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),