ocfs2: fix NULL pointer dereference in __ocfs2_change_file_space()
[linux-2.6.git] / fs / ocfs2 / file.c
index 6002273..7602783 100644 (file)
@@ -36,8 +36,8 @@
 #include <linux/writeback.h>
 #include <linux/falloc.h>
 #include <linux/quotaops.h>
+#include <linux/blkdev.h>
 
-#define MLOG_MASK_PREFIX ML_INODE
 #include <cluster/masklog.h>
 
 #include "ocfs2.h"
 #include "xattr.h"
 #include "acl.h"
 #include "quota.h"
+#include "refcounttree.h"
+#include "ocfs2_trace.h"
 
 #include "buffer_head_io.h"
 
-static int ocfs2_sync_inode(struct inode *inode)
-{
-       filemap_fdatawrite(inode->i_mapping);
-       return sync_mapping_buffers(inode->i_mapping);
-}
-
 static int ocfs2_init_file_private(struct inode *inode, struct file *file)
 {
        struct ocfs2_file_private *fp;
@@ -103,8 +99,13 @@ static int ocfs2_file_open(struct inode *inode, struct file *file)
        int mode = file->f_flags;
        struct ocfs2_inode_info *oi = OCFS2_I(inode);
 
-       mlog_entry("(0x%p, 0x%p, '%.*s')\n", inode, file,
-                  file->f_path.dentry->d_name.len, file->f_path.dentry->d_name.name);
+       trace_ocfs2_file_open(inode, file, file->f_path.dentry,
+                             (unsigned long long)OCFS2_I(inode)->ip_blkno,
+                             file->f_path.dentry->d_name.len,
+                             file->f_path.dentry->d_name.name, mode);
+
+       if (file->f_mode & FMODE_WRITE)
+               dquot_initialize(inode);
 
        spin_lock(&oi->ip_lock);
 
@@ -136,7 +137,6 @@ static int ocfs2_file_open(struct inode *inode, struct file *file)
        }
 
 leave:
-       mlog_exit(status);
        return status;
 }
 
@@ -144,19 +144,19 @@ static int ocfs2_file_release(struct inode *inode, struct file *file)
 {
        struct ocfs2_inode_info *oi = OCFS2_I(inode);
 
-       mlog_entry("(0x%p, 0x%p, '%.*s')\n", inode, file,
-                      file->f_path.dentry->d_name.len,
-                      file->f_path.dentry->d_name.name);
-
        spin_lock(&oi->ip_lock);
        if (!--oi->ip_open_count)
                oi->ip_flags &= ~OCFS2_INODE_OPEN_DIRECT;
+
+       trace_ocfs2_file_release(inode, file, file->f_path.dentry,
+                                oi->ip_blkno,
+                                file->f_path.dentry->d_name.len,
+                                file->f_path.dentry->d_name.name,
+                                oi->ip_open_count);
        spin_unlock(&oi->ip_lock);
 
        ocfs2_free_file_private(inode, file);
 
-       mlog_exit(0);
-
        return 0;
 }
 
@@ -171,30 +171,47 @@ static int ocfs2_dir_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int ocfs2_sync_file(struct file *file,
-                          struct dentry *dentry,
+static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end,
                           int datasync)
 {
        int err = 0;
        journal_t *journal;
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file->f_mapping->host;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
-       mlog_entry("(0x%p, 0x%p, %d, '%.*s')\n", file, dentry, datasync,
-                  dentry->d_name.len, dentry->d_name.name);
+       trace_ocfs2_sync_file(inode, file, file->f_path.dentry,
+                             OCFS2_I(inode)->ip_blkno,
+                             file->f_path.dentry->d_name.len,
+                             file->f_path.dentry->d_name.name,
+                             (unsigned long long)datasync);
 
-       err = ocfs2_sync_inode(dentry->d_inode);
+       err = filemap_write_and_wait_range(inode->i_mapping, start, end);
        if (err)
-               goto bail;
+               return err;
 
-       if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+       /*
+        * Probably don't need the i_mutex at all in here, just putting it here
+        * to be consistent with how fsync used to be called, someone more
+        * familiar with the fs could possibly remove it.
+        */
+       mutex_lock(&inode->i_mutex);
+       if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) {
+               /*
+                * We still have to flush drive's caches to get data to the
+                * platter
+                */
+               if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER)
+                       blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
                goto bail;
+       }
 
        journal = osb->journal->j_journal;
        err = jbd2_journal_force_commit(journal);
 
 bail:
-       mlog_exit(err);
+       if (err)
+               mlog_errno(err);
+       mutex_unlock(&inode->i_mutex);
 
        return (err < 0) ? -EIO : 0;
 }
@@ -250,8 +267,6 @@ int ocfs2_update_inode_atime(struct inode *inode,
        handle_t *handle;
        struct ocfs2_dinode *di = (struct ocfs2_dinode *) bh->b_data;
 
-       mlog_entry_void();
-
        handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
        if (IS_ERR(handle)) {
                ret = PTR_ERR(handle);
@@ -259,7 +274,7 @@ int ocfs2_update_inode_atime(struct inode *inode,
                goto out;
        }
 
-       ret = ocfs2_journal_access_di(handle, inode, bh,
+       ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), bh,
                                      OCFS2_JOURNAL_ACCESS_WRITE);
        if (ret) {
                mlog_errno(ret);
@@ -274,15 +289,11 @@ int ocfs2_update_inode_atime(struct inode *inode,
        inode->i_atime = CURRENT_TIME;
        di->i_atime = cpu_to_le64(inode->i_atime.tv_sec);
        di->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec);
-
-       ret = ocfs2_journal_dirty(handle, bh);
-       if (ret < 0)
-               mlog_errno(ret);
+       ocfs2_journal_dirty(handle, bh);
 
 out_commit:
        ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
 out:
-       mlog_exit(ret);
        return ret;
 }
 
@@ -293,7 +304,6 @@ static int ocfs2_set_inode_size(handle_t *handle,
 {
        int status;
 
-       mlog_entry_void();
        i_size_write(inode, new_i_size);
        inode->i_blocks = ocfs2_inode_sector_count(inode);
        inode->i_ctime = inode->i_mtime = CURRENT_TIME;
@@ -305,7 +315,6 @@ static int ocfs2_set_inode_size(handle_t *handle,
        }
 
 bail:
-       mlog_exit(status);
        return status;
 }
 
@@ -334,6 +343,39 @@ out:
        return ret;
 }
 
+static int ocfs2_cow_file_pos(struct inode *inode,
+                             struct buffer_head *fe_bh,
+                             u64 offset)
+{
+       int status;
+       u32 phys, cpos = offset >> OCFS2_SB(inode->i_sb)->s_clustersize_bits;
+       unsigned int num_clusters = 0;
+       unsigned int ext_flags = 0;
+
+       /*
+        * If the new offset is aligned to the range of the cluster, there is
+        * no space for ocfs2_zero_range_for_truncate to fill, so no need to
+        * CoW either.
+        */
+       if ((offset & (OCFS2_SB(inode->i_sb)->s_clustersize - 1)) == 0)
+               return 0;
+
+       status = ocfs2_get_clusters(inode, cpos, &phys,
+                                   &num_clusters, &ext_flags);
+       if (status) {
+               mlog_errno(status);
+               goto out;
+       }
+
+       if (!(ext_flags & OCFS2_EXT_REFCOUNTED))
+               goto out;
+
+       return ocfs2_refcount_cow(inode, NULL, fe_bh, cpos, 1, cpos+1);
+
+out:
+       return status;
+}
+
 static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
                                     struct inode *inode,
                                     struct buffer_head *fe_bh,
@@ -344,7 +386,16 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
        struct ocfs2_dinode *di;
        u64 cluster_bytes;
 
-       mlog_entry_void();
+       /*
+        * We need to CoW the cluster contains the offset if it is reflinked
+        * since we will call ocfs2_zero_range_for_truncate later which will
+        * write "0" from offset to the end of the cluster.
+        */
+       status = ocfs2_cow_file_pos(inode, fe_bh, new_i_size);
+       if (status) {
+               mlog_errno(status);
+               return status;
+       }
 
        /* TODO: This needs to actually orphan the inode in this
         * transaction. */
@@ -356,7 +407,7 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
                goto out;
        }
 
