[Ocfs2-devel] [PATCH 02/15] ocfs2: Add clusters free in dealloc_ctxt.
Joel Becker
Joel.Becker at oracle.com
Mon Nov 3 17:16:52 PST 2008
On Thu, Oct 30, 2008 at 01:42:12PM +0800, Tao Ma wrote:
> Now in ocfs2 xattr set, the whole process are divided into many small
> parts and they are wrapped into diffrent transactions and it make the
> set doesn't look like a real transaction. So we want to integrate it
> into a real one.
>
> In some cases we will allocate some clusters and free some in just one
> transaction. e.g, one xattr is larger than inline size, so it and its
> value root is stored within the inode while the value is outside in a
> cluster. Then we try to update it with a smaller value(larger than the
> size of root but smaller than inline size), we may need to free the
> outside cluster while allocate a new bucket(one cluster) since now the
> inode may be full. The old solution will lock the global_bitmap(if the
> local alloc failed in stress test) and then the truncate log. This will
> cause a ABBA lock with truncate log flush.
>
> This patch add the clusters free in dealloc_ctxt, so that we can record
> the free clusters during the transaction and then free it after we
> release the global_bitmap in xattr set.
So, you're really adding the global cluster allocator as a type
of allocator that can live on the dealloc context.
> diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
> index 0cc2deb..3c54572 100644
> --- a/fs/ocfs2/alloc.c
> +++ b/fs/ocfs2/alloc.c
> @@ -5801,6 +5801,11 @@ int ocfs2_truncate_log_init(struct ocfs2_super *osb)
>
> /*
> * Describes a single block free from a suballocator
> + *
> + * XXX:
> + * This structure is reused when we free a number of clusters
> + * during xattr set. In that case, free_bit indicates the number
> + * of the free clusters.
> */
How about:
/*
* Describe a single bit freed from a suballocator. For the block
* suballocators, it represents one block. For the global cluster
* allocator, it represents one cluster.
*/
> struct ocfs2_cached_block_free {
> struct ocfs2_cached_block_free *free_next;
> @@ -5893,6 +5898,73 @@ out:
> return ret;
> }
>
> +int ocfs2_cache_clusters_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
> + u64 blkno, unsigned int bit)
Call it ocfs2_cache_cluster_dealloc() for consistency (the
singular form).
> +{
> + int ret = 0;
> + struct ocfs2_cached_block_free *item;
> +
> + item = kmalloc(sizeof(*item), GFP_NOFS);
> + if (item == NULL) {
> + ret = -ENOMEM;
> + mlog_errno(ret);
> + return ret;
> + }
> +
> + mlog(0, "Insert clusters: (bit %u, blk %llu)\n",
> + bit, (unsigned long long)blkno);
> +
> + item->free_blk = blkno;
> + item->free_bit = bit;
> + item->free_next = ctxt->c_clusters_list;
You need to push item on to the list too.
+ ctxt->c_clusters_list = item;
> +
> + return ret;
> +}
> +
> +static int ocfs2_free_clusters_list(struct ocfs2_super *osb,
> + struct ocfs2_cached_block_free *head)
Call this 'ocfs2_free_cached_clusters' and change
'ocfs2_free_cached_items' to 'ocfs2_free_cached_blocks'.
> +{
> + struct ocfs2_cached_block_free *tmp;
> + struct inode *tl_inode = osb->osb_tl_inode;
> + handle_t *handle;
> + int ret = 0;
> +
> + mutex_lock(&tl_inode->i_mutex);
> +
> + handle = ocfs2_start_trans(osb, OCFS2_TRUNCATE_LOG_UPDATE);
> + if (IS_ERR(handle)) {
> + ret = PTR_ERR(handle);
> + mlog_errno(ret);
> + goto out_mutex;
> + }
> +
> + while (head) {
> + ret = ocfs2_truncate_log_append(osb, handle, head->free_blk,
> + head->free_bit);
> + if (ret) {
> + mlog_errno(ret);
> + break;
> + }
What happens if the truncate log fills up?
> + tmp = head;
> + head = head->free_next;
> + kfree(tmp);
> + }
> +
> + ocfs2_commit_trans(osb, handle);
> +
> +out_mutex:
> + mutex_unlock(&tl_inode->i_mutex);
> +
> + while (head) {
> + /* Premature exit may have left some dangling items. */
> + tmp = head;
> + head = head->free_next;
> + kfree(tmp);
> + }
> +
> + return ret;
> +}
> +
> int ocfs2_run_deallocs(struct ocfs2_super *osb,
> struct ocfs2_cached_dealloc_ctxt *ctxt)
> {
<snip>
> diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h
> index 70257c8..1333a92 100644
> --- a/fs/ocfs2/alloc.h
> +++ b/fs/ocfs2/alloc.h
> @@ -167,11 +167,15 @@ int __ocfs2_flush_truncate_log(struct ocfs2_super *osb);
> */
> struct ocfs2_cached_dealloc_ctxt {
> struct ocfs2_per_slot_free_list *c_first_suballocator;
> + struct ocfs2_cached_block_free *c_clusters_list;
Change 'c_clusters_list' to 'c_global_allocator'.
Joel
--
"If you took all of the grains of sand in the world, and lined
them up end to end in a row, you'd be working for the government!"
- Mr. Interesting
Joel Becker
Principal Software Developer
Oracle
E-mail: joel.becker at oracle.com
Phone: (650) 506-8127
More information about the Ocfs2-devel
mailing list