]>
Commit | Line | Data |
---|---|---|
ccd979bd MF |
1 | /* -*- mode: c; c-basic-offset: 8; -*- |
2 | * vim: noexpandtab sw=8 ts=8 sts=0: | |
3 | * | |
4 | * extent_map.c | |
5 | * | |
363041a5 | 6 | * Block/Cluster mapping functions |
ccd979bd MF |
7 | * |
8 | * Copyright (C) 2004 Oracle. All rights reserved. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU General Public | |
12 | * License, version 2, as published by the Free Software Foundation. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public | |
20 | * License along with this program; if not, write to the | |
21 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
22 | * Boston, MA 021110-1307, USA. | |
23 | */ | |
24 | ||
25 | #include <linux/fs.h> | |
26 | #include <linux/init.h> | |
27 | #include <linux/types.h> | |
ccd979bd MF |
28 | |
29 | #define MLOG_MASK_PREFIX ML_EXTENT_MAP | |
30 | #include <cluster/masklog.h> | |
31 | ||
32 | #include "ocfs2.h" | |
33 | ||
363041a5 | 34 | #include "alloc.h" |
ccd979bd MF |
35 | #include "extent_map.h" |
36 | #include "inode.h" | |
37 | #include "super.h" | |
38 | ||
39 | #include "buffer_head_io.h" | |
40 | ||
4f902c37 MF |
41 | /* |
42 | * Return the 1st index within el which contains an extent start | |
43 | * larger than v_cluster. | |
44 | */ | |
45 | static int ocfs2_search_for_hole_index(struct ocfs2_extent_list *el, | |
46 | u32 v_cluster) | |
47 | { | |
48 | int i; | |
49 | struct ocfs2_extent_rec *rec; | |
50 | ||
51 | for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) { | |
52 | rec = &el->l_recs[i]; | |
53 | ||
54 | if (v_cluster < le32_to_cpu(rec->e_cpos)) | |
55 | break; | |
56 | } | |
57 | ||
58 | return i; | |
59 | } | |
60 | ||
61 | /* | |
62 | * Figure out the size of a hole which starts at v_cluster within the given | |
63 | * extent list. | |
64 | * | |
65 | * If there is no more allocation past v_cluster, we return the maximum | |
66 | * cluster size minus v_cluster. | |
67 | * | |
68 | * If we have in-inode extents, then el points to the dinode list and | |
69 | * eb_bh is NULL. Otherwise, eb_bh should point to the extent block | |
70 | * containing el. | |
71 | */ | |
72 | static int ocfs2_figure_hole_clusters(struct inode *inode, | |
73 | struct ocfs2_extent_list *el, | |
74 | struct buffer_head *eb_bh, | |
75 | u32 v_cluster, | |
76 | u32 *num_clusters) | |
77 | { | |
78 | int ret, i; | |
79 | struct buffer_head *next_eb_bh = NULL; | |
80 | struct ocfs2_extent_block *eb, *next_eb; | |
81 | ||
82 | i = ocfs2_search_for_hole_index(el, v_cluster); | |
83 | ||
84 | if (i == le16_to_cpu(el->l_next_free_rec) && eb_bh) { | |
85 | eb = (struct ocfs2_extent_block *)eb_bh->b_data; | |
86 | ||
87 | /* | |
88 | * Check the next leaf for any extents. | |
89 | */ | |
90 | ||
91 | if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL) | |
92 | goto no_more_extents; | |
93 | ||
94 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), | |
95 | le64_to_cpu(eb->h_next_leaf_blk), | |
96 | &next_eb_bh, OCFS2_BH_CACHED, inode); | |
97 | if (ret) { | |
98 | mlog_errno(ret); | |
99 | goto out; | |
100 | } | |
101 | next_eb = (struct ocfs2_extent_block *)next_eb_bh->b_data; | |
102 | ||
103 | if (!OCFS2_IS_VALID_EXTENT_BLOCK(next_eb)) { | |
104 | ret = -EROFS; | |
105 | OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, next_eb); | |
106 | goto out; | |
107 | } | |
108 | ||
109 | el = &next_eb->h_list; | |
110 | ||
111 | i = ocfs2_search_for_hole_index(el, v_cluster); | |
112 | } | |
113 | ||
114 | no_more_extents: | |
115 | if (i == le16_to_cpu(el->l_next_free_rec)) { | |
116 | /* | |
117 | * We're at the end of our existing allocation. Just | |
118 | * return the maximum number of clusters we could | |
119 | * possibly allocate. | |
120 | */ | |
121 | *num_clusters = UINT_MAX - v_cluster; | |
122 | } else { | |
123 | *num_clusters = le32_to_cpu(el->l_recs[i].e_cpos) - v_cluster; | |
124 | } | |
125 | ||
126 | ret = 0; | |
127 | out: | |
128 | brelse(next_eb_bh); | |
129 | return ret; | |
130 | } | |
131 | ||
ccd979bd | 132 | /* |
363041a5 MF |
133 | * Return the index of the extent record which contains cluster #v_cluster. |
134 | * -1 is returned if it was not found. | |
ccd979bd | 135 | * |
363041a5 | 136 | * Should work fine on interior and exterior nodes. |
ccd979bd | 137 | */ |
363041a5 MF |
138 | static int ocfs2_search_extent_list(struct ocfs2_extent_list *el, |
139 | u32 v_cluster) | |
ccd979bd | 140 | { |
363041a5 MF |
141 | int ret = -1; |
142 | int i; | |
ccd979bd | 143 | struct ocfs2_extent_rec *rec; |
e48edee2 | 144 | u32 rec_end, rec_start, clusters; |
ccd979bd | 145 | |
363041a5 | 146 | for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) { |
ccd979bd | 147 | rec = &el->l_recs[i]; |
110ba908 | 148 | |
363041a5 | 149 | rec_start = le32_to_cpu(rec->e_cpos); |
e48edee2 MF |
150 | clusters = ocfs2_rec_clusters(el, rec); |
151 | ||
152 | rec_end = rec_start + clusters; | |
110ba908 | 153 | |
363041a5 MF |
154 | if (v_cluster >= rec_start && v_cluster < rec_end) { |
155 | ret = i; | |
156 | break; | |
ccd979bd MF |
157 | } |
158 | } | |
159 | ||
ccd979bd MF |
160 | return ret; |
161 | } | |
162 | ||
9517bac6 | 163 | int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, |
49cb8d2d MF |
164 | u32 *p_cluster, u32 *num_clusters, |
165 | unsigned int *extent_flags) | |
ccd979bd | 166 | { |
363041a5 | 167 | int ret, i; |
49cb8d2d | 168 | unsigned int flags = 0; |
363041a5 MF |
169 | struct buffer_head *di_bh = NULL; |
170 | struct buffer_head *eb_bh = NULL; | |
ccd979bd | 171 | struct ocfs2_dinode *di; |
363041a5 | 172 | struct ocfs2_extent_block *eb; |
ccd979bd | 173 | struct ocfs2_extent_list *el; |
363041a5 MF |
174 | struct ocfs2_extent_rec *rec; |
175 | u32 coff; | |
ccd979bd | 176 | |
363041a5 MF |
177 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno, |
178 | &di_bh, OCFS2_BH_CACHED, inode); | |
ccd979bd MF |
179 | if (ret) { |
180 | mlog_errno(ret); | |
363041a5 | 181 | goto out; |
ccd979bd MF |
182 | } |
183 | ||
363041a5 MF |
184 | di = (struct ocfs2_dinode *) di_bh->b_data; |
185 | el = &di->id2.i_list; | |
ccd979bd | 186 | |
363041a5 MF |
187 | if (el->l_tree_depth) { |
188 | ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh); | |
189 | if (ret) { | |
190 | mlog_errno(ret); | |
191 | goto out; | |
192 | } | |
ccd979bd | 193 | |
363041a5 MF |
194 | eb = (struct ocfs2_extent_block *) eb_bh->b_data; |
195 | el = &eb->h_list; | |
e48edee2 MF |
196 | |
197 | if (el->l_tree_depth) { | |
198 | ocfs2_error(inode->i_sb, | |
199 | "Inode %lu has non zero tree depth in " | |
200 | "leaf block %llu\n", inode->i_ino, | |
201 | (unsigned long long)eb_bh->b_blocknr); | |
202 | ret = -EROFS; | |
203 | goto out; | |
204 | } | |
a43db30c | 205 | } |
ccd979bd | 206 | |
363041a5 MF |
207 | i = ocfs2_search_extent_list(el, v_cluster); |
208 | if (i == -1) { | |
a43db30c | 209 | /* |
363041a5 | 210 | * A hole was found. Return some canned values that |
4f902c37 MF |
211 | * callers can key on. If asked for, num_clusters will |
212 | * be populated with the size of the hole. | |
a43db30c | 213 | */ |
363041a5 | 214 | *p_cluster = 0; |
4f902c37 MF |
215 | if (num_clusters) { |
216 | ret = ocfs2_figure_hole_clusters(inode, el, eb_bh, | |
217 | v_cluster, | |
218 | num_clusters); | |
219 | if (ret) { | |
220 | mlog_errno(ret); | |
221 | goto out; | |
222 | } | |
223 | } | |
363041a5 MF |
224 | } else { |
225 | rec = &el->l_recs[i]; | |
ccd979bd | 226 | |
363041a5 | 227 | BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)); |
ccd979bd | 228 | |
363041a5 MF |
229 | if (!rec->e_blkno) { |
230 | ocfs2_error(inode->i_sb, "Inode %lu has bad extent " | |
231 | "record (%u, %u, 0)", inode->i_ino, | |
232 | le32_to_cpu(rec->e_cpos), | |
e48edee2 | 233 | ocfs2_rec_clusters(el, rec)); |
363041a5 MF |
234 | ret = -EROFS; |
235 | goto out; | |
ccd979bd MF |
236 | } |
237 | ||
363041a5 | 238 | coff = v_cluster - le32_to_cpu(rec->e_cpos); |
ccd979bd | 239 | |
363041a5 MF |
240 | *p_cluster = ocfs2_blocks_to_clusters(inode->i_sb, |
241 | le64_to_cpu(rec->e_blkno)); | |
242 | *p_cluster = *p_cluster + coff; | |
ccd979bd | 243 | |
363041a5 | 244 | if (num_clusters) |
e48edee2 | 245 | *num_clusters = ocfs2_rec_clusters(el, rec) - coff; |
49cb8d2d MF |
246 | |
247 | flags = rec->e_flags; | |
ccd979bd MF |
248 | } |
249 | ||
49cb8d2d MF |
250 | if (extent_flags) |
251 | *extent_flags = flags; | |
252 | ||
363041a5 MF |
253 | out: |
254 | brelse(di_bh); | |
255 | brelse(eb_bh); | |
ccd979bd MF |
256 | return ret; |
257 | } | |
258 | ||
ccd979bd | 259 | /* |
363041a5 MF |
260 | * This expects alloc_sem to be held. The allocation cannot change at |
261 | * all while the map is in the process of being updated. | |
ccd979bd | 262 | */ |
363041a5 | 263 | int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno, |
4f902c37 | 264 | u64 *ret_count, unsigned int *extent_flags) |
ccd979bd MF |
265 | { |
266 | int ret; | |
ccd979bd | 267 | int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); |
363041a5 MF |
268 | u32 cpos, num_clusters, p_cluster; |
269 | u64 boff = 0; | |
ccd979bd MF |
270 | |
271 | cpos = ocfs2_blocks_to_clusters(inode->i_sb, v_blkno); | |
ccd979bd | 272 | |
49cb8d2d MF |
273 | ret = ocfs2_get_clusters(inode, cpos, &p_cluster, &num_clusters, |
274 | extent_flags); | |
ccd979bd MF |
275 | if (ret) { |
276 | mlog_errno(ret); | |
363041a5 | 277 | goto out; |
ccd979bd MF |
278 | } |
279 | ||
363041a5 MF |
280 | /* |
281 | * p_cluster == 0 indicates a hole. | |
282 | */ | |
283 | if (p_cluster) { | |
284 | boff = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster); | |
ccd979bd | 285 | boff += (v_blkno & (u64)(bpc - 1)); |
ccd979bd MF |
286 | } |
287 | ||
363041a5 | 288 | *p_blkno = boff; |
ccd979bd | 289 | |
363041a5 MF |
290 | if (ret_count) { |
291 | *ret_count = ocfs2_clusters_to_blocks(inode->i_sb, num_clusters); | |
292 | *ret_count -= v_blkno & (u64)(bpc - 1); | |
ccd979bd | 293 | } |
ccd979bd | 294 | |
363041a5 MF |
295 | out: |
296 | return ret; | |
ccd979bd | 297 | } |