-       status = ocfs2_journal_access_di(handle, inode, fe_bh,
+       status = ocfs2_journal_access_di(handle, INODE_CACHE(inode), fe_bh,
                                         OCFS2_JOURNAL_ACCESS_WRITE);
        if (status < 0) {
                mlog_errno(status);
@@ -382,15 +433,11 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
        di->i_ctime = di->i_mtime = cpu_to_le64(inode->i_ctime.tv_sec);
        di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
 
-       status = ocfs2_journal_dirty(handle, fe_bh);
-       if (status < 0)
-               mlog_errno(status);
+       ocfs2_journal_dirty(handle, fe_bh);
 
 out_commit:
        ocfs2_commit_trans(osb, handle);
 out:
-
-       mlog_exit(status);
        return status;
 }
 
@@ -401,16 +448,15 @@ static int ocfs2_truncate_file(struct inode *inode,
        int status = 0;
        struct ocfs2_dinode *fe = NULL;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-       struct ocfs2_truncate_context *tc = NULL;
-
-       mlog_entry("(inode = %llu, new_i_size = %llu\n",
-                  (unsigned long long)OCFS2_I(inode)->ip_blkno,
-                  (unsigned long long)new_i_size);
 
        /* We trust di_bh because it comes from ocfs2_inode_lock(), which
         * already validated it */
        fe = (struct ocfs2_dinode *) di_bh->b_data;
 
+       trace_ocfs2_truncate_file((unsigned long long)OCFS2_I(inode)->ip_blkno,
+                                 (unsigned long long)le64_to_cpu(fe->i_size),
+                                 (unsigned long long)new_i_size);
+
        mlog_bug_on_msg(le64_to_cpu(fe->i_size) != i_size_read(inode),
                        "Inode %llu, inode i_size = %lld != di "
                        "i_size = %llu, i_flags = 0x%x\n",
@@ -420,19 +466,14 @@ static int ocfs2_truncate_file(struct inode *inode,
                        le32_to_cpu(fe->i_flags));
 
        if (new_i_size > le64_to_cpu(fe->i_size)) {
-               mlog(0, "asked to truncate file with size (%llu) to size (%llu)!\n",
-                    (unsigned long long)le64_to_cpu(fe->i_size),
-                    (unsigned long long)new_i_size);
+               trace_ocfs2_truncate_file_error(
+                       (unsigned long long)le64_to_cpu(fe->i_size),
+                       (unsigned long long)new_i_size);
                status = -EINVAL;
                mlog_errno(status);
                goto bail;
        }
 
-       mlog(0, "inode %llu, i_size = %llu, new_i_size = %llu\n",
-            (unsigned long long)le64_to_cpu(fe->i_blkno),
-            (unsigned long long)le64_to_cpu(fe->i_size),
-            (unsigned long long)new_i_size);
-
        /* lets handle the simple truncate cases before doing any more
         * cluster locking. */
        if (new_i_size == le64_to_cpu(fe->i_size))
@@ -440,6 +481,9 @@ static int ocfs2_truncate_file(struct inode *inode,
 
        down_write(&OCFS2_I(inode)->ip_alloc_sem);
 
+       ocfs2_resv_discard(&osb->osb_la_resmap,
+                          &OCFS2_I(inode)->ip_la_data_resv);
+
        /*
         * The inode lock forced other nodes to sync and drop their
         * pages, which (correctly) happens even if we have a truncate
@@ -469,13 +513,7 @@ static int ocfs2_truncate_file(struct inode *inode,
                goto bail_unlock_sem;
        }
 
-       status = ocfs2_prepare_truncate(osb, inode, di_bh, &tc);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail_unlock_sem;
-       }
-
-       status = ocfs2_commit_truncate(osb, inode, di_bh, tc);
+       status = ocfs2_commit_truncate(osb, inode, di_bh);
        if (status < 0) {
                mlog_errno(status);
                goto bail_unlock_sem;
@@ -486,8 +524,9 @@ bail_unlock_sem:
        up_write(&OCFS2_I(inode)->ip_alloc_sem);
 
 bail:
+       if (!status && OCFS2_I(inode)->ip_clusters == 0)
+               status = ocfs2_try_remove_refcount_tree(inode, di_bh);
 
-       mlog_exit(status);
        return status;
 }
 
@@ -515,11 +554,10 @@ int ocfs2_add_inode_data(struct ocfs2_super *osb,
        int ret;
        struct ocfs2_extent_tree et;
 
-       ocfs2_init_dinode_extent_tree(&et, inode, fe_bh);
-       ret = ocfs2_add_clusters_in_btree(osb, inode, logical_offset,
-                                          clusters_to_add, mark_unwritten,
-                                          &et, handle,
-                                          data_ac, meta_ac, reason_ret);
+       ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), fe_bh);
+       ret = ocfs2_add_clusters_in_btree(handle, &et, logical_offset,
+                                         clusters_to_add, mark_unwritten,
+                                         data_ac, meta_ac, reason_ret);
 
        return ret;
 }
@@ -541,8 +579,6 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
        struct ocfs2_extent_tree et;
        int did_quota = 0;
 
-       mlog_entry("(clusters_to_add = %u)\n", clusters_to_add);
-
        /*
         * This function only exists for file systems which don't
         * support holes.
@@ -559,12 +595,7 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
 restart_all:
        BUG_ON(le32_to_cpu(fe->i_clusters) != OCFS2_I(inode)->ip_clusters);
 
-       mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u, "
-            "clusters_to_add = %u\n",
-            (unsigned long long)OCFS2_I(inode)->ip_blkno,
-            (long long)i_size_read(inode), le32_to_cpu(fe->i_clusters),
-            clusters_to_add);
-       ocfs2_init_dinode_extent_tree(&et, inode, bh);
+       ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), bh);
        status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0,
                                       &data_ac, &meta_ac);
        if (status) {
@@ -583,17 +614,22 @@ restart_all:
        }
 
 restarted_transaction:
-       if (vfs_dq_alloc_space_nodirty(inode, ocfs2_clusters_to_bytes(osb->sb,
-           clusters_to_add))) {
-               status = -EDQUOT;
+       trace_ocfs2_extend_allocation(
+               (unsigned long long)OCFS2_I(inode)->ip_blkno,
+               (unsigned long long)i_size_read(inode),
+               le32_to_cpu(fe->i_clusters), clusters_to_add,
+               why, restart_func);
+
+       status = dquot_alloc_space_nodirty(inode,
+                       ocfs2_clusters_to_bytes(osb->sb, clusters_to_add));
+       if (status)
                goto leave;
-       }
        did_quota = 1;
 
        /* reserve a write to the file entry early on - that we if we
         * run out of credits in the allocation path, we can still
         * update i_size. */
-       status = ocfs2_journal_access_di(handle, inode, bh,
+       status = ocfs2_journal_access_di(handle, INODE_CACHE(inode), bh,
                                         OCFS2_JOURNAL_ACCESS_WRITE);
        if (status < 0) {
                mlog_errno(status);
@@ -618,28 +654,23 @@ restarted_transaction:
                goto leave;
        }
 
-       status = ocfs2_journal_dirty(handle, bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto leave;
-       }
+       ocfs2_journal_dirty(handle, bh);
 
        spin_lock(&OCFS2_I(inode)->ip_lock);
        clusters_to_add -= (OCFS2_I(inode)->ip_clusters - prev_clusters);
        spin_unlock(&OCFS2_I(inode)->ip_lock);
        /* Release unused quota reservation */
-       vfs_dq_free_space(inode,
+       dquot_free_space(inode,
                        ocfs2_clusters_to_bytes(osb->sb, clusters_to_add));
        did_quota = 0;
 
        if (why != RESTART_NONE && clusters_to_add) {
                if (why == RESTART_META) {
-                       mlog(0, "restarting function.\n");
                        restart_func = 1;
+                       status = 0;
                } else {
                        BUG_ON(why != RESTART_TRANS);
 
-                       mlog(0, "restarting transaction.\n");
                        /* TODO: This can be more intelligent. */
                        credits = ocfs2_calc_extend_credits(osb->sb,
                                                            &fe->id2.i_list,
@@ -656,15 +687,15 @@ restarted_transaction:
                }
        }
 
-       mlog(0, "fe: i_clusters = %u, i_size=%llu\n",
+       trace_ocfs2_extend_allocation_end(OCFS2_I(inode)->ip_blkno,
             le32_to_cpu(fe->i_clusters),
-            (unsigned long long)le64_to_cpu(fe->i_size));
-       mlog(0, "inode: ip_clusters=%u, i_size=%lld\n",
-            OCFS2_I(inode)->ip_clusters, (long long)i_size_read(inode));
+            (unsigned long long)le64_to_cpu(fe->i_size),
+            OCFS2_I(inode)->ip_clusters,
+            (unsigned long long)i_size_read(inode));
 
 leave:
        if (status < 0 && did_quota)
-               vfs_dq_free_space(inode,
+               dquot_free_space(inode,
                        ocfs2_clusters_to_bytes(osb->sb, clusters_to_add));
        if (handle) {
                ocfs2_commit_trans(osb, handle);
@@ -685,65 +716,116 @@ leave:
        brelse(bh);
        bh = NULL;
 
-       mlog_exit(status);
        return status;
 }
 
+/*
+ * While a write will already be ordering the data, a truncate will not.
+ * Thus, we need to explicitly order the zeroed pages.
+ */
+static handle_t *ocfs2_zero_start_ordered_transaction(struct inode *inode)
+{
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       handle_t *handle = NULL;
+       int ret = 0;
+
+       if (!ocfs2_should_order_data(inode))
+               goto out;
+
+       handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
+       if (IS_ERR(handle)) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_jbd2_file_inode(handle, inode);
+       if (ret < 0)
+               mlog_errno(ret);
+
+out:
+       if (ret) {
+               if (!IS_ERR(handle))
+                       ocfs2_commit_trans(osb, handle);
+               handle = ERR_PTR(ret);
+       }
+       return handle;
+}
+
 /* Some parts of this taken from generic_cont_expand, which turned out
  * to be too fragile to do exactly what we need without us having to
  * worry about recursive locking in ->write_begin() and ->write_end(). */
-static int ocfs2_write_zero_page(struct inode *inode,
-                                u64 size)
+static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from,
+                                u64 abs_to)
 {
        struct address_space *mapping = inode->i_mapping;
        struct page *page;
-       unsigned long index;
-       unsigned int offset;
+       unsigned long index = abs_from >> PAGE_CACHE_SHIFT;
        handle_t *handle = NULL;
-       int ret;
+       int ret = 0;
+       unsigned zero_from, zero_to, block_start, block_end;
 
-       offset = (size & (PAGE_CACHE_SIZE-1)); /* Within page */
-       /* ugh.  in prepare/commit_write, if from==to==start of block, we 
-       ** skip the prepare.  make sure we never send an offset for the start
-       ** of a block
-       */
-       if ((offset & (inode->i_sb->s_blocksize - 1)) == 0) {
-               offset++;
-       }
-       index = size >> PAGE_CACHE_SHIFT;
+       BUG_ON(abs_from >= abs_to);
+       BUG_ON(abs_to > (((u64)index + 1) << PAGE_CACHE_SHIFT));
+       BUG_ON(abs_from & (inode->i_blkbits - 1));
 
-       page = grab_cache_page(mapping, index);
+       page = find_or_create_page(mapping, index, GFP_NOFS);
        if (!page) {
                ret = -ENOMEM;
                mlog_errno(ret);
                goto out;
        }
 
-       ret = ocfs2_prepare_write_nolock(inode, page, offset, offset);
-       if (ret < 0) {
-               mlog_errno(ret);
-               goto out_unlock;
-       }
+       /* Get the offsets within the page that we want to zero */
+       zero_from = abs_from & (PAGE_CACHE_SIZE - 1);
+       zero_to = abs_to & (PAGE_CACHE_SIZE - 1);
+       if (!zero_to)
+               zero_to = PAGE_CACHE_SIZE;
 
-       if (ocfs2_should_order_data(inode)) {
-               handle = ocfs2_start_walk_page_trans(inode, page, offset,
-                                                    offset);
-               if (IS_ERR(handle)) {
-                       ret = PTR_ERR(handle);
-                       handle = NULL;
+       trace_ocfs2_write_zero_page(
+                       (unsigned long long)OCFS2_I(inode)->ip_blkno,
+                       (unsigned long long)abs_from,
+                       (unsigned long long)abs_to,
+                       index, zero_from, zero_to);
+
+       /* We know that zero_from is block aligned */
+       for (block_start = zero_from; block_start < zero_to;
+            block_start = block_end) {
+               block_end = block_start + (1 << inode->i_blkbits);
+
+               /*
+                * block_start is block-aligned.  Bump it by one to force
+                * __block_write_begin and block_commit_write to zero the
+                * whole block.
+                */
+               ret = __block_write_begin(page, block_start + 1, 0,
+                                         ocfs2_get_block);
+               if (ret < 0) {
+                       mlog_errno(ret);
                        goto out_unlock;
                }
-       }
 
-       /* must not update i_size! */
-       ret = block_commit_write(page, offset, offset);
-       if (ret < 0)
-               mlog_errno(ret);
-       else
-               ret = 0;
+               if (!handle) {
+                       handle = ocfs2_zero_start_ordered_transaction(inode);
+                       if (IS_ERR(handle)) {
+                               ret = PTR_ERR(handle);
+                               handle = NULL;
+                               break;
+                       }
+               }
+
+               /* must not update i_size! */
+               ret = block_commit_write(page, block_start + 1,
+                                        block_start + 1);
+               if (ret < 0)
+                       mlog_errno(ret);
+               else
+                       ret = 0;
+       }
 
        if (handle)
                ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+
 out_unlock:
        unlock_page(page);
        page_cache_release(page);
@@ -751,22 +833,115 @@ out:
        return ret;
 }
 
-static int ocfs2_zero_extend(struct inode *inode,
-                            u64 zero_to_size)
+/*
+ * Find the next range to zero.  We do this in terms of bytes because
+ * that's what ocfs2_zero_extend() wants, and it is dealing with the
+ * pagecache.  We may return multiple extents.
+ *
+ * zero_start and zero_end are ocfs2_zero_extend()s current idea of what
+ * needs to be zeroed.  range_start and range_end return the next zeroing
+ * range.  A subsequent call should pass the previous range_end as its
+ * zero_start.  If range_end is 0, there's nothing to do.
+ *
+ * Unwritten extents are skipped over.  Refcounted extents are CoWd.
+ */
+static int ocfs2_zero_extend_get_range(struct inode *inode,
+                                      struct buffer_head *di_bh,
+                                      u64 zero_start, u64 zero_end,
+                                      u64 *range_start, u64 *range_end)
 {
-       int ret = 0;
-       u64 start_off;
-       struct super_block *sb = inode->i_sb;
+       int rc = 0, needs_cow = 0;
+       u32 p_cpos, zero_clusters = 0;
+       u32 zero_cpos =
+               zero_start >> OCFS2_SB(inode->i_sb)->s_clustersize_bits;
+       u32 last_cpos = ocfs2_clusters_for_bytes(inode->i_sb, zero_end);
+       unsigned int num_clusters = 0;
+       unsigned int ext_flags = 0;
+
+       while (zero_cpos < last_cpos) {
+               rc = ocfs2_get_clusters(inode, zero_cpos, &p_cpos,
+                                       &num_clusters, &ext_flags);
+               if (rc) {
+                       mlog_errno(rc);
+                       goto out;
+               }
 
-       start_off = ocfs2_align_bytes_to_blocks(sb, i_size_read(inode));
-       while (start_off < zero_to_size) {
-               ret = ocfs2_write_zero_page(inode, start_off);
-               if (ret < 0) {
-                       mlog_errno(ret);
+               if (p_cpos && !(ext_flags & OCFS2_EXT_UNWRITTEN)) {
+                       zero_clusters = num_clusters;
+                       if (ext_flags & OCFS2_EXT_REFCOUNTED)
+                               needs_cow = 1;
+                       break;
+               }
+
+               zero_cpos += num_clusters;
+       }
+       if (!zero_clusters) {
+               *range_end = 0;
+               goto out;
+       }
+
+       while ((zero_cpos + zero_clusters) < last_cpos) {
+               rc = ocfs2_get_clusters(inode, zero_cpos + zero_clusters,
+                                       &p_cpos, &num_clusters,
+                                       &ext_flags);
+               if (rc) {
+                       mlog_errno(rc);
+                       goto out;
+               }
+
+               if (!p_cpos || (ext_flags & OCFS2_EXT_UNWRITTEN))
+                       break;
+               if (ext_flags & OCFS2_EXT_REFCOUNTED)
+                       needs_cow = 1;
+               zero_clusters += num_clusters;
+       }
+       if ((zero_cpos + zero_clusters) > last_cpos)
+               zero_clusters = last_cpos - zero_cpos;
+
+       if (needs_cow) {
+               rc = ocfs2_refcount_cow(inode, NULL, di_bh, zero_cpos,
+                                       zero_clusters, UINT_MAX);
+               if (rc) {
+                       mlog_errno(rc);
                        goto out;
                }
+       }
+
+       *range_start = ocfs2_clusters_to_bytes(inode->i_sb, zero_cpos);
+       *range_end = ocfs2_clusters_to_bytes(inode->i_sb,
+                                            zero_cpos + zero_clusters);
+
+out:
+       return rc;
+}
+
+/*
+ * Zero one range returned from ocfs2_zero_extend_get_range().  The caller
+ * has made sure that the entire range needs zeroing.
+ */
+static int ocfs2_zero_extend_range(struct inode *inode, u64 range_start,
+                                  u64 range_end)
+{
+       int rc = 0;
+       u64 next_pos;
+       u64 zero_pos = range_start;
 
-               start_off += sb->s_blocksize;
+       trace_ocfs2_zero_extend_range(
+                       (unsigned long long)OCFS2_I(inode)->ip_blkno,
+                       (unsigned long long)range_start,
+                       (unsigned long long)range_end);
+       BUG_ON(range_start >= range_end);
+
+       while (zero_pos < range_end) {
+               next_pos = (zero_pos & PAGE_CACHE_MASK) + PAGE_CACHE_SIZE;
+               if (next_pos > range_end)
+                       next_pos = range_end;
+               rc = ocfs2_write_zero_page(inode, zero_pos, next_pos);
+               if (rc < 0) {
+                       mlog_errno(rc);
+                       break;
+               }
+               zero_pos = next_pos;
 
                /*
                 * Very large extends have the potential to lock up
@@ -775,16 +950,63 @@ static int ocfs2_zero_extend(struct inode *inode,
                cond_resched();
        }
 
-out:
+       return rc;
+}
+
+int ocfs2_zero_extend(struct inode *inode, struct buffer_head *di_bh,
+                     loff_t zero_to_size)
+{
+       int ret = 0;
+       u64 zero_start, range_start = 0, range_end = 0;
+       struct super_block *sb = inode->i_sb;
+
+       zero_start = ocfs2_align_bytes_to_blocks(sb, i_size_read(inode));
+       trace_ocfs2_zero_extend((unsigned long long)OCFS2_I(inode)->ip_blkno,
+                               (unsigned long long)zero_start,
+                               (unsigned long long)i_size_read(inode));
+       while (zero_start < zero_to_size) {
+               ret = ocfs2_zero_extend_get_range(inode, di_bh, zero_start,
+                                                 zero_to_size,
+                                                 &range_start,
+                                                 &range_end);
+               if (ret) {
+                       mlog_errno(ret);
+                       break;
+               }
+               if (!range_end)
+                       break;
+               /* Trim the ends */
+               if (range_start < zero_start)
+                       range_start = zero_start;
+               if (range_end > zero_to_size)
+                       range_end = zero_to_size;
+
+               ret = ocfs2_zero_extend_range(inode, range_start,
+                                             range_end);
+               if (ret) {
+                       mlog_errno(ret);
+                       break;
+               }
+               zero_start = range_end;
+       }
+
        return ret;
 }
 
-int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size, u64 zero_to)
+int ocfs2_extend_no_holes(struct inode *inode, struct buffer_head *di_bh,
+                         u64 new_i_size, u64 zero_to)
 {
        int ret;
        u32 clusters_to_add;
        struct ocfs2_inode_info *oi = OCFS2_I(inode);
 
+       /*
+        * Only quota files call this without a bh, and they can't be
+        * refcounted.
+        */
+       BUG_ON(!di_bh && (oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL));
+       BUG_ON(!di_bh && !(oi->ip_flags & OCFS2_INODE_SYSTEM_FILE));
+
        clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size);
        if (clusters_to_add < oi->ip_clusters)
                clusters_to_add = 0;
@@ -805,7 +1027,7 @@ int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size, u64 zero_to)
         * still need to zero the area between the old i_size and the
         * new i_size.
         */
-       ret = ocfs2_zero_extend(inode, zero_to);
+       ret = ocfs2_zero_extend(inode, di_bh, zero_to);
        if (ret < 0)
                mlog_errno(ret);
 
@@ -827,27 +1049,15 @@ static int ocfs2_extend_file(struct inode *inode,
                goto out;
 
        if (i_size_read(inode) == new_i_size)
-               goto out;
+               goto out;
        BUG_ON(new_i_size < i_size_read(inode));
 
        /*
-        * Fall through for converting inline data, even if the fs
-        * supports sparse files.
-        *
-        * The check for inline data here is legal - nobody can add
-        * the feature since we have i_mutex. We must check it again
-        * after acquiring ip_alloc_sem though, as paths like mmap
-        * might have raced us to converting the inode to extents.
-        */
-       if (!(oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
-           && ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
-               goto out_update_size;
-
-       /*
         * The alloc sem blocks people in read/write from reading our
         * allocation until we're done changing it. We depend on
         * i_mutex to block other extend/truncate calls while we're
-        * here.
+        * here.  We even have to hold it for sparse files because there
+        * might be some tail zeroing.
         */
        down_write(&oi->ip_alloc_sem);
 
@@ -864,14 +1074,16 @@ static int ocfs2_extend_file(struct inode *inode,
                ret = ocfs2_convert_inline_data_to_extents(inode, di_bh);
                if (ret) {
                        up_write(&oi->ip_alloc_sem);
-
                        mlog_errno(ret);
                        goto out;
                }
        }
 
-       if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
-               ret = ocfs2_extend_no_holes(inode, new_i_size, new_i_size);
+       if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+               ret = ocfs2_zero_extend(inode, di_bh, new_i_size);
+       else
+               ret = ocfs2_extend_no_holes(inode, di_bh, new_i_size,
+                                           new_i_size);
 
        up_write(&oi->ip_alloc_sem);
 
@@ -897,39 +1109,30 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
        struct ocfs2_super *osb = OCFS2_SB(sb);
        struct buffer_head *bh = NULL;
        handle_t *handle = NULL;
-       int qtype;
-       struct dquot *transfer_from[MAXQUOTAS] = { };
        struct dquot *transfer_to[MAXQUOTAS] = { };
+       int qtype;
 
-       mlog_entry("(0x%p, '%.*s')\n", dentry,
-                  dentry->d_name.len, dentry->d_name.name);
+       trace_ocfs2_setattr(inode, dentry,
+                           (unsigned long long)OCFS2_I(inode)->ip_blkno,
+                           dentry->d_name.len, dentry->d_name.name,
+                           attr->ia_valid, attr->ia_mode,
+                           attr->ia_uid, attr->ia_gid);
 
        /* ensuring we don't even attempt to truncate a symlink */
        if (S_ISLNK(inode->i_mode))
                attr->ia_valid &= ~ATTR_SIZE;
 
-       if (attr->ia_valid & ATTR_MODE)
-               mlog(0, "mode change: %d\n", attr->ia_mode);
-       if (attr->ia_valid & ATTR_UID)
-               mlog(0, "uid change: %d\n", attr->ia_uid);
-       if (attr->ia_valid & ATTR_GID)
-               mlog(0, "gid change: %d\n", attr->ia_gid);
-       if (attr->ia_valid & ATTR_SIZE)
-               mlog(0, "size change...\n");
-       if (attr->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_CTIME))
-               mlog(0, "time change...\n");
-
 #define OCFS2_VALID_ATTRS (ATTR_ATIME | ATTR_MTIME | ATTR_CTIME | ATTR_SIZE \
                           | ATTR_GID | ATTR_UID | ATTR_MODE)
-       if (!(attr->ia_valid & OCFS2_VALID_ATTRS)) {
-               mlog(0, "can't handle attrs: 0x%x\n", attr->ia_valid);
+       if (!(attr->ia_valid & OCFS2_VALID_ATTRS))
                return 0;
-       }
 
        status = inode_change_ok(inode, attr);
        if (status)
                return status;
 
+       if (is_quota_modification(inode, attr))
+               dquot_initialize(inode);
        size_change = S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE;
        if (size_change) {
                status = ocfs2_rw_lock(inode, 1);
@@ -947,10 +1150,11 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
        }
 
        if (size_change && attr->ia_size != i_size_read(inode)) {
-               if (attr->ia_size > sb->s_maxbytes) {
-                       status = -EFBIG;
+               status = inode_newsize_ok(inode, attr->ia_size);
+               if (status)
                        goto bail_unlock;
-               }
+
+               inode_dio_wait(inode);
 
                if (i_size_read(inode) > attr->ia_size) {
                        if (ocfs2_should_order_data(inode)) {
@@ -975,16 +1179,14 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
                /*
                 * Gather pointers to quota structures so that allocation /
                 * freeing of quota structures happens here and not inside
-                * vfs_dq_transfer() where we have problems with lock ordering
+                * dquot_transfer() where we have problems with lock ordering
                 */
                if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid
                    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
                    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
                        transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid,
                                                      USRQUOTA);
-                       transfer_from[USRQUOTA] = dqget(sb, inode->i_uid,
-                                                       USRQUOTA);
-                       if (!transfer_to[USRQUOTA] || !transfer_from[USRQUOTA]) {
+                       if (!transfer_to[USRQUOTA]) {
                                status = -ESRCH;
                                goto bail_unlock;
                        }
@@ -994,9 +1196,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
                    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
                        transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid,
                                                      GRPQUOTA);
-                       transfer_from[GRPQUOTA] = dqget(sb, inode->i_gid,
-                                                       GRPQUOTA);
-                       if (!transfer_to[GRPQUOTA] || !transfer_from[GRPQUOTA]) {
+                       if (!transfer_to[GRPQUOTA]) {
                                status = -ESRCH;
                                goto bail_unlock;
                        }
@@ -1008,7 +1208,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
                        mlog_errno(status);
                        goto bail_unlock;
                }
-               status = vfs_dq_transfer(inode, attr) ? -EDQUOT : 0;
+               status = __dquot_transfer(inode, transfer_to);
                if (status < 0)
                        goto bail_commit;
        } else {
@@ -1021,18 +1221,26 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
        }
 
        /*
-        * This will intentionally not wind up calling vmtruncate(),
+        * This will intentionally not wind up calling truncate_setsize(),
         * since all the work for a size change has been done above.
         * Otherwise, we could get into problems with truncate as
         * ip_alloc_sem is used there to protect against i_size
         * changes.
+        *
+        * XXX: this means the conditional below can probably be removed.
         */
-       status = inode_setattr(inode, attr);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail_commit;
+       if ((attr->ia_valid & ATTR_SIZE) &&
+           attr->ia_size != i_size_read(inode)) {
+               status = vmtruncate(inode, attr->ia_size);
+               if (status) {
+                       mlog_errno(status);
+                       goto bail_commit;
+               }
        }
 
+       setattr_copy(inode, attr);
+       mark_inode_dirty(inode);
+
        status = ocfs2_mark_inode_dirty(handle, inode, bh);
        if (status < 0)
                mlog_errno(status);
@@ -1048,10 +1256,8 @@ bail:
        brelse(bh);
 
        /* Release quota pointers in case we acquired them */
-       for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
+       for (qtype = 0; qtype < MAXQUOTAS; qtype++)
                dqput(transfer_to[qtype]);
-               dqput(transfer_from[qtype]);
-       }
 
        if (!status && attr->ia_valid & ATTR_MODE) {
                status = ocfs2_acl_chmod(inode);
@@ -1059,7 +1265,6 @@ bail:
                        mlog_errno(status);
        }
 
-       mlog_exit(status);
        return status;
 }
 
@@ -1072,8 +1277,6 @@ int ocfs2_getattr(struct vfsmount *mnt,
        struct ocfs2_super *osb = sb->s_fs_info;
        int err;
 
-       mlog_entry_void();
-
        err = ocfs2_inode_revalidate(dentry);
        if (err) {
                if (err != -ENOENT)
@@ -1087,8 +1290,6 @@ int ocfs2_getattr(struct vfsmount *mnt,
        stat->blksize = osb->s_clustersize;
 
 bail:
-       mlog_exit(err);
-
        return err;
 }
 
@@ -1096,7 +1297,8 @@ int ocfs2_permission(struct inode *inode, int mask)
 {
        int ret;
 
-       mlog_entry_void();
+       if (mask & MAY_NOT_BLOCK)
+               return -ECHILD;
 
        ret = ocfs2_inode_lock(inode, NULL, 0);
        if (ret) {
@@ -1105,11 +1307,10 @@ int ocfs2_permission(struct inode *inode, int mask)
                goto out;
        }
 
-       ret = generic_permission(inode, mask, ocfs2_check_acl);
+       ret = generic_permission(inode, mask);
 
        ocfs2_inode_unlock(inode, 0);
 out:
-       mlog_exit(ret);
        return ret;
 }
 
@@ -1121,8 +1322,9 @@ static int __ocfs2_write_remove_suid(struct inode *inode,
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct ocfs2_dinode *di;
 
-       mlog_entry("(Inode %llu, mode 0%o)\n",
-                  (unsigned long long)OCFS2_I(inode)->ip_blkno, inode->i_mode);
+       trace_ocfs2_write_remove_suid(
+                       (unsigned long long)OCFS2_I(inode)->ip_blkno,
+                       inode->i_mode);
 
        handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
        if (IS_ERR(handle)) {
@@ -1131,7 +1333,7 @@ static int __ocfs2_write_remove_suid(struct inode *inode,
                goto out;
        }
 
-       ret = ocfs2_journal_access_di(handle, inode, bh,
+       ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), bh,
                                      OCFS2_JOURNAL_ACCESS_WRITE);
        if (ret < 0) {
                mlog_errno(ret);
@@ -1145,14 +1347,11 @@ static int __ocfs2_write_remove_suid(struct inode *inode,
        di = (struct ocfs2_dinode *) bh->b_data;
        di->i_mode = cpu_to_le16(inode->i_mode);
 
-       ret = ocfs2_journal_dirty(handle, bh);
-       if (ret < 0)
-               mlog_errno(ret);
+       ocfs2_journal_dirty(handle, bh);
 
 out_trans:
        ocfs2_commit_trans(osb, handle);
 out:
-       mlog_exit(ret);
        return ret;
 }
 
@@ -1331,8 +1530,9 @@ static int ocfs2_zero_partial_clusters(struct inode *inode,
         * partial clusters here. There's no need to worry about
         * physical allocation - the zeroing code knows to skip holes.
         */
-       mlog(0, "byte start: %llu, end: %llu\n",
-            (unsigned long long)start, (unsigned long long)end);
+       trace_ocfs2_zero_partial_clusters(
+               (unsigned long long)OCFS2_I(inode)->ip_blkno,
+               (unsigned long long)start, (unsigned long long)end);
 
        /*
         * If both edges are on a cluster boundary then there's no
@@ -1356,8 +1556,8 @@ static int ocfs2_zero_partial_clusters(struct inode *inode,
        if (tmpend > end)
                tmpend = end;
 
-       mlog(0, "1st range: start: %llu, tmpend: %llu\n",
-            (unsigned long long)start, (unsigned long long)tmpend);
+       trace_ocfs2_zero_partial_clusters_range1((unsigned long long)start,
+                                                (unsigned long long)tmpend);
 
        ret = ocfs2_zero_range_for_truncate(inode, handle, start, tmpend);
        if (ret)
@@ -1371,8 +1571,8 @@ static int ocfs2_zero_partial_clusters(struct inode *inode,
                 */
                start = end & ~(osb->s_clustersize - 1);
 
-               mlog(0, "2nd range: start: %llu, end: %llu\n",
-                    (unsigned long long)start, (unsigned long long)end);
+               trace_ocfs2_zero_partial_clusters_range2(
+                       (unsigned long long)start, (unsigned long long)end);
 
                ret = ocfs2_zero_range_for_truncate(inode, handle, start, end);
                if (ret)
@@ -1384,20 +1584,111 @@ out:
        return ret;
 }
 
+static int ocfs2_find_rec(struct ocfs2_extent_list *el, u32 pos)
+{
+       int i;
+       struct ocfs2_extent_rec *rec = NULL;
+
+       for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) {
+
+               rec = &el->l_recs[i];
+
+               if (le32_to_cpu(rec->e_cpos) < pos)
+                       break;
+       }
+
+       return i;
+}
+
+/*
+ * Helper to calculate the punching pos and length in one run, we handle the
+ * following three cases in order:
+ *
+ * - remove the entire record
+ * - remove a partial record
+ * - no record needs to be removed (hole-punching completed)
+*/
+static void ocfs2_calc_trunc_pos(struct inode *inode,
+                                struct ocfs2_extent_list *el,
+                                struct ocfs2_extent_rec *rec,
+                                u32 trunc_start, u32 *trunc_cpos,
+                                u32 *trunc_len, u32 *trunc_end,
+                                u64 *blkno, int *done)
+{
+       int ret = 0;
+       u32 coff, range;
+
+       range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec);
+
+       if (le32_to_cpu(rec->e_cpos) >= trunc_start) {
+               /*
+                * remove an entire extent record.
+                */
+               *trunc_cpos = le32_to_cpu(rec->e_cpos);
+               /*
+                * Skip holes if any.
+                */
+               if (range < *trunc_end)
+                       *trunc_end = range;
+               *trunc_len = *trunc_end - le32_to_cpu(rec->e_cpos);
+               *blkno = le64_to_cpu(rec->e_blkno);
+               *trunc_end = le32_to_cpu(rec->e_cpos);
+       } else if (range > trunc_start) {
+               /*
+                * remove a partial extent record, which means we're
+                * removing the last extent record.
+                */
+               *trunc_cpos = trunc_start;
+               /*
+                * skip hole if any.
+                */
+               if (range < *trunc_end)
+                       *trunc_end = range;
+               *trunc_len = *trunc_end - trunc_start;
+               coff = trunc_start - le32_to_cpu(rec->e_cpos);
+               *blkno = le64_to_cpu(rec->e_blkno) +
+                               ocfs2_clusters_to_blocks(inode->i_sb, coff);
+               *trunc_end = trunc_start;
+       } else {
+               /*
+                * It may have two following possibilities:
+                *
+                * - last record has been removed
+                * - trunc_start was within a hole
+                *
+                * both two cases mean the completion of hole punching.
+                */
+               ret = 1;
+       }
+
+       *done = ret;
+}
+
 static int ocfs2_remove_inode_range(struct inode *inode,
                                    struct buffer_head *di_bh, u64 byte_start,
                                    u64 byte_len)
 {
-       int ret = 0;
-       u32 trunc_start, trunc_len, cpos, phys_cpos, alloc_size;
+       int ret = 0, flags = 0, done = 0, i;
+       u32 trunc_start, trunc_len, trunc_end, trunc_cpos, phys_cpos;
+       u32 cluster_in_el;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct ocfs2_cached_dealloc_ctxt dealloc;
        struct address_space *mapping = inode->i_mapping;
        struct ocfs2_extent_tree et;
+       struct ocfs2_path *path = NULL;
+       struct ocfs2_extent_list *el = NULL;
+       struct ocfs2_extent_rec *rec = NULL;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       u64 blkno, refcount_loc = le64_to_cpu(di->i_refcount_loc);
 
-       ocfs2_init_dinode_extent_tree(&et, inode, di_bh);
+       ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh);
        ocfs2_init_dealloc_ctxt(&dealloc);
 
+       trace_ocfs2_remove_inode_range(
+                       (unsigned long long)OCFS2_I(inode)->ip_blkno,
+                       (unsigned long long)byte_start,
+                       (unsigned long long)byte_len);
+
        if (byte_len == 0)
                return 0;
 
@@ -1419,17 +1710,30 @@ static int ocfs2_remove_inode_range(struct inode *inode,
                goto out;
        }
 
-       trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start);
-       trunc_len = (byte_start + byte_len) >> osb->s_clustersize_bits;
-       if (trunc_len >= trunc_start)
-               trunc_len -= trunc_start;
-       else
-               trunc_len = 0;
+       /*
+        * For reflinks, we may need to CoW 2 clusters which might be
+        * partially zero'd later, if hole's start and end offset were
+        * within one cluster(means is not exactly aligned to clustersize).
+        */
+
+       if (OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL) {
+
+               ret = ocfs2_cow_file_pos(inode, di_bh, byte_start);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
 
-       mlog(0, "Inode: %llu, start: %llu, len: %llu, cstart: %u, clen: %u\n",
-            (unsigned long long)OCFS2_I(inode)->ip_blkno,
-            (unsigned long long)byte_start,
-            (unsigned long long)byte_len, trunc_start, trunc_len);
+               ret = ocfs2_cow_file_pos(inode, di_bh, byte_start + byte_len);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start);
+       trunc_end = (byte_start + byte_len) >> osb->s_clustersize_bits;
+       cluster_in_el = trunc_end;
 
        ret = ocfs2_zero_partial_clusters(inode, byte_start, byte_len);
        if (ret) {
@@ -1437,31 +1741,79 @@ static int ocfs2_remove_inode_range(struct inode *inode,
                goto out;
        }
 
-       cpos = trunc_start;
-       while (trunc_len) {
-               ret = ocfs2_get_clusters(inode, cpos, &phys_cpos,
-                                        &alloc_size, NULL);
+       path = ocfs2_new_path_from_et(&et);
+       if (!path) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       while (trunc_end > trunc_start) {
+
+               ret = ocfs2_find_path(INODE_CACHE(inode), path,
+                                     cluster_in_el);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
                }
 
-               if (alloc_size > trunc_len)
-                       alloc_size = trunc_len;
+               el = path_leaf_el(path);
+
+               i = ocfs2_find_rec(el, trunc_end);
+               /*
+                * Need to go to previous extent block.
+                */
+               if (i < 0) {
+                       if (path->p_tree_depth == 0)
+                               break;
 
-               /* Only do work for non-holes */
-               if (phys_cpos != 0) {
-                       ret = ocfs2_remove_btree_range(inode, &et, cpos,
-                                                      phys_cpos, alloc_size,
-                                                      &dealloc);
+                       ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb,
+                                                           path,
+                                                           &cluster_in_el);
                        if (ret) {
                                mlog_errno(ret);
                                goto out;
                        }
+
+                       /*
+                        * We've reached the leftmost extent block,
+                        * it's safe to leave.
+                        */
+                       if (cluster_in_el == 0)
+                               break;
+
+                       /*
+                        * The 'pos' searched for previous extent block is
+                        * always one cluster less than actual trunc_end.
+                        */
+                       trunc_end = cluster_in_el + 1;
+
+                       ocfs2_reinit_path(path, 1);
+
+                       continue;
+
+               } else
+                       rec = &el->l_recs[i];
+
+               ocfs2_calc_trunc_pos(inode, el, rec, trunc_start, &trunc_cpos,
+                                    &trunc_len, &trunc_end, &blkno, &done);
+               if (done)
+                       break;
+
+               flags = rec->e_flags;
+               phys_cpos = ocfs2_blocks_to_clusters(inode->i_sb, blkno);
+
+               ret = ocfs2_remove_btree_range(inode, &et, trunc_cpos,
+                                              phys_cpos, trunc_len, flags,
+                                              &dealloc, refcount_loc);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
                }
 
-               cpos += alloc_size;
-               trunc_len -= alloc_size;
+               cluster_in_el = trunc_end;
+
+               ocfs2_reinit_path(path, 1);
        }
 
        ocfs2_truncate_cluster_pages(inode, byte_start, byte_len);
@@ -1598,6 +1950,9 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
        if (ret < 0)
                mlog_errno(ret);
 
+       if (file && (file->f_flags & O_SYNC))
+               handle->h_sync = 1;
+
        ocfs2_commit_trans(osb, handle);
 
 out_inode_unlock:
@@ -1633,41 +1988,130 @@ int ocfs2_change_file_space(struct file *file, unsigned int cmd,
        return __ocfs2_change_file_space(file, inode, file->f_pos, cmd, sr, 0);
 }
 
-static long ocfs2_fallocate(struct inode *inode, int mode, loff_t offset,
+static long ocfs2_fallocate(struct file *file, int mode, loff_t offset,
                            loff_t len)
 {
+       struct inode *inode = file->f_path.dentry->d_inode;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct ocfs2_space_resv sr;
        int change_size = 1;
+       int cmd = OCFS2_IOC_RESVSP64;
 
+       if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
+               return -EOPNOTSUPP;
        if (!ocfs2_writes_unwritten_extents(osb))
                return -EOPNOTSUPP;
 
-       if (S_ISDIR(inode->i_mode))
-               return -ENODEV;
-
        if (mode & FALLOC_FL_KEEP_SIZE)
                change_size = 0;
 
+       if (mode & FALLOC_FL_PUNCH_HOLE)
+               cmd = OCFS2_IOC_UNRESVSP64;
+
        sr.l_whence = 0;
        sr.l_start = (s64)offset;
        sr.l_len = (s64)len;
 
-       return __ocfs2_change_file_space(NULL, inode, offset,
-                                        OCFS2_IOC_RESVSP64, &sr, change_size);
+       return __ocfs2_change_file_space(NULL, inode, offset, cmd, &sr,
+                                        change_size);
+}
+
+int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos,
+                                  size_t count)
+{
+       int ret = 0;
+       unsigned int extent_flags;
+       u32 cpos, clusters, extent_len, phys_cpos;
+       struct super_block *sb = inode->i_sb;
+
+       if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)) ||
+           !(OCFS2_I(inode)->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL) ||
+           OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+               return 0;
+
+       cpos = pos >> OCFS2_SB(sb)->s_clustersize_bits;
+       clusters = ocfs2_clusters_for_bytes(sb, pos + count) - cpos;
+
+       while (clusters) {
+               ret = ocfs2_get_clusters(inode, cpos, &phys_cpos, &extent_len,
+                                        &extent_flags);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               if (phys_cpos && (extent_flags & OCFS2_EXT_REFCOUNTED)) {
+                       ret = 1;
+                       break;
+               }
+
+               if (extent_len > clusters)
+                       extent_len = clusters;
+
+               clusters -= extent_len;
+               cpos += extent_len;
+       }
+out:
+       return ret;
+}
+
+static void ocfs2_aiodio_wait(struct inode *inode)
+{
+       wait_queue_head_t *wq = ocfs2_ioend_wq(inode);
+
+       wait_event(*wq, (atomic_read(&OCFS2_I(inode)->ip_unaligned_aio) == 0));
+}
+
+static int ocfs2_is_io_unaligned(struct inode *inode, size_t count, loff_t pos)
+{
+       int blockmask = inode->i_sb->s_blocksize - 1;
+       loff_t final_size = pos + count;
+
+       if ((pos & blockmask) || (final_size & blockmask))
+               return 1;
+       return 0;
 }
 
-static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
+static int ocfs2_prepare_inode_for_refcount(struct inode *inode,
+                                           struct file *file,
+                                           loff_t pos, size_t count,
+                                           int *meta_level)
+{
+       int ret;
+       struct buffer_head *di_bh = NULL;
+       u32 cpos = pos >> OCFS2_SB(inode->i_sb)->s_clustersize_bits;
+       u32 clusters =
+               ocfs2_clusters_for_bytes(inode->i_sb, pos + count) - cpos;
+
+       ret = ocfs2_inode_lock(inode, &di_bh, 1);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       *meta_level = 1;
+
+       ret = ocfs2_refcount_cow(inode, file, di_bh, cpos, clusters, UINT_MAX);
+       if (ret)
+               mlog_errno(ret);
+out:
+       brelse(di_bh);
+       return ret;
+}
+
+static int ocfs2_prepare_inode_for_write(struct file *file,
                                         loff_t *ppos,
                                         size_t count,
                                         int appending,
-                                        int *direct_io)
+                                        int *direct_io,
+                                        int *has_refcount)
 {
        int ret = 0, meta_level = 0;
+       struct dentry *dentry = file->f_path.dentry;
        struct inode *inode = dentry->d_inode;
-       loff_t saved_pos, end;
+       loff_t saved_pos = 0, end;
 
-       /* 
+       /*
         * We start with a read level meta lock and only jump to an ex
         * if we need to make modifications here.
         */
@@ -1684,7 +2128,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
                 * remove_suid() calls ->setattr without any hint that
                 * we may have already done our cluster locking. Since
                 * ocfs2_setattr() *must* take cluster locks to
-                * proceeed, this will lead us to recursively lock the
+                * proceed, this will lead us to recursively lock the
                 * inode. There's also the dinode i_size state which
                 * can be lost via setattr during extending writes (we
                 * set inode->i_size at the end of a write. */
@@ -1704,15 +2148,34 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
 
                /* work on a copy of ppos until we're sure that we won't have
                 * to recalculate it due to relocking. */
-               if (appending) {
+               if (appending)
                        saved_pos = i_size_read(inode);
-                       mlog(0, "O_APPEND: inode->i_size=%llu\n", saved_pos);
-               } else {
+               else
                        saved_pos = *ppos;
-               }
 
                end = saved_pos + count;
 
+               ret = ocfs2_check_range_for_refcount(inode, saved_pos, count);
+               if (ret == 1) {
+                       ocfs2_inode_unlock(inode, meta_level);
+                       meta_level = -1;
+
+                       ret = ocfs2_prepare_inode_for_refcount(inode,
+                                                              file,
+                                                              saved_pos,
+                                                              count,
+                                                              &meta_level);
+                       if (has_refcount)
+                               *has_refcount = 1;
+                       if (direct_io)
+                               *direct_io = 0;
+               }
+
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out_unlock;
+               }
+
                /*
                 * Skip the O_DIRECT checks if we don't need
                 * them.
@@ -1759,7 +2222,12 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
                *ppos = saved_pos;
 
 out_unlock:
-       ocfs2_inode_unlock(inode, meta_level);
+       trace_ocfs2_prepare_inode_for_write(OCFS2_I(inode)->ip_blkno,
+                                           saved_pos, appending, count,
+                                           direct_io, has_refcount);
+
+       if (meta_level >= 0)
+               ocfs2_inode_unlock(inode, meta_level);
 
 out:
        return ret;
@@ -1771,7 +2239,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
                                    loff_t pos)
 {
        int ret, direct_io, appending, rw_level, have_alloc_sem  = 0;
-       int can_do_direct;
+       int can_do_direct, has_refcount = 0;
        ssize_t written = 0;
        size_t ocount;          /* original count */
        size_t count;           /* after file limit checks */
@@ -1780,11 +2248,15 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_path.dentry->d_inode;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       int full_coherency = !(osb->s_mount_opt &
+                              OCFS2_MOUNT_COHERENCY_BUFFERED);
+       int unaligned_dio = 0;
 
-       mlog_entry("(0x%p, %u, '%.*s')\n", file,
-                  (unsigned int)nr_segs,
-                  file->f_path.dentry->d_name.len,
-                  file->f_path.dentry->d_name.name);
+       trace_ocfs2_file_aio_write(inode, file, file->f_path.dentry,
+               (unsigned long long)OCFS2_I(inode)->ip_blkno,
+               file->f_path.dentry->d_name.len,
+               file->f_path.dentry->d_name.name,
+               (unsigned int)nr_segs);
 
        if (iocb->ki_left == 0)
                return 0;
@@ -1796,37 +2268,66 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
 
        mutex_lock(&inode->i_mutex);
 
+       ocfs2_iocb_clear_sem_locked(iocb);
+
 relock:
-       /* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */
+       /* to match setattr's i_mutex -> rw_lock ordering */
        if (direct_io) {
-               down_read(&inode->i_alloc_sem);
                have_alloc_sem = 1;
+               /* communicate with ocfs2_dio_end_io */
+               ocfs2_iocb_set_sem_locked(iocb);
        }
 
-       /* concurrent O_DIRECT writes are allowed */
-       rw_level = !direct_io;
+       /*
+        * Concurrent O_DIRECT writes are allowed with
+        * mount_option "coherency=buffered".
+        */
+       rw_level = (!direct_io || full_coherency);
+
        ret = ocfs2_rw_lock(inode, rw_level);
        if (ret < 0) {
                mlog_errno(ret);
                goto out_sems;
        }
 
+       /*
+        * O_DIRECT writes with "coherency=full" need to take EX cluster
+        * inode_lock to guarantee coherency.
+        */
+       if (direct_io && full_coherency) {
+               /*
+                * We need to take and drop the inode lock to force
+                * other nodes to drop their caches.  Buffered I/O
+                * already does this in write_begin().
+                */
+               ret = ocfs2_inode_lock(inode, NULL, 1);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out_sems;
+               }
+
+               ocfs2_inode_unlock(inode, 1);
+       }
+
        can_do_direct = direct_io;
-       ret = ocfs2_prepare_inode_for_write(file->f_path.dentry, ppos,
+       ret = ocfs2_prepare_inode_for_write(file, ppos,
                                            iocb->ki_left, appending,
-                                           &can_do_direct);
+                                           &can_do_direct, &has_refcount);
        if (ret < 0) {
                mlog_errno(ret);
                goto out;
        }
 
+       if (direct_io && !is_sync_kiocb(iocb))
+               unaligned_dio = ocfs2_is_io_unaligned(inode, iocb->ki_left,
+                                                     *ppos);
+
        /*
         * We can't complete the direct I/O as requested, fall back to
         * buffered I/O.
         */
        if (direct_io && !can_do_direct) {
                ocfs2_rw_unlock(inode, rw_level);
-               up_read(&inode->i_alloc_sem);
 
                have_alloc_sem = 0;
                rw_level = -1;
@@ -1835,6 +2336,18 @@ relock:
                goto relock;
        }
 
+       if (unaligned_dio) {
+               /*
+                * Wait on previous unaligned aio to complete before
+                * proceeding.
+                */
+               ocfs2_aiodio_wait(inode);
+
+               /* Mark the iocb as needing a decrement in ocfs2_dio_end_io */
+               atomic_inc(&OCFS2_I(inode)->ip_unaligned_aio);
+               ocfs2_iocb_set_unaligned_aio(iocb);
+       }
+
        /*
         * To later detect whether a journal commit for sync writes is
         * necessary, we sample i_size, and cluster count here.
@@ -1845,47 +2358,45 @@ relock:
        /* communicate with ocfs2_dio_end_io */
        ocfs2_iocb_set_rw_locked(iocb, rw_level);
 
-       if (direct_io) {
-               ret = generic_segment_checks(iov, &nr_segs, &ocount,
-                                            VERIFY_READ);
-               if (ret)
-                       goto out_dio;
+       ret = generic_segment_checks(iov, &nr_segs, &ocount,
+                                    VERIFY_READ);
+       if (ret)
+               goto out_dio;
 
-               count = ocount;
-               ret = generic_write_checks(file, ppos, &count,
-                                          S_ISBLK(inode->i_mode));
-               if (ret)
-                       goto out_dio;
+       count = ocount;
+       ret = generic_write_checks(file, ppos, &count,
+                                  S_ISBLK(inode->i_mode));
+       if (ret)
+               goto out_dio;
 
+       if (direct_io) {
                written = generic_file_direct_write(iocb, iov, &nr_segs, *ppos,
                                                    ppos, count, ocount);
                if (written < 0) {
-                       /*
-                        * direct write may have instantiated a few
-                        * blocks outside i_size. Trim these off again.
-                        * Don't need i_size_read because we hold i_mutex.
-                        */
-                       if (*ppos + count > inode->i_size)
-                               vmtruncate(inode, inode->i_size);
                        ret = written;
                        goto out_dio;
                }
        } else {
-               written = __generic_file_aio_write(iocb, iov, nr_segs, ppos);
+               current->backing_dev_info = file->f_mapping->backing_dev_info;
+               written = generic_file_buffered_write(iocb, iov, nr_segs, *ppos,
+                                                     ppos, count, 0);
+               current->backing_dev_info = NULL;
        }
 
 out_dio:
        /* buffered aio wouldn't have proper lock coverage today */
        BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT));
 
-       if ((file->f_flags & O_SYNC && !direct_io) || IS_SYNC(inode)) {
+       if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) ||
+           ((file->f_flags & O_DIRECT) && !direct_io)) {
                ret = filemap_fdatawrite_range(file->f_mapping, pos,
                                               pos + count - 1);
                if (ret < 0)
                        written = ret;
 
-               if (!ret && (old_size != i_size_read(inode) ||
-                   old_clusters != OCFS2_I(inode)->ip_clusters)) {
+               if (!ret && ((old_size != i_size_read(inode)) ||
+                            (old_clusters != OCFS2_I(inode)->ip_clusters) ||
+                            has_refcount)) {
                        ret = jbd2_journal_force_commit(osb->journal->j_journal);
                        if (ret < 0)
                                written = ret;
@@ -1896,19 +2407,24 @@ out_dio:
                                                      pos + count - 1);
        }
 
-       /* 
+       /*
         * deep in g_f_a_w_n()->ocfs2_direct_IO we pass in a ocfs2_dio_end_io
         * function pointer which is called when o_direct io completes so that
-        * it can unlock our rw lock.  (it's the clustered equivalent of
-        * i_alloc_sem; protects truncate from racing with pending ios).
+        * it can unlock our rw lock.
         * Unfortunately there are error cases which call end_io and others
         * that don't.  so we don't have to unlock the rw_lock if either an
         * async dio is going to do it in the future or an end_io after an
         * error has already done it.
         */
-       if (ret == -EIOCBQUEUED || !ocfs2_iocb_is_rw_locked(iocb)) {
+       if ((ret == -EIOCBQUEUED) || (!ocfs2_iocb_is_rw_locked(iocb))) {
                rw_level = -1;
                have_alloc_sem = 0;
+               unaligned_dio = 0;
+       }
+
+       if (unaligned_dio) {
+               ocfs2_iocb_clear_unaligned_aio(iocb);
+               atomic_dec(&OCFS2_I(inode)->ip_unaligned_aio);
        }
 
 out:
@@ -1917,13 +2433,12 @@ out:
 
 out_sems:
        if (have_alloc_sem)
-               up_read(&inode->i_alloc_sem);
+               ocfs2_iocb_clear_sem_locked(iocb);
 
        mutex_unlock(&inode->i_mutex);
 
        if (written)
                ret = written;
-       mlog_exit(ret);
        return ret;
 }
 
@@ -1933,8 +2448,8 @@ static int ocfs2_splice_to_file(struct pipe_inode_info *pipe,
 {
        int ret;
 
-       ret = ocfs2_prepare_inode_for_write(out->f_path.dentry, &sd->pos,
-                                           sd->total_len, 0, NULL);
+       ret = ocfs2_prepare_inode_for_write(out, &sd->pos,
+                                           sd->total_len, 0, NULL, NULL);
        if (ret < 0) {
                mlog_errno(ret);
                return ret;
@@ -1959,10 +2474,11 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe,
                .u.file = out,
        };
 
-       mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", out, pipe,
-                  (unsigned int)len,
-                  out->f_path.dentry->d_name.len,
-                  out->f_path.dentry->d_name.name);
+
+       trace_ocfs2_file_splice_write(inode, out, out->f_path.dentry,
+                       (unsigned long long)OCFS2_I(inode)->ip_blkno,
+                       out->f_path.dentry->d_name.len,
+                       out->f_path.dentry->d_name.name, len);
 
        if (pipe->inode)
                mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_PARENT);
@@ -1993,35 +2509,19 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe,
 
        if (ret > 0) {
                unsigned long nr_pages;
+               int err;
 
-               *ppos += ret;
                nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 
-               /*
-                * If file or inode is SYNC and we actually wrote some data,
-                * sync it.
-                */
-               if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) {
-                       int err;
-
-                       mutex_lock(&inode->i_mutex);
-                       err = ocfs2_rw_lock(inode, 1);
-                       if (err < 0) {
-                               mlog_errno(err);
-                       } else {
-                               err = generic_osync_inode(inode, mapping,
-                                                 OSYNC_METADATA|OSYNC_DATA);
-                               ocfs2_rw_unlock(inode, 1);
-                       }
-                       mutex_unlock(&inode->i_mutex);
+               err = generic_write_sync(out, *ppos, ret);
+               if (err)
+                       ret = err;
+               else
+                       *ppos += ret;
 
-                       if (err)
-                               ret = err;
-               }
                balance_dirty_pages_ratelimited_nr(mapping, nr_pages);
        }
 
-       mlog_exit(ret);
        return ret;
 }
 
@@ -2034,10 +2534,10 @@ static ssize_t ocfs2_file_splice_read(struct file *in,
        int ret = 0, lock_level = 0;
        struct inode *inode = in->f_path.dentry->d_inode;
 
-       mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", in, pipe,
-                  (unsigned int)len,
-                  in->f_path.dentry->d_name.len,
-                  in->f_path.dentry->d_name.name);
+       trace_ocfs2_file_splice_read(inode, in, in->f_path.dentry,
+                       (unsigned long long)OCFS2_I(inode)->ip_blkno,
+                       in->f_path.dentry->d_name.len,
+                       in->f_path.dentry->d_name.name, len);
 
        /*
         * See the comment in ocfs2_file_aio_read()
@@ -2052,7 +2552,6 @@ static ssize_t ocfs2_file_splice_read(struct file *in,
        ret = generic_file_splice_read(in, ppos, pipe, len, flags);
 
 bail:
-       mlog_exit(ret);
        return ret;
 }
 
@@ -2065,10 +2564,11 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
        struct file *filp = iocb->ki_filp;
        struct inode *inode = filp->f_path.dentry->d_inode;
 
-       mlog_entry("(0x%p, %u, '%.*s')\n", filp,
-                  (unsigned int)nr_segs,
-                  filp->f_path.dentry->d_name.len,
-                  filp->f_path.dentry->d_name.name);
+       trace_ocfs2_file_aio_read(inode, filp, filp->f_path.dentry,
+                       (unsigned long long)OCFS2_I(inode)->ip_blkno,
+                       filp->f_path.dentry->d_name.len,
+                       filp->f_path.dentry->d_name.name, nr_segs);
+
 
        if (!inode) {
                ret = -EINVAL;
@@ -2076,13 +2576,15 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
                goto bail;
        }
 
-       /* 
+       ocfs2_iocb_clear_sem_locked(iocb);
+
+       /*
         * buffered reads protect themselves in ->readpage().  O_DIRECT reads
         * need locks to protect pending reads from racing with truncate.
         */
        if (filp->f_flags & O_DIRECT) {
-               down_read(&inode->i_alloc_sem);
                have_alloc_sem = 1;
+               ocfs2_iocb_set_sem_locked(iocb);
 
                ret = ocfs2_rw_lock(inode, 0);
                if (ret < 0) {
@@ -2098,10 +2600,10 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
         * We're fine letting folks race truncates and extending
         * writes with read across the cluster, just like they can
         * locally. Hence no rw_lock during read.
-        * 
+        *
         * Take and drop the meta data lock to update inode fields
         * like i_size. This allows the checks down below
-        * generic_file_aio_read() a chance of actually working. 
+        * generic_file_aio_read() a chance of actually working.
         */
        ret = ocfs2_inode_lock_atime(inode, filp->f_vfsmnt, &lock_level);
        if (ret < 0) {
@@ -2111,8 +2613,7 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
        ocfs2_inode_unlock(inode, lock_level);
 
        ret = generic_file_aio_read(iocb, iov, nr_segs, iocb->ki_pos);
-       if (ret == -EINVAL)
-               mlog(0, "generic_file_aio_read returned -EINVAL\n");
+       trace_generic_file_aio_read_ret(ret);
 
        /* buffered aio wouldn't have proper lock coverage today */
        BUG_ON(ret == -EIOCBQUEUED && !(filp->f_flags & O_DIRECT));
@@ -2125,14 +2626,65 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
 
 bail:
        if (have_alloc_sem)
-               up_read(&inode->i_alloc_sem);
-       if (rw_level != -1) 
+               ocfs2_iocb_clear_sem_locked(iocb);
+
+       if (rw_level != -1)
                ocfs2_rw_unlock(inode, rw_level);
-       mlog_exit(ret);
 
        return ret;
 }
 
+/* Refer generic_file_llseek_unlocked() */
+static loff_t ocfs2_file_llseek(struct file *file, loff_t offset, int origin)
+{
+       struct inode *inode = file->f_mapping->host;
+       int ret = 0;
+
+       mutex_lock(&inode->i_mutex);
+
+       switch (origin) {
+       case SEEK_SET:
+               break;
+       case SEEK_END:
+               offset += inode->i_size;
+               break;
+       case SEEK_CUR:
+               if (offset == 0) {
+                       offset = file->f_pos;
+                       goto out;
+               }
+               offset += file->f_pos;
+               break;
+       case SEEK_DATA:
+       case SEEK_HOLE:
+               ret = ocfs2_seek_data_hole_offset(file, &offset, origin);
+               if (ret)
+                       goto out;
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET))
+               ret = -EINVAL;
+       if (!ret && offset > inode->i_sb->s_maxbytes)
+               ret = -EINVAL;
+       if (ret)
+               goto out;
+
+       if (offset != file->f_pos) {
+               file->f_pos = offset;
+               file->f_version = 0;
+       }
+
+out:
+       mutex_unlock(&inode->i_mutex);
+       if (ret)
+               return ret;
+       return offset;
+}
+
 const struct inode_operations ocfs2_file_iops = {
        .setattr        = ocfs2_setattr,
        .getattr        = ocfs2_getattr,
@@ -2141,14 +2693,15 @@ const struct inode_operations ocfs2_file_iops = {
        .getxattr       = generic_getxattr,
        .listxattr      = ocfs2_listxattr,
        .removexattr    = generic_removexattr,
-       .fallocate      = ocfs2_fallocate,
        .fiemap         = ocfs2_fiemap,
+       .get_acl        = ocfs2_iop_get_acl,
 };
 
 const struct inode_operations ocfs2_special_file_iops = {
        .setattr        = ocfs2_setattr,
        .getattr        = ocfs2_getattr,
        .permission     = ocfs2_permission,
+       .get_acl        = ocfs2_iop_get_acl,
 };
 
 /*
@@ -2156,7 +2709,7 @@ const struct inode_operations ocfs2_special_file_iops = {
  * ocfs2_fops_no_plocks and ocfs2_dops_no_plocks!
  */
 const struct file_operations ocfs2_fops = {
-       .llseek         = generic_file_llseek,
+       .llseek         = ocfs2_file_llseek,
        .read           = do_sync_read,
        .write          = do_sync_write,
        .mmap           = ocfs2_mmap,
@@ -2173,6 +2726,7 @@ const struct file_operations ocfs2_fops = {
        .flock          = ocfs2_flock,
        .splice_read    = ocfs2_file_splice_read,
        .splice_write   = ocfs2_file_splice_write,
+       .fallocate      = ocfs2_fallocate,
 };
 
 const struct file_operations ocfs2_dops = {
@@ -2203,7 +2757,7 @@ const struct file_operations ocfs2_dops = {
  * the cluster.
  */
 const struct file_operations ocfs2_fops_no_plocks = {
-       .llseek         = generic_file_llseek,
+       .llseek         = ocfs2_file_llseek,
        .read           = do_sync_read,
        .write          = do_sync_write,
        .mmap           = ocfs2_mmap,
@@ -2219,6 +2773,7 @@ const struct file_operations ocfs2_fops_no_plocks = {
        .flock          = ocfs2_flock,
        .splice_read    = ocfs2_file_splice_read,
        .splice_write   = ocfs2_file_splice_write,
+       .fallocate      = ocfs2_fallocate,
 };
 
 const struct file_operations ocfs2_dops_no_plocks = {