ocfs2: Add extent tree operation for xattr value btrees
authorTao Ma <tao.ma@oracle.com>
Mon, 18 Aug 2008 09:38:48 +0000 (17:38 +0800)
committerMark Fasheh <mfasheh@suse.com>
Mon, 13 Oct 2008 23:57:01 +0000 (16:57 -0700)
Add some thin wrappers around ocfs2_insert_extent() for each of the 3
different btree types, ocfs2_inode_insert_extent(),
ocfs2_xattr_value_insert_extent() and ocfs2_xattr_tree_insert_extent(). The
last is for the xattr index btree, which will be used in a followup patch.

All the old callers in file.c etc will call ocfs2_dinode_insert_extent(),
while the other two handle the xattr issue. And the init of extent tree are
handled by these functions.

When storing xattr value which is too large, we will allocate some clusters
for it and here ocfs2_extent_list and ocfs2_extent_rec will also be used. In
order to re-use the b-tree operation code, a new parameter named "private"
is added into ocfs2_extent_tree and it is used to indicate the root of
ocfs2_exent_list. The reason is that we can't deduce the root from the
buffer_head now. It may be in an inode, an ocfs2_xattr_block or even worse,
in any place in an ocfs2_xattr_bucket.

Signed-off-by: Tao Ma <tao.ma@oracle.com>
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
13 files changed:
fs/ocfs2/Makefile
fs/ocfs2/alloc.c
fs/ocfs2/alloc.h
fs/ocfs2/aops.c
fs/ocfs2/cluster/masklog.c
fs/ocfs2/cluster/masklog.h
fs/ocfs2/dir.c
fs/ocfs2/extent_map.c
fs/ocfs2/extent_map.h
fs/ocfs2/file.c
fs/ocfs2/suballoc.c
fs/ocfs2/suballoc.h
fs/ocfs2/xattr.c [new file with mode: 0644]

index f6956de56fdb8e96b0e592f5ed4b95f98a7d3320..af63980319c365997582c36a1dfd63dcf13ff47e 100644 (file)
@@ -34,7 +34,8 @@ ocfs2-objs := \
        symlink.o               \
        sysfile.o               \
        uptodate.o              \
-       ver.o
+       ver.o                   \
+       xattr.o                 \
 
 ocfs2_stackglue-objs := stackglue.o
 ocfs2_stack_o2cb-objs := stack_o2cb.o
index cacfc118b71c9356d908c77b731bfbc932c62032..e45421fee204449024bb2a492c1bdd423bf32a0b 100644 (file)
@@ -78,6 +78,7 @@ struct ocfs2_extent_tree {
        struct ocfs2_extent_tree_operations *eops;
        struct buffer_head *root_bh;
        struct ocfs2_extent_list *root_el;
+       void *private;
 };
 
 static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et,
@@ -136,9 +137,50 @@ static struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = {
        .sanity_check           = ocfs2_dinode_sanity_check,
 };
 
