Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jlbec...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 23 Sep 2009 16:29:20 +0000 (09:29 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 23 Sep 2009 16:29:20 +0000 (09:29 -0700)
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jlbec/ocfs2: (85 commits)
  ocfs2: Use buffer IO if we are appending a file.
  ocfs2: add spinlock protection when dealing with lockres->purge.
  dlmglue.c: add missed mlog lines
  ocfs2: __ocfs2_abort() should not enable panic for local mounts
  ocfs2: Add ioctl for reflink.
  ocfs2: Enable refcount tree support.
  ocfs2: Implement ocfs2_reflink.
  ocfs2: Add preserve to reflink.
  ocfs2: Create reflinked file in orphan dir.
  ocfs2: Use proper parameter for some inode operation.
  ocfs2: Make transaction extend more efficient.
  ocfs2: Don't merge in 1st refcount ops of reflink.
  ocfs2: Modify removing xattr process for refcount.
  ocfs2: Add reflink support for xattr.
  ocfs2: Create an xattr indexed block if needed.
  ocfs2: Call refcount tree remove process properly.
  ocfs2: Attach xattr clusters to refcount tree.
  ocfs2: Abstract ocfs2 xattr tree extend rec iteration process.
  ocfs2: Abstract the creation of xattr block.
  ocfs2: Remove inode from ocfs2_xattr_bucket_get_name_value.
  ...

1  2 
fs/ocfs2/file.c
fs/ocfs2/ioctl.c
fs/ocfs2/quota_global.c
fs/ocfs2/super.c

diff --combined fs/ocfs2/file.c
index 221c5e98957b59212e9ad21314bd3645c2f4fbc9,2effac5d030eadc57915f851d45d890c3df1913b..89fc8ee1f5a5932ea40bba6537bd9a8e319f1c84
@@@ -59,6 -59,7 +59,7 @@@
  #include "xattr.h"
  #include "acl.h"
  #include "quota.h"
+ #include "refcounttree.h"
  
  #include "buffer_head_io.h"
  
@@@ -259,7 -260,7 +260,7 @@@ int ocfs2_update_inode_atime(struct ino
                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);
@@@ -334,6 -335,39 +335,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, 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,
  
        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. */
  
                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);
@@@ -486,6 -531,8 +531,8 @@@ 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 -562,10 +562,10 @@@ int ocfs2_add_inode_data(struct ocfs2_s
        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;
  }
