#include <linux/falloc.h>
 #include <linux/slab.h>
 #include <linux/ratelimit.h>
+#include <linux/mount.h>
 #include "compat.h"
 #include "ctree.h"
 #include "disk-io.h"
                        return ret;
                }
 
-               mark_inode_dirty(inode);
+               ret = btrfs_dirty_inode(inode);
        } else {
 
                /*
 
        if (attr->ia_valid) {
                setattr_copy(inode, attr);
-               mark_inode_dirty(inode);
+               err = btrfs_dirty_inode(inode);
 
-               if (attr->ia_valid & ATTR_MODE)
+               if (!err && attr->ia_valid & ATTR_MODE)
                        err = btrfs_acl_chmod(inode);
        }
 
  * FIXME, needs more benchmarking...there are no reasons other than performance
  * to keep or drop this code.
  */
-void btrfs_dirty_inode(struct inode *inode, int flags)
+int btrfs_dirty_inode(struct inode *inode)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_trans_handle *trans;
        int ret;
 
        if (BTRFS_I(inode)->dummy_inode)
-               return;
+               return 0;
 
        trans = btrfs_join_transaction(root);
-       BUG_ON(IS_ERR(trans));
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
 
        ret = btrfs_update_inode(trans, root, inode);
        if (ret && ret == -ENOSPC) {
                /* whoops, lets try again with the full transaction */
                btrfs_end_transaction(trans, root);
                trans = btrfs_start_transaction(root, 1);
-               if (IS_ERR(trans)) {
-                       printk_ratelimited(KERN_ERR "btrfs: fail to "
-                                      "dirty  inode %llu error %ld\n",
-                                      (unsigned long long)btrfs_ino(inode),
-                                      PTR_ERR(trans));
-                       return;
-               }
+               if (IS_ERR(trans))
+                       return PTR_ERR(trans);
 
                ret = btrfs_update_inode(trans, root, inode);
-               if (ret) {
-                       printk_ratelimited(KERN_ERR "btrfs: fail to "
-                                      "dirty  inode %llu error %d\n",
-                                      (unsigned long long)btrfs_ino(inode),
-                                      ret);
-               }
        }
        btrfs_end_transaction(trans, root);
        if (BTRFS_I(inode)->delayed_node)
                btrfs_balance_delayed_items(root);
+
+       return ret;
+}
+
+/*
+ * This is a copy of file_update_time.  We need this so we can return error on
+ * ENOSPC for updating the inode in the case of file write and mmap writes.
+ */
+int btrfs_update_time(struct file *file)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct timespec now;
+       int ret;
+       enum { S_MTIME = 1, S_CTIME = 2, S_VERSION = 4 } sync_it = 0;
+
+       /* First try to exhaust all avenues to not sync */
+       if (IS_NOCMTIME(inode))
+               return 0;
+
+       now = current_fs_time(inode->i_sb);
+       if (!timespec_equal(&inode->i_mtime, &now))
+               sync_it = S_MTIME;
+
+       if (!timespec_equal(&inode->i_ctime, &now))
+               sync_it |= S_CTIME;
+
+       if (IS_I_VERSION(inode))
+               sync_it |= S_VERSION;
+
+       if (!sync_it)
+               return 0;
+
+       /* Finally allowed to write? Takes lock. */
+       if (mnt_want_write_file(file))
+               return 0;
+
+       /* Only change inode inside the lock region */
+       if (sync_it & S_VERSION)
+               inode_inc_iversion(inode);
+       if (sync_it & S_CTIME)
+               inode->i_ctime = now;
+       if (sync_it & S_MTIME)
+               inode->i_mtime = now;
+       ret = btrfs_dirty_inode(inode);
+       if (!ret)
+               mark_inode_dirty_sync(inode);
+       mnt_drop_write(file->f_path.mnt);
+       return ret;
 }
 
 /*
        u64 page_end;
 
        ret  = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
+       if (!ret)
+               ret = btrfs_update_time(vma->vm_file);
        if (ret) {
                if (ret == -ENOMEM)
                        ret = VM_FAULT_OOM;
        .follow_link    = page_follow_link_light,
        .put_link       = page_put_link,
        .getattr        = btrfs_getattr,
+       .setattr        = btrfs_setattr,
        .permission     = btrfs_permission,
        .setxattr       = btrfs_setxattr,
        .getxattr       = btrfs_getxattr,
 
 #include <linux/slab.h>
 #include <linux/cleancache.h>
 #include <linux/mnt_namespace.h>
+#include <linux/ratelimit.h>
 #include "compat.h"
 #include "delayed-inode.h"
 #include "ctree.h"
        return 0;
 }
 
+static void btrfs_fs_dirty_inode(struct inode *inode, int flags)
+{
+       int ret;
+
+       ret = btrfs_dirty_inode(inode);
+       if (ret)
+               printk_ratelimited(KERN_ERR "btrfs: fail to dirty inode %Lu "
+                                  "error %d\n", btrfs_ino(inode), ret);
+}
+
 static const struct super_operations btrfs_super_ops = {
        .drop_inode     = btrfs_drop_inode,
        .evict_inode    = btrfs_evict_inode,
        .sync_fs        = btrfs_sync_fs,
        .show_options   = btrfs_show_options,
        .write_inode    = btrfs_write_inode,
-       .dirty_inode    = btrfs_dirty_inode,
+       .dirty_inode    = btrfs_fs_dirty_inode,
        .alloc_inode    = btrfs_alloc_inode,
        .destroy_inode  = btrfs_destroy_inode,
        .statfs         = btrfs_statfs,