]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Tao Ma <tao.ma@oracle.com> |
2 | Date: Wed, 12 Nov 2008 08:26:58 +0800 | |
3 | Subject: ocfs2: Add clusters free in dealloc_ctxt. | |
4 | Patch-mainline: 2.6.29 | |
5 | ||
6 | Now in ocfs2 xattr set, the whole process are divided into many small | |
7 | parts and they are wrapped into diffrent transactions and it make the | |
8 | set doesn't look like a real transaction. So we want to integrate it | |
9 | into a real one. | |
10 | ||
11 | In some cases we will allocate some clusters and free some in just one | |
12 | transaction. e.g, one xattr is larger than inline size, so it and its | |
13 | value root is stored within the inode while the value is outside in a | |
14 | cluster. Then we try to update it with a smaller value(larger than the | |
15 | size of root but smaller than inline size), we may need to free the | |
16 | outside cluster while allocate a new bucket(one cluster) since now the | |
17 | inode may be full. The old solution will lock the global_bitmap(if the | |
18 | local alloc failed in stress test) and then the truncate log. This will | |
19 | cause a ABBA lock with truncate log flush. | |
20 | ||
21 | This patch add the clusters free in dealloc_ctxt, so that we can record | |
22 | the free clusters during the transaction and then free it after we | |
23 | release the global_bitmap in xattr set. | |
24 | ||
25 | Signed-off-by: Tao Ma <tao.ma@oracle.com> | |
26 | Signed-off-by: Mark Fasheh <mfasheh@suse.com> | |
27 | --- | |
28 | fs/ocfs2/alloc.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++---- | |
29 | fs/ocfs2/alloc.h | 4 ++ | |
30 | 2 files changed, 103 insertions(+), 7 deletions(-) | |
31 | ||
32 | Index: linux-2.6.27-ocfs2/fs/ocfs2/alloc.c | |
33 | =================================================================== | |
34 | --- linux-2.6.27-ocfs2.orig/fs/ocfs2/alloc.c | |
35 | +++ linux-2.6.27-ocfs2/fs/ocfs2/alloc.c | |
36 | @@ -5809,7 +5809,10 @@ int ocfs2_truncate_log_init(struct ocfs2 | |
37 | */ | |
38 | ||
39 | /* | |
40 | - * Describes a single block free from a suballocator | |
41 | + * Describe a single bit freed from a suballocator. For the block | |
42 | + * suballocators, it represents one block. For the global cluster | |
43 | + * allocator, it represents some clusters and free_bit indicates | |
44 | + * clusters number. | |
45 | */ | |
46 | struct ocfs2_cached_block_free { | |
47 | struct ocfs2_cached_block_free *free_next; | |
48 | @@ -5824,10 +5827,10 @@ struct ocfs2_per_slot_free_list { | |
49 | struct ocfs2_cached_block_free *f_first; | |
50 | }; | |
51 | ||
52 | -static int ocfs2_free_cached_items(struct ocfs2_super *osb, | |
53 | - int sysfile_type, | |
54 | - int slot, | |
55 | - struct ocfs2_cached_block_free *head) | |
56 | +static int ocfs2_free_cached_blocks(struct ocfs2_super *osb, | |
57 | + int sysfile_type, | |
58 | + int slot, | |
59 | + struct ocfs2_cached_block_free *head) | |
60 | { | |
61 | int ret; | |
62 | u64 bg_blkno; | |
63 | @@ -5902,6 +5905,82 @@ out: | |
64 | return ret; | |
65 | } | |
66 | ||
67 | +int ocfs2_cache_cluster_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt, | |
68 | + u64 blkno, unsigned int bit) | |
69 | +{ | |
70 | + int ret = 0; | |
71 | + struct ocfs2_cached_block_free *item; | |
72 | + | |
73 | + item = kmalloc(sizeof(*item), GFP_NOFS); | |
74 | + if (item == NULL) { | |
75 | + ret = -ENOMEM; | |
76 | + mlog_errno(ret); | |
77 | + return ret; | |
78 | + } | |
79 | + | |
80 | + mlog(0, "Insert clusters: (bit %u, blk %llu)\n", | |
81 | + bit, (unsigned long long)blkno); | |
82 | + | |
83 | + item->free_blk = blkno; | |
84 | + item->free_bit = bit; | |
85 | + item->free_next = ctxt->c_global_allocator; | |
86 | + | |
87 | + ctxt->c_global_allocator = item; | |
88 | + return ret; | |
89 | +} | |
90 | + | |
91 | +static int ocfs2_free_cached_clusters(struct ocfs2_super *osb, | |
92 | + struct ocfs2_cached_block_free *head) | |
93 | +{ | |
94 | + struct ocfs2_cached_block_free *tmp; | |
95 | + struct inode *tl_inode = osb->osb_tl_inode; | |
96 | + handle_t *handle; | |
97 | + int ret = 0; | |
98 | + | |
99 | + mutex_lock(&tl_inode->i_mutex); | |
100 | + | |
101 | + while (head) { | |
102 | + if (ocfs2_truncate_log_needs_flush(osb)) { | |
103 | + ret = __ocfs2_flush_truncate_log(osb); | |
104 | + if (ret < 0) { | |
105 | + mlog_errno(ret); | |
106 | + break; | |
107 | + } | |
108 | + } | |
109 | + | |
110 | + handle = ocfs2_start_trans(osb, OCFS2_TRUNCATE_LOG_UPDATE); | |
111 | + if (IS_ERR(handle)) { | |
112 | + ret = PTR_ERR(handle); | |
113 | + mlog_errno(ret); | |
114 | + break; | |
115 | + } | |
116 | + | |
117 | + ret = ocfs2_truncate_log_append(osb, handle, head->free_blk, | |
118 | + head->free_bit); | |
119 | + | |
120 | + ocfs2_commit_trans(osb, handle); | |
121 | + tmp = head; | |
122 | + head = head->free_next; | |
123 | + kfree(tmp); | |
124 | + | |
125 | + if (ret < 0) { | |
126 | + mlog_errno(ret); | |
127 | + break; | |
128 | + } | |
129 | + } | |
130 | + | |
131 | + mutex_unlock(&tl_inode->i_mutex); | |
132 | + | |
133 | + while (head) { | |
134 | + /* Premature exit may have left some dangling items. */ | |
135 | + tmp = head; | |
136 | + head = head->free_next; | |
137 | + kfree(tmp); | |
138 | + } | |
139 | + | |
140 | + return ret; | |
141 | +} | |
142 | + | |
143 | int ocfs2_run_deallocs(struct ocfs2_super *osb, | |
144 | struct ocfs2_cached_dealloc_ctxt *ctxt) | |
145 | { | |
146 | @@ -5917,8 +5996,10 @@ int ocfs2_run_deallocs(struct ocfs2_supe | |
147 | if (fl->f_first) { | |
148 | mlog(0, "Free items: (type %u, slot %d)\n", | |
149 | fl->f_inode_type, fl->f_slot); | |
150 | - ret2 = ocfs2_free_cached_items(osb, fl->f_inode_type, | |
151 | - fl->f_slot, fl->f_first); | |
152 | + ret2 = ocfs2_free_cached_blocks(osb, | |
153 | + fl->f_inode_type, | |
154 | + fl->f_slot, | |
155 | + fl->f_first); | |
156 | if (ret2) | |
157 | mlog_errno(ret2); | |
158 | if (!ret) | |
159 | @@ -5929,6 +6010,17 @@ int ocfs2_run_deallocs(struct ocfs2_supe | |
160 | kfree(fl); | |
161 | } | |
162 | ||
163 | + if (ctxt->c_global_allocator) { | |
164 | + ret2 = ocfs2_free_cached_clusters(osb, | |
165 | + ctxt->c_global_allocator); | |
166 | + if (ret2) | |
167 | + mlog_errno(ret2); | |
168 | + if (!ret) | |
169 | + ret = ret2; | |
170 | + | |
171 | + ctxt->c_global_allocator = NULL; | |
172 | + } | |
173 | + | |
174 | return ret; | |
175 | } | |
176 | ||
177 | Index: linux-2.6.27-ocfs2/fs/ocfs2/alloc.h | |
178 | =================================================================== | |
179 | --- linux-2.6.27-ocfs2.orig/fs/ocfs2/alloc.h | |
180 | +++ linux-2.6.27-ocfs2/fs/ocfs2/alloc.h | |
181 | @@ -167,11 +167,15 @@ int __ocfs2_flush_truncate_log(struct oc | |
182 | */ | |
183 | struct ocfs2_cached_dealloc_ctxt { | |
184 | struct ocfs2_per_slot_free_list *c_first_suballocator; | |
185 | + struct ocfs2_cached_block_free *c_global_allocator; | |
186 | }; | |
187 | static inline void ocfs2_init_dealloc_ctxt(struct ocfs2_cached_dealloc_ctxt *c) | |
188 | { | |
189 | c->c_first_suballocator = NULL; | |
190 | + c->c_global_allocator = NULL; | |
191 | } | |
192 | +int ocfs2_cache_cluster_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt, | |
193 | + u64 blkno, unsigned int bit); | |
194 | int ocfs2_run_deallocs(struct ocfs2_super *osb, | |
195 | struct ocfs2_cached_dealloc_ctxt *ctxt); | |
196 |