+static void ocfs2_xattr_value_set_last_eb_blk(struct ocfs2_extent_tree *et,
+                                             u64 blkno)
+{
+       struct ocfs2_xattr_value_root *xv =
+               (struct ocfs2_xattr_value_root *)et->private;
+
+       xv->xr_last_eb_blk = cpu_to_le64(blkno);
+}
+
+static u64 ocfs2_xattr_value_get_last_eb_blk(struct ocfs2_extent_tree *et)
+{
+       struct ocfs2_xattr_value_root *xv =
+               (struct ocfs2_xattr_value_root *) et->private;
+
+       return le64_to_cpu(xv->xr_last_eb_blk);
+}
+
+static void ocfs2_xattr_value_update_clusters(struct inode *inode,
+                                             struct ocfs2_extent_tree *et,
+                                             u32 clusters)
+{
+       struct ocfs2_xattr_value_root *xv =
+               (struct ocfs2_xattr_value_root *)et->private;
+
+       le32_add_cpu(&xv->xr_clusters, clusters);
+}
+
+static int ocfs2_xattr_value_sanity_check(struct inode *inode,
+                                         struct ocfs2_extent_tree *et)
+{
+       return 0;
+}
+
+static struct ocfs2_extent_tree_operations ocfs2_xattr_et_ops = {
+       .set_last_eb_blk        = ocfs2_xattr_value_set_last_eb_blk,
+       .get_last_eb_blk        = ocfs2_xattr_value_get_last_eb_blk,
+       .update_clusters        = ocfs2_xattr_value_update_clusters,
+       .sanity_check           = ocfs2_xattr_value_sanity_check,
+};
+
 static struct ocfs2_extent_tree*
         ocfs2_new_extent_tree(struct buffer_head *bh,
-                              enum ocfs2_extent_tree_type et_type)
+                              enum ocfs2_extent_tree_type et_type,
+                              void *private)
 {
        struct ocfs2_extent_tree *et;
 
@@ -149,12 +191,16 @@ static struct ocfs2_extent_tree*
        et->type = et_type;
        get_bh(bh);
        et->root_bh = bh;
+       et->private = private;
 
-       /* current we only support dinode extent. */
-       BUG_ON(et->type != OCFS2_DINODE_EXTENT);
        if (et_type == OCFS2_DINODE_EXTENT) {
                et->root_el = &((struct ocfs2_dinode *)bh->b_data)->id2.i_list;
                et->eops = &ocfs2_dinode_et_ops;
+       } else if (et_type == OCFS2_XATTR_VALUE_EXTENT) {
+               struct ocfs2_xattr_value_root *xv =
+                       (struct ocfs2_xattr_value_root *) private;
+               et->root_el = &xv->xr_list;
+               et->eops = &ocfs2_xattr_et_ops;
        }
 
        return et;
@@ -495,7 +541,8 @@ struct ocfs2_merge_ctxt {
 int ocfs2_num_free_extents(struct ocfs2_super *osb,
                           struct inode *inode,
                           struct buffer_head *root_bh,
-                          enum ocfs2_extent_tree_type type)
+                          enum ocfs2_extent_tree_type type,
+                          void *private)
 {
        int retval;
        struct ocfs2_extent_list *el = NULL;
@@ -517,6 +564,12 @@ int ocfs2_num_free_extents(struct ocfs2_super *osb,
                if (fe->i_last_eb_blk)
                        last_eb_blk = le64_to_cpu(fe->i_last_eb_blk);
                el = &fe->id2.i_list;
+       } else if (type == OCFS2_XATTR_VALUE_EXTENT) {
+               struct ocfs2_xattr_value_root *xv =
+                       (struct ocfs2_xattr_value_root *) private;
+
+               last_eb_blk = le64_to_cpu(xv->xr_last_eb_blk);
+               el = &xv->xr_list;
        }
 
        if (last_eb_blk) {
@@ -4209,33 +4262,25 @@ out:
  *
  * The caller needs to update fe->i_clusters
  */
-int ocfs2_insert_extent(struct ocfs2_super *osb,
-                       handle_t *handle,
-                       struct inode *inode,
-                       struct buffer_head *root_bh,
-                       u32 cpos,
-                       u64 start_blk,
-                       u32 new_clusters,
-                       u8 flags,
-                       struct ocfs2_alloc_context *meta_ac,
-                       enum ocfs2_extent_tree_type et_type)
+static int ocfs2_insert_extent(struct ocfs2_super *osb,
+                              handle_t *handle,
+                              struct inode *inode,
+                              struct buffer_head *root_bh,
+                              u32 cpos,
+                              u64 start_blk,
+                              u32 new_clusters,
+                              u8 flags,
+                              struct ocfs2_alloc_context *meta_ac,
+                              struct ocfs2_extent_tree *et)
 {
        int status;
        int uninitialized_var(free_records);
        struct buffer_head *last_eb_bh = NULL;
        struct ocfs2_insert_type insert = {0, };
        struct ocfs2_extent_rec rec;
-       struct ocfs2_extent_tree *et = NULL;
 
        BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL);
 
-       et = ocfs2_new_extent_tree(root_bh, et_type);
-       if (!et) {
-               status = -ENOMEM;
-               mlog_errno(status);
-               goto bail;
-       }
-
        mlog(0, "add %u clusters at position %u to inode %llu\n",
             new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno);
 
@@ -4287,9 +4332,68 @@ bail:
        if (last_eb_bh)
                brelse(last_eb_bh);
 
+       mlog_exit(status);
+       return status;
+}
+
+int ocfs2_dinode_insert_extent(struct ocfs2_super *osb,
+                              handle_t *handle,
+                              struct inode *inode,
+                              struct buffer_head *root_bh,
+                              u32 cpos,
+                              u64 start_blk,
+                              u32 new_clusters,
+                              u8 flags,
+                              struct ocfs2_alloc_context *meta_ac)
+{
+       int status;
+       struct ocfs2_extent_tree *et = NULL;
+
+       et = ocfs2_new_extent_tree(root_bh, OCFS2_DINODE_EXTENT, NULL);
+       if (!et) {
+               status = -ENOMEM;
+               mlog_errno(status);
+               goto bail;
+       }
+
+       status = ocfs2_insert_extent(osb, handle, inode, root_bh,
+                                    cpos, start_blk, new_clusters,
+                                    flags, meta_ac, et);
+
        if (et)
                ocfs2_free_extent_tree(et);
-       mlog_exit(status);
+bail:
+       return status;
+}
+
+int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb,
+                                   handle_t *handle,
+                                   struct inode *inode,
+                                   struct buffer_head *root_bh,
+                                   u32 cpos,
+                                   u64 start_blk,
+                                   u32 new_clusters,
+                                   u8 flags,
+                                   struct ocfs2_alloc_context *meta_ac,
+                                   void *private)
+{
+       int status;
+       struct ocfs2_extent_tree *et = NULL;
+
+       et = ocfs2_new_extent_tree(root_bh, OCFS2_XATTR_VALUE_EXTENT, private);
+       if (!et) {
+               status = -ENOMEM;
+               mlog_errno(status);
+               goto bail;
+       }
+
+       status = ocfs2_insert_extent(osb, handle, inode, root_bh,
+                                    cpos, start_blk, new_clusters,
+                                    flags, meta_ac, et);
+
+       if (et)
+               ocfs2_free_extent_tree(et);
+bail:
        return status;
 }
 
@@ -4311,7 +4415,8 @@ int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb,
                                struct ocfs2_alloc_context *data_ac,
                                struct ocfs2_alloc_context *meta_ac,
                                enum ocfs2_alloc_restarted *reason_ret,
-                               enum ocfs2_extent_tree_type type)
+                               enum ocfs2_extent_tree_type type,
+                               void *private)
 {
        int status = 0;
        int free_extents;
@@ -4325,7 +4430,8 @@ int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb,
        if (mark_unwritten)
                flags = OCFS2_EXT_UNWRITTEN;
 
-       free_extents = ocfs2_num_free_extents(osb, inode, root_bh, type);
+       free_extents = ocfs2_num_free_extents(osb, inode, root_bh, type,
+                                             private);
        if (free_extents < 0) {
                status = free_extents;
                mlog_errno(status);
@@ -4372,9 +4478,16 @@ int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb,
        block = ocfs2_clusters_to_blocks(osb->sb, bit_off);
        mlog(0, "Allocating %u clusters at block %u for inode %llu\n",
             num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno);
-       status = ocfs2_insert_extent(osb, handle, inode, root_bh,
-                                    *logical_offset, block, num_bits,
-                                    flags, meta_ac, type);
+       if (type == OCFS2_DINODE_EXTENT)
+               status = ocfs2_dinode_insert_extent(osb, handle, inode, root_bh,
+                                                   *logical_offset, block,
+                                                   num_bits, flags, meta_ac);
+       else
+               status = ocfs2_xattr_value_insert_extent(osb, handle,
+                                                        inode, root_bh,
+                                                        *logical_offset,
+                                                        block, num_bits, flags,
+                                                        meta_ac, private);
        if (status < 0) {
                mlog_errno(status);
                goto leave;
@@ -4655,7 +4768,8 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh,
                              handle_t *handle, u32 cpos, u32 len, u32 phys,
                              struct ocfs2_alloc_context *meta_ac,
                              struct ocfs2_cached_dealloc_ctxt *dealloc,
-                             enum ocfs2_extent_tree_type et_type)
+                             enum ocfs2_extent_tree_type et_type,
+                             void *private)
 {
        int ret, index;
        u64 start_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys);
@@ -4676,7 +4790,7 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh,
                goto out;
        }
 
