aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2008-11-11 19:26:58 -0500
committerMark Fasheh <mfasheh@suse.com>2009-01-05 11:34:18 -0500
commit2891d290aa6eee0821f7e4ad0b1c4ae4d964b0f1 (patch)
tree2f06b8d3afcf1986d0f041319a8ec08395acdf83
parent976331d8789d4d84a11b45b87c520ade83715343 (diff)
ocfs2: Add clusters free in dealloc_ctxt.
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. Signed-off-by: Tao Ma <tao.ma@oracle.com> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
-rw-r--r--fs/ocfs2/alloc.c106
-rw-r--r--fs/ocfs2/alloc.h4
2 files changed, 103 insertions, 7 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 0cc2deb9394c..4614614084dd 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -5800,7 +5800,10 @@ int ocfs2_truncate_log_init(struct ocfs2_super *osb)
5800 */ 5800 */
5801 5801
5802/* 5802/*
5803 * Describes a single block free from a suballocator 5803 * Describe a single bit freed from a suballocator. For the block
5804 * suballocators, it represents one block. For the global cluster
5805 * allocator, it represents some clusters and free_bit indicates
5806 * clusters number.
5804 */ 5807 */
5805struct ocfs2_cached_block_free { 5808struct ocfs2_cached_block_free {
5806 struct ocfs2_cached_block_free *free_next; 5809 struct ocfs2_cached_block_free *free_next;
@@ -5815,10 +5818,10 @@ struct ocfs2_per_slot_free_list {
5815 struct ocfs2_cached_block_free *f_first; 5818 struct ocfs2_cached_block_free *f_first;
5816}; 5819};
5817 5820
5818static int ocfs2_free_cached_items(struct ocfs2_super *osb, 5821static int ocfs2_free_cached_blocks(struct ocfs2_super *osb,
5819 int sysfile_type, 5822 int sysfile_type,
5820 int slot, 5823 int slot,
5821 struct ocfs2_cached_block_free *head) 5824 struct ocfs2_cached_block_free *head)
5822{ 5825{
5823 int ret; 5826 int ret;
5824 u64 bg_blkno; 5827 u64 bg_blkno;
@@ -5893,6 +5896,82 @@ out:
5893 return ret; 5896 return ret;
5894} 5897}
5895 5898
5899int ocfs2_cache_cluster_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
5900 u64 blkno, unsigned int bit)
5901{
5902 int ret = 0;
5903 struct ocfs2_cached_block_free *item;
5904
5905 item = kmalloc(sizeof(*item), GFP_NOFS);
5906 if (item == NULL) {
5907 ret = -ENOMEM;
5908 mlog_errno(ret);
5909 return ret;
5910 }
5911
5912 mlog(0, "Insert clusters: (bit %u, blk %llu)\n",
5913 bit, (unsigned long long)blkno);
5914
5915 item->free_blk = blkno;
5916 item->free_bit = bit;
5917 item->free_next = ctxt->c_global_allocator;
5918
5919 ctxt->c_global_allocator = item;
5920 return ret;
5921}
5922
5923static int ocfs2_free_cached_clusters(struct ocfs2_super *osb,
5924 struct ocfs2_cached_block_free *head)
5925{
5926 struct ocfs2_cached_block_free *tmp;
5927 struct inode *tl_inode = osb->osb_tl_inode;
5928 handle_t *handle;
5929 int ret = 0;
5930
5931 mutex_lock(&tl_inode->i_mutex);
5932
5933 while (head) {
5934 if (ocfs2_truncate_log_needs_flush(osb)) {
5935 ret = __ocfs2_flush_truncate_log(osb);
5936 if (ret < 0) {
5937 mlog_errno(ret);
5938 break;
5939 }
5940 }
5941
5942 handle = ocfs2_start_trans(osb, OCFS2_TRUNCATE_LOG_UPDATE);
5943 if (IS_ERR(handle)) {
5944 ret = PTR_ERR(handle);
5945 mlog_errno(ret);
5946 break;
5947 }
5948
5949 ret = ocfs2_truncate_log_append(osb, handle, head->free_blk,
5950 head->free_bit);
5951
5952 ocfs2_commit_trans(osb, handle);
5953 tmp = head;
5954 head = head->free_next;
5955 kfree(tmp);
5956
5957 if (ret < 0) {
5958 mlog_errno(ret);
5959 break;
5960 }
5961 }
5962
5963 mutex_unlock(&tl_inode->i_mutex);
5964
5965 while (head) {
5966 /* Premature exit may have left some dangling items. */
5967 tmp = head;
5968 head = head->free_next;
5969 kfree(tmp);
5970 }
5971
5972 return ret;
5973}
5974
5896int ocfs2_run_deallocs(struct ocfs2_super *osb, 5975int ocfs2_run_deallocs(struct ocfs2_super *osb,
5897 struct ocfs2_cached_dealloc_ctxt *ctxt) 5976 struct ocfs2_cached_dealloc_ctxt *ctxt)
5898{ 5977{
@@ -5908,8 +5987,10 @@ int ocfs2_run_deallocs(struct ocfs2_super *osb,
5908 if (fl->f_first) { 5987 if (fl->f_first) {
5909 mlog(0, "Free items: (type %u, slot %d)\n", 5988 mlog(0, "Free items: (type %u, slot %d)\n",
5910 fl->f_inode_type, fl->f_slot); 5989 fl->f_inode_type, fl->f_slot);
5911 ret2 = ocfs2_free_cached_items(osb, fl->f_inode_type, 5990 ret2 = ocfs2_free_cached_blocks(osb,
5912 fl->f_slot, fl->f_first); 5991 fl->f_inode_type,
5992 fl->f_slot,
5993 fl->f_first);
5913 if (ret2) 5994 if (ret2)
5914 mlog_errno(ret2); 5995 mlog_errno(ret2);
5915 if (!ret) 5996 if (!ret)
@@ -5920,6 +6001,17 @@ int ocfs2_run_deallocs(struct ocfs2_super *osb,
5920 kfree(fl); 6001 kfree(fl);
5921 } 6002 }
5922 6003
6004 if (ctxt->c_global_allocator) {
6005 ret2 = ocfs2_free_cached_clusters(osb,
6006 ctxt->c_global_allocator);
6007 if (ret2)
6008 mlog_errno(ret2);
6009 if (!ret)
6010 ret = ret2;
6011
6012 ctxt->c_global_allocator = NULL;
6013 }
6014
5923 return ret; 6015 return ret;
5924} 6016}
5925 6017
diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h
index 70257c84cfbe..c301cf225f0b 100644
--- a/fs/ocfs2/alloc.h
+++ b/fs/ocfs2/alloc.h
@@ -167,11 +167,15 @@ int __ocfs2_flush_truncate_log(struct ocfs2_super *osb);
167 */ 167 */
168struct ocfs2_cached_dealloc_ctxt { 168struct ocfs2_cached_dealloc_ctxt {
169 struct ocfs2_per_slot_free_list *c_first_suballocator; 169 struct ocfs2_per_slot_free_list *c_first_suballocator;
170 struct ocfs2_cached_block_free *c_global_allocator;
170}; 171};
171static inline void ocfs2_init_dealloc_ctxt(struct ocfs2_cached_dealloc_ctxt *c) 172static inline void ocfs2_init_dealloc_ctxt(struct ocfs2_cached_dealloc_ctxt *c)
172{ 173{
173 c->c_first_suballocator = NULL; 174 c->c_first_suballocator = NULL;
175 c->c_global_allocator = NULL;
174} 176}
177int ocfs2_cache_cluster_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
178 u64 blkno, unsigned int bit);
175int ocfs2_run_deallocs(struct ocfs2_super *osb, 179int ocfs2_run_deallocs(struct ocfs2_super *osb,
176 struct ocfs2_cached_dealloc_ctxt *ctxt); 180 struct ocfs2_cached_dealloc_ctxt *ctxt);
177 181