@@@ -564,7 -610,7 +610,7 @@@ restart_all
             (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) {
@@@ -593,7 -639,7 +639,7 @@@ restarted_transaction
        /* 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);
@@@ -1131,7 -1177,7 +1177,7 @@@ static int __ocfs2_write_remove_suid(st
                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);
@@@ -1395,7 -1441,7 +1441,7 @@@ static int ocfs2_remove_inode_range(str
        struct address_space *mapping = inode->i_mapping;
        struct ocfs2_extent_tree et;
  
-       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);
  
        if (byte_len == 0)
@@@ -1657,6 -1703,70 +1703,70 @@@ static long ocfs2_fallocate(struct inod
                                         OCFS2_IOC_RESVSP64, &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))
+               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 int ocfs2_prepare_inode_for_refcount(struct inode *inode,
+                                           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, 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 dentry *dentry,
                                         loff_t *ppos,
                                         size_t count,
  
                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,
+                                                              saved_pos,
+                                                              count,
+                                                              &meta_level);
+               }
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out_unlock;
+               }
                /*
                 * Skip the O_DIRECT checks if we don't need
                 * them.
                *ppos = saved_pos;
  
  out_unlock:
-       ocfs2_inode_unlock(inode, meta_level);
+       if (meta_level >= 0)
+               ocfs2_inode_unlock(inode, meta_level);
  
  out:
        return ret;
@@@ -1871,7 -1998,8 +1998,7 @@@ relock
                        goto out_dio;
                }
        } else {
 -              written = generic_file_aio_write_nolock(iocb, iov, nr_segs,
 -                                                      *ppos);
 +              written = __generic_file_aio_write(iocb, iov, nr_segs, ppos);
        }
  
  out_dio:
        BUG_ON(ret == -EIOCBQUEUED && !(file->f_flags & O_DIRECT));
  
        if ((file->f_flags & O_SYNC && !direct_io) || IS_SYNC(inode)) {
 -              /*
 -               * The generic write paths have handled getting data
 -               * to disk, but since we don't make use of the dirty
 -               * inode list, a manual journal commit is necessary
 -               * here.
 -               */
 -              if (old_size != i_size_read(inode) ||
 -                  old_clusters != OCFS2_I(inode)->ip_clusters) {
 +              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)) {
                        ret = jbd2_journal_force_commit(osb->journal->j_journal);
                        if (ret < 0)
                                written = ret;
                }
 +
 +              if (!ret)
 +                      ret = filemap_fdatawait_range(file->f_mapping, pos,
 +                                                    pos + count - 1);
        }
  
        /* 
@@@ -1993,16 -2118,31 +2120,16 @@@ static ssize_t ocfs2_file_splice_write(
  
        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);
        }
  
diff --combined fs/ocfs2/ioctl.c
index 467b413bec21e7b407f45a2adba2002e72504e72,a68d0e4ca6dc17ed10d339ad6c33f7663ba34126..31fbb061951035d3211e1041e5b39bb6ed8d6db9
@@@ -7,6 -7,7 +7,6 @@@
  
  #include <linux/fs.h>
  #include <linux/mount.h>
 -#include <linux/smp_lock.h>
  
  #define MLOG_MASK_PREFIX ML_INODE
  #include <cluster/masklog.h>
@@@ -21,6 -22,7 +21,7 @@@
  #include "ocfs2_fs.h"
  #include "ioctl.h"
  #include "resize.h"
+ #include "refcounttree.h"
  
  #include <linux/ext2_fs.h>
  
@@@ -115,6 -117,9 +116,9 @@@ long ocfs2_ioctl(struct file *filp, uns
        int status;
        struct ocfs2_space_resv sr;
        struct ocfs2_new_group_input input;
+       struct reflink_arguments args;
+       const char *old_path, *new_path;
+       bool preserve;
  
        switch (cmd) {
        case OCFS2_IOC_GETFLAGS:
                        return -EFAULT;
  
                return ocfs2_group_add(inode, &input);
+       case OCFS2_IOC_REFLINK:
+               if (copy_from_user(&args, (struct reflink_arguments *)arg,
+                                  sizeof(args)))
+                       return -EFAULT;
+               old_path = (const char *)(unsigned long)args.old_path;
+               new_path = (const char *)(unsigned long)args.new_path;
+               preserve = (args.preserve != 0);
+               return ocfs2_reflink_ioctl(inode, old_path, new_path, preserve);
        default:
                return -ENOTTY;
        }
@@@ -182,6 -196,7 +195,7 @@@ long ocfs2_compat_ioctl(struct file *fi
        case OCFS2_IOC_GROUP_EXTEND:
        case OCFS2_IOC_GROUP_ADD:
        case OCFS2_IOC_GROUP_ADD64:
+       case OCFS2_IOC_REFLINK:
                break;
        default:
                return -ENOIOCTLCMD;
diff --combined fs/ocfs2/quota_global.c
index 3cf0ec0acdd59efd4ba990f50f7527b2b41ee433,7eadf8bf1e1f458177e58da29231bc20c3d41ccb..b437dc0c4caddd814c824822ff93aa48d26afd65
@@@ -154,7 -154,7 +154,7 @@@ static int ocfs2_get_quota_block(struc
                err = -EIO;
                mlog_errno(err);
        }
 -      return err;;
 +      return err;
  }
  
  /* Read data from global quotafile - avoid pagecache and such because we cannot
@@@ -253,8 -253,9 +253,9 @@@ ssize_t ocfs2_quota_write(struct super_
        flush_dcache_page(bh->b_page);
        set_buffer_uptodate(bh);
        unlock_buffer(bh);
-       ocfs2_set_buffer_uptodate(gqinode, bh);
-       err = ocfs2_journal_access_dq(handle, gqinode, bh, ja_type);
+       ocfs2_set_buffer_uptodate(INODE_CACHE(gqinode), bh);
+       err = ocfs2_journal_access_dq(handle, INODE_CACHE(gqinode), bh,
+                                     ja_type);
        if (err < 0) {
                brelse(bh);
                goto out;
@@@ -849,7 -850,7 +850,7 @@@ static void ocfs2_destroy_dquot(struct 
        kmem_cache_free(ocfs2_dquot_cachep, dquot);
  }
  
 -struct dquot_operations ocfs2_quota_operations = {
 +const struct dquot_operations ocfs2_quota_operations = {
        .initialize     = dquot_initialize,
        .drop           = dquot_drop,
        .alloc_space    = dquot_alloc_space,
diff --combined fs/ocfs2/super.c
index faca4720aa47f18f967405e2ef768ff557c3f40d,154e62522b0595b1eb859ce90a11c7c2a58e0c11..24feb449a1dc1f7329e0784d34b470db520d2684
@@@ -69,6 -69,7 +69,7 @@@
  #include "ver.h"
  #include "xattr.h"
  #include "quota.h"
+ #include "refcounttree.h"
  
  #include "buffer_head_io.h"
  
@@@ -965,7 -966,7 +966,7 @@@ static int ocfs2_quota_off(struct super
        return vfs_quota_disable(sb, type, DQUOT_LIMITS_ENABLED);
  }
  
 -static struct quotactl_ops ocfs2_quotactl_ops = {
 +static const struct quotactl_ops ocfs2_quotactl_ops = {
        .quota_on       = ocfs2_quota_on,
        .quota_off      = ocfs2_quota_off,
        .quota_sync     = vfs_quota_sync,
@@@ -1668,8 -1669,6 +1669,6 @@@ static void ocfs2_inode_init_once(void 
        spin_lock_init(&oi->ip_lock);
        ocfs2_extent_map_init(&oi->vfs_inode);
        INIT_LIST_HEAD(&oi->ip_io_markers);
-       oi->ip_created_trans = 0;
-       oi->ip_last_trans = 0;
        oi->ip_dir_start_lookup = 0;
  
        init_rwsem(&oi->ip_alloc_sem);
        ocfs2_lock_res_init_once(&oi->ip_inode_lockres);
        ocfs2_lock_res_init_once(&oi->ip_open_lockres);
  
-       ocfs2_metadata_cache_init(&oi->vfs_inode);
+       ocfs2_metadata_cache_init(INODE_CACHE(&oi->vfs_inode),
+                                 &ocfs2_inode_caching_ops);
  
        inode_init_once(&oi->vfs_inode);
  }
@@@ -1859,6 -1859,8 +1859,8 @@@ static void ocfs2_dismount_volume(struc
  
        ocfs2_sync_blockdev(sb);
  
+       ocfs2_purge_refcount_trees(osb);
        /* No cluster connection means we've failed during mount, so skip
         * all the steps which depended on that to complete. */
        if (osb->cconn) {
@@@ -2065,6 -2067,8 +2067,8 @@@ static int ocfs2_initialize_super(struc
                goto bail;
        }
  
+       osb->osb_rf_lock_tree = RB_ROOT;
        osb->s_feature_compat =
                le32_to_cpu(OCFS2_RAW_SB(di)->s_feature_compat);
        osb->s_feature_ro_compat =
@@@ -2490,7 -2494,8 +2494,8 @@@ void __ocfs2_abort(struct super_block* 
        /* Force a panic(). This stinks, but it's better than letting
         * things continue without having a proper hard readonly
         * here. */
-       OCFS2_SB(sb)->s_mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
+       if (!ocfs2_mount_local(OCFS2_SB(sb)))
+               OCFS2_SB(sb)->s_mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
        ocfs2_handle_error(sb);
  }