-       et = ocfs2_new_extent_tree(root_bh, et_type);
+       et = ocfs2_new_extent_tree(root_bh, et_type, private);
        if (!et) {
                ret = -ENOMEM;
                mlog_errno(ret);
@@ -4964,7 +5078,8 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh,
                        u32 cpos, u32 len, handle_t *handle,
                        struct ocfs2_alloc_context *meta_ac,
                        struct ocfs2_cached_dealloc_ctxt *dealloc,
-                       enum ocfs2_extent_tree_type et_type)
+                       enum ocfs2_extent_tree_type et_type,
+                       void *private)
 {
        int ret, index;
        u32 rec_range, trunc_range;
@@ -4973,7 +5088,7 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh,
        struct ocfs2_path *path = NULL;
        struct ocfs2_extent_tree *et = NULL;
 
-       et = ocfs2_new_extent_tree(root_bh, et_type);
+       et = ocfs2_new_extent_tree(root_bh, et_type, private);
        if (!et) {
                ret = -ENOMEM;
                mlog_errno(ret);
@@ -6608,9 +6723,8 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode,
                 * this proves to be false, we could always re-build
                 * the in-inode data from our pages.
                 */
-               ret = ocfs2_insert_extent(osb, handle, inode, di_bh,
-                                         0, block, 1, 0,
-                                         NULL, OCFS2_DINODE_EXTENT);
+               ret = ocfs2_dinode_insert_extent(osb, handle, inode, di_bh,
+                                                0, block, 1, 0, NULL);
                if (ret) {
                        mlog_errno(ret);
                        goto out_commit;
index 5e090c5d8498ad6f708480edd3ff49f62aa1f819..ec7baeb2ea7d3fe083ad83354dc7cf67d4c0a997 100644 (file)
 
 enum ocfs2_extent_tree_type {
        OCFS2_DINODE_EXTENT = 0,
+       OCFS2_XATTR_VALUE_EXTENT,
 };
 
 struct ocfs2_alloc_context;
-int ocfs2_insert_extent(struct ocfs2_super *osb,
-                       handle_t *handle,
-                       struct inode *inode,
-                       struct buffer_head *root_bh,
-                       u32 cpos,
-                       u64 start_blk,
-                       u32 new_clusters,
-                       u8 flags,
-                       struct ocfs2_alloc_context *meta_ac,
-                       enum ocfs2_extent_tree_type et_type);
+int ocfs2_dinode_insert_extent(struct ocfs2_super *osb,
+                              handle_t *handle,
+                              struct inode *inode,
+                              struct buffer_head *root_bh,
+                              u32 cpos,
+                              u64 start_blk,
+                              u32 new_clusters,
+                              u8 flags,
+                              struct ocfs2_alloc_context *meta_ac);
+int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb,
+                                   handle_t *handle,
+                                   struct inode *inode,
+                                   struct buffer_head *root_bh,
+                                   u32 cpos,
+                                   u64 start_blk,
+                                   u32 new_clusters,
+                                   u8 flags,
+                                   struct ocfs2_alloc_context *meta_ac,
+                                   void *private);
 enum ocfs2_alloc_restarted {
        RESTART_NONE = 0,
        RESTART_TRANS,
@@ -57,22 +67,26 @@ int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb,
                                struct ocfs2_alloc_context *data_ac,
                                struct ocfs2_alloc_context *meta_ac,
                                enum ocfs2_alloc_restarted *reason_ret,
-                               enum ocfs2_extent_tree_type type);
+                               enum ocfs2_extent_tree_type type,
+                               void *private);
 struct ocfs2_cached_dealloc_ctxt;
 int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh,
                              handle_t *handle, u32 cpos, u32 len, u32 phys,
                              struct ocfs2_alloc_context *meta_ac,
                              struct ocfs2_cached_dealloc_ctxt *dealloc,
-                             enum ocfs2_extent_tree_type et_type);
+                             enum ocfs2_extent_tree_type et_type,
+                             void *private);
 int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh,
                        u32 cpos, u32 len, handle_t *handle,
                        struct ocfs2_alloc_context *meta_ac,
                        struct ocfs2_cached_dealloc_ctxt *dealloc,
-                       enum ocfs2_extent_tree_type et_type);
+                       enum ocfs2_extent_tree_type et_type,
+                       void *private);
 int ocfs2_num_free_extents(struct ocfs2_super *osb,
                           struct inode *inode,
                           struct buffer_head *root_bh,
-                          enum ocfs2_extent_tree_type et_type);
+                          enum ocfs2_extent_tree_type et_type,
+                          void *private);
 
 /*
  * how many new metadata chunks would an allocation need at maximum?
index e7acd28679044d6d9288e6f85764e8d4e6e5c59b..530b1ff599c0be7c17002e9cff716c48c75cfcee 100644 (file)
@@ -1279,7 +1279,7 @@ static int ocfs2_write_cluster(struct address_space *mapping,
                ret = ocfs2_mark_extent_written(inode, wc->w_di_bh,
                                                wc->w_handle, cpos, 1, phys,
                                                meta_ac, &wc->w_dealloc,
-                                               OCFS2_DINODE_EXTENT);
+                                               OCFS2_DINODE_EXTENT, NULL);
                if (ret < 0) {
                        mlog_errno(ret);
                        goto out;
@@ -1721,7 +1721,8 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
 
                ret = ocfs2_lock_allocators(inode, wc->w_di_bh, &di->id2.i_list,
                                            clusters_to_alloc, extents_to_split,
-                                           &data_ac, &meta_ac);
+                                           &data_ac, &meta_ac,
+                                           OCFS2_DINODE_EXTENT, NULL);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
index 23c732f275293bfdd24dad2d03ddbb07c7c4b8e8..d8a0cb92cef62a6b108696b0a9dae36dcfc9768a 100644 (file)
@@ -109,6 +109,7 @@ static struct mlog_attribute mlog_attrs[MLOG_MAX_BITS] = {
        define_mask(CONN),
        define_mask(QUORUM),
        define_mask(EXPORT),
+       define_mask(XATTR),
        define_mask(ERROR),
        define_mask(NOTICE),
        define_mask(KTHREAD),
index 597e064bb94fa9333ea40ad0387d7b34fa2005dc..57670c6804713454f02f2a6b18ed5ca41bbbfe6b 100644 (file)
 #define ML_CONN                0x0000000004000000ULL /* net connection management */
 #define ML_QUORUM      0x0000000008000000ULL /* net connection quorum */
 #define ML_EXPORT      0x0000000010000000ULL /* ocfs2 export operations */
+#define ML_XATTR       0x0000000020000000ULL /* ocfs2 extended attributes */
 /* bits that are infrequently given and frequently matched in the high word */
 #define ML_ERROR       0x0000000100000000ULL /* sent to KERN_ERR */
 #define ML_NOTICE      0x0000000200000000ULL /* setn to KERN_NOTICE */
index d17c34b0ac6b7a9daedd727497265794863cff66..5426a02c12bbaa99dfd820ed8aac20cc9b042b15 100644 (file)
@@ -1305,8 +1305,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
         * This should never fail as our extent list is empty and all
         * related blocks have been journaled already.
         */
-       ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 0, blkno, len, 0,
-                                 NULL, OCFS2_DINODE_EXTENT);
+       ret = ocfs2_dinode_insert_extent(osb, handle, dir, di_bh, 0, blkno,
+                                        len, 0, NULL);
        if (ret) {
                mlog_errno(ret);
                goto out_commit;
@@ -1337,8 +1337,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
                }
                blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
 
-               ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 1, blkno,
-                                         len, 0, NULL, OCFS2_DINODE_EXTENT);
+               ret = ocfs2_dinode_insert_extent(osb, handle, dir, di_bh, 1,
+                                                blkno, len, 0, NULL);
                if (ret) {
                        mlog_errno(ret);
                        goto out_commit;
@@ -1482,7 +1482,8 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
                spin_unlock(&OCFS2_I(dir)->ip_lock);
                num_free_extents = ocfs2_num_free_extents(osb, dir,
                                                          parent_fe_bh,
-                                                         OCFS2_DINODE_EXTENT);
+                                                         OCFS2_DINODE_EXTENT,
+                                                         NULL);
                if (num_free_extents < 0) {
                        status = num_free_extents;
                        mlog_errno(status);
index aed268e80b49173a5a3af264bcd5ca5c7e55ca8a..a7b1cfa735bfd3ff76bfc39cdf4e8a189e3dac5e 100644 (file)
@@ -551,6 +551,66 @@ static void ocfs2_relative_extent_offsets(struct super_block *sb,
                *num_clusters = le16_to_cpu(rec->e_leaf_clusters) - coff;
 }
 
+int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
+                            u32 *p_cluster, u32 *num_clusters,
+                            struct ocfs2_extent_list *el)
+{
+       int ret = 0, i;
+       struct buffer_head *eb_bh = NULL;
+       struct ocfs2_extent_block *eb;
+       struct ocfs2_extent_rec *rec;
+       u32 coff;
+
+       if (el->l_tree_depth) {
+               ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               eb = (struct ocfs2_extent_block *) eb_bh->b_data;
+               el = &eb->h_list;
+
+               if (el->l_tree_depth) {
+                       ocfs2_error(inode->i_sb,
+                                   "Inode %lu has non zero tree depth in "
+                                   "xattr leaf block %llu\n", inode->i_ino,
+                                   (unsigned long long)eb_bh->b_blocknr);
+                       ret = -EROFS;
+                       goto out;
+               }
+       }
+
+       i = ocfs2_search_extent_list(el, v_cluster);
+       if (i == -1) {
+               ret = -EROFS;
+               mlog_errno(ret);
+               goto out;
+       } else {
+               rec = &el->l_recs[i];
+               BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos));
+
+               if (!rec->e_blkno) {
+                       ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
+                                   "record (%u, %u, 0) in xattr", inode->i_ino,
+                                   le32_to_cpu(rec->e_cpos),
+                                   ocfs2_rec_clusters(el, rec));
+                       ret = -EROFS;
+                       goto out;
+               }
+               coff = v_cluster - le32_to_cpu(rec->e_cpos);
+               *p_cluster = ocfs2_blocks_to_clusters(inode->i_sb,
+                                                   le64_to_cpu(rec->e_blkno));
+               *p_cluster = *p_cluster + coff;
+               if (num_clusters)
+                       *num_clusters = ocfs2_rec_clusters(el, rec) - coff;
+       }
+out:
+       if (eb_bh)
+               brelse(eb_bh);
+       return ret;
+}
+
 int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
                       u32 *p_cluster, u32 *num_clusters,
                       unsigned int *extent_flags)
index 1b97490e1ea8d7b431cf40c9bbcab801b3bb4305..1c4aa8b06f348c89b4560f733cdd0e1aefe9e852 100644 (file)
@@ -53,4 +53,8 @@ int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno,
 int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                 u64 map_start, u64 map_len);
 
+int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
+                            u32 *p_cluster, u32 *num_clusters,
+                            struct ocfs2_extent_list *el);
+
 #endif  /* _EXTENT_MAP_H */
index 7bb4fde70054b72ffdbb79e281c6de3f81a39c8a..89d8541f85b5c5661bc5fb793b83dc7e1483688c 100644 (file)
@@ -515,7 +515,7 @@ int ocfs2_add_inode_data(struct ocfs2_super *osb,
                                           clusters_to_add, mark_unwritten,
                                           fe_bh, el, handle,
                                           data_ac, meta_ac, reason_ret,
-                                          OCFS2_DINODE_EXTENT);
+                                          OCFS2_DINODE_EXTENT, NULL);
 }
 
 static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
@@ -565,7 +565,7 @@ restart_all:
             clusters_to_add);
        status = ocfs2_lock_allocators(inode, bh, &fe->id2.i_list,
                                       clusters_to_add, 0, &data_ac,
-                                      &meta_ac);
+                                      &meta_ac, OCFS2_DINODE_EXTENT, NULL);
        if (status) {
                mlog_errno(status);
                goto leave;
@@ -1237,7 +1237,8 @@ static int __ocfs2_remove_inode_range(struct inode *inode,
        struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
 
        ret = ocfs2_lock_allocators(inode, di_bh, &di->id2.i_list,
-                                   0, 1, NULL, &meta_ac);
+                                   0, 1, NULL, &meta_ac,
+                                   OCFS2_DINODE_EXTENT, NULL);
        if (ret) {
                mlog_errno(ret);
                return ret;
@@ -1268,7 +1269,7 @@ static int __ocfs2_remove_inode_range(struct inode *inode,
        }
 
        ret = ocfs2_remove_extent(inode, di_bh, cpos, len, handle, meta_ac,
-                                 dealloc, OCFS2_DINODE_EXTENT);
+                                 dealloc, OCFS2_DINODE_EXTENT, NULL);
        if (ret) {
                mlog_errno(ret);
                goto out_commit;
index b642c825fb7c810934a20b5fc51ab2f540f134bd..bb774d70d268c2c65fbf71f92607b8a4f14109bf 100644 (file)
@@ -1909,7 +1909,8 @@ int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh,
                          struct ocfs2_extent_list *root_el,
                          u32 clusters_to_add, u32 extents_to_split,
                          struct ocfs2_alloc_context **data_ac,
-                         struct ocfs2_alloc_context **meta_ac)
+                         struct ocfs2_alloc_context **meta_ac,
+                         enum ocfs2_extent_tree_type type, void *private)
 {
        int ret = 0, num_free_extents;
        unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split;
@@ -1922,7 +1923,7 @@ int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh,
        BUG_ON(clusters_to_add != 0 && data_ac == NULL);
 
        num_free_extents = ocfs2_num_free_extents(osb, inode, root_bh,
-                                                 OCFS2_DINODE_EXTENT);
+                                                 type, private);
        if (num_free_extents < 0) {
                ret = num_free_extents;
                mlog_errno(ret);
index a3e531e62df27cc19825497c33dd63ebed909ff7..9e026c8afee47d5ef10bd22c9a25f08171ce7482 100644 (file)
@@ -166,5 +166,6 @@ int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh,
                          struct ocfs2_extent_list *root_el,
                          u32 clusters_to_add, u32 extents_to_split,
                          struct ocfs2_alloc_context **data_ac,
-                         struct ocfs2_alloc_context **meta_ac);
+                         struct ocfs2_alloc_context **meta_ac,
+                         enum ocfs2_extent_tree_type type, void *private);
 #endif /* _CHAINALLOC_H_ */
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
new file mode 100644 (file)
index 0000000..9604a4c
--- /dev/null
@@ -0,0 +1,305 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * xattr.c
+ *
+ * Copyright (C) 2008 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#define MLOG_MASK_PREFIX ML_XATTR
+#include <cluster/masklog.h>
+
+#include "ocfs2.h"
+#include "alloc.h"
+#include "dlmglue.h"
+#include "file.h"
+#include "inode.h"
+#include "journal.h"
+#include "ocfs2_fs.h"
+#include "suballoc.h"
+#include "uptodate.h"
+#include "buffer_head_io.h"
+
+static int ocfs2_xattr_extend_allocation(struct inode *inode,
+                                        u32 clusters_to_add,
+                                        struct buffer_head *xattr_bh,
+                                        struct ocfs2_xattr_value_root *xv)
+{
+       int status = 0;
+       int restart_func = 0;
+       int credits = 0;
+       handle_t *handle = NULL;
+       struct ocfs2_alloc_context *data_ac = NULL;
+       struct ocfs2_alloc_context *meta_ac = NULL;
+       enum ocfs2_alloc_restarted why;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_extent_list *root_el = &xv->xr_list;
+       u32 prev_clusters, logical_start = le32_to_cpu(xv->xr_clusters);
+
+       mlog(0, "(clusters_to_add for xattr= %u)\n", clusters_to_add);
+
+restart_all:
+
+       status = ocfs2_lock_allocators(inode, xattr_bh, root_el,
+                                      clusters_to_add, 0, &data_ac,
+                                      &meta_ac, OCFS2_XATTR_VALUE_EXTENT, xv);
+       if (status) {
+               mlog_errno(status);
+               goto leave;
+       }
+
+       credits = ocfs2_calc_extend_credits(osb->sb, root_el, clusters_to_add);
+       handle = ocfs2_start_trans(osb, credits);
+       if (IS_ERR(handle)) {
+               status = PTR_ERR(handle);
+               handle = NULL;
+               mlog_errno(status);
+               goto leave;
+       }
+
+restarted_transaction:
+       status = ocfs2_journal_access(handle, inode, xattr_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (status < 0) {
+               mlog_errno(status);
+               goto leave;
+       }
+
+       prev_clusters = le32_to_cpu(xv->xr_clusters);
+       status = ocfs2_add_clusters_in_btree(osb,
+                                            inode,
+                                            &logical_start,
+                                            clusters_to_add,
+                                            0,
+                                            xattr_bh,
+                                            root_el,
+                                            handle,
+                                            data_ac,
+                                            meta_ac,
+                                            &why,
+                                            OCFS2_XATTR_VALUE_EXTENT,
+                                            xv);
+       if ((status < 0) && (status != -EAGAIN)) {
+               if (status != -ENOSPC)
+                       mlog_errno(status);
+               goto leave;
+       }
+
+       status = ocfs2_journal_dirty(handle, xattr_bh);
+       if (status < 0) {
+               mlog_errno(status);
+               goto leave;
+       }
+
+       clusters_to_add -= le32_to_cpu(xv->xr_clusters) - prev_clusters;
+
+       if (why != RESTART_NONE && clusters_to_add) {
+               if (why == RESTART_META) {
+                       mlog(0, "restarting function.\n");
+                       restart_func = 1;
+               } else {
+                       BUG_ON(why != RESTART_TRANS);
+
+                       mlog(0, "restarting transaction.\n");
+                       /* TODO: This can be more intelligent. */
+                       credits = ocfs2_calc_extend_credits(osb->sb,
+                                                           root_el,
+                                                           clusters_to_add);
+                       status = ocfs2_extend_trans(handle, credits);
+                       if (status < 0) {
+                               /* handle still has to be committed at
+                                * this point. */
+                               status = -ENOMEM;
+                               mlog_errno(status);
+                               goto leave;
+                       }
+                       goto restarted_transaction;
+               }
+       }
+
+leave:
+       if (handle) {
+               ocfs2_commit_trans(osb, handle);
+               handle = NULL;
+       }
+       if (data_ac) {
+               ocfs2_free_alloc_context(data_ac);
+               data_ac = NULL;
+       }
+       if (meta_ac) {
+               ocfs2_free_alloc_context(meta_ac);
+               meta_ac = NULL;
+       }
+       if ((!status) && restart_func) {
+               restart_func = 0;
+               goto restart_all;
+       }
+
+       return status;
+}
+
+static int __ocfs2_remove_xattr_range(struct inode *inode,
+                                     struct buffer_head *root_bh,
+                                     struct ocfs2_xattr_value_root *xv,
+                                     u32 cpos, u32 phys_cpos, u32 len,
+                                     struct ocfs2_cached_dealloc_ctxt *dealloc)
+{
+       int ret;
+       u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct inode *tl_inode = osb->osb_tl_inode;
+       handle_t *handle;
+       struct ocfs2_alloc_context *meta_ac = NULL;
+
+       ret = ocfs2_lock_allocators(inode, root_bh, &xv->xr_list,
+                                   0, 1, NULL, &meta_ac,
+                                   OCFS2_XATTR_VALUE_EXTENT, xv);
+       if (ret) {
+               mlog_errno(ret);
+               return ret;
+       }
+
+       mutex_lock(&tl_inode->i_mutex);
+
+       if (ocfs2_truncate_log_needs_flush(osb)) {
+               ret = __ocfs2_flush_truncate_log(osb);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+       handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS);
+       if (IS_ERR(handle)) {
+               ret = PTR_ERR(handle);
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_journal_access(handle, inode, root_bh,
+                                  OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ret = ocfs2_remove_extent(inode, root_bh, cpos, len, handle, meta_ac,
+                                 dealloc, OCFS2_XATTR_VALUE_EXTENT, xv);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       le32_add_cpu(&xv->xr_clusters, -len);
+
+       ret = ocfs2_journal_dirty(handle, root_bh);
+       if (ret) {
+               mlog_errno(ret);
+               goto out_commit;
+       }
+
+       ret = ocfs2_truncate_log_append(osb, handle, phys_blkno, len);
+       if (ret)
+               mlog_errno(ret);
+
+out_commit:
+       ocfs2_commit_trans(osb, handle);
+out:
+       mutex_unlock(&tl_inode->i_mutex);
+
+       if (meta_ac)
+               ocfs2_free_alloc_context(meta_ac);
+
+       return ret;
+}
+
+static int ocfs2_xattr_shrink_size(struct inode *inode,
+                                  u32 old_clusters,
+                                  u32 new_clusters,
+                                  struct buffer_head *root_bh,
+                                  struct ocfs2_xattr_value_root *xv)
+{
+       int ret = 0;
+       u32 trunc_len, cpos, phys_cpos, alloc_size;
+       u64 block;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct ocfs2_cached_dealloc_ctxt dealloc;
+
+       ocfs2_init_dealloc_ctxt(&dealloc);
+
+       if (old_clusters <= new_clusters)
+               return 0;
+
+       cpos = new_clusters;
+       trunc_len = old_clusters - new_clusters;
+       while (trunc_len) {
+               ret = ocfs2_xattr_get_clusters(inode, cpos, &phys_cpos,
+                                              &alloc_size, &xv->xr_list);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               if (alloc_size > trunc_len)
+                       alloc_size = trunc_len;
+
+               ret = __ocfs2_remove_xattr_range(inode, root_bh, xv, cpos,
+                                                phys_cpos, alloc_size,
+                                                &dealloc);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               block = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
+               ocfs2_remove_xattr_clusters_from_cache(inode, block,
+                                                      alloc_size);
+               cpos += alloc_size;
+               trunc_len -= alloc_size;
+       }
+
+out:
+       ocfs2_schedule_truncate_log_flush(osb, 1);
+       ocfs2_run_deallocs(osb, &dealloc);
+
+       return ret;
+}
+
+static int ocfs2_xattr_value_truncate(struct inode *inode,
+                                     struct buffer_head *root_bh,
+                                     struct ocfs2_xattr_value_root *xv,
+                                     int len)
+{
+       int ret;
+       u32 new_clusters = ocfs2_clusters_for_bytes(inode->i_sb, len);
+       u32 old_clusters = le32_to_cpu(xv->xr_clusters);
+
+       if (new_clusters == old_clusters)
+               return 0;
+
+       if (new_clusters > old_clusters)
+               ret = ocfs2_xattr_extend_allocation(inode,
+                                                   new_clusters - old_clusters,
+                                                   root_bh, xv);
+       else
+               ret = ocfs2_xattr_shrink_size(inode,
+                                             old_clusters, new_clusters,
+                                             root_bh, xv);
+
+       return ret;
+}