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 | ||
ccd979bd | 41 | /* |
363041a5 MF |
42 | * Return the index of the extent record which contains cluster #v_cluster. |
43 | * -1 is returned if it was not found. | |
ccd979bd | 44 | * |
363041a5 | 45 | * Should work fine on interior and exterior nodes. |
ccd979bd | 46 | */ |
363041a5 MF |
47 | static int ocfs2_search_extent_list(struct ocfs2_extent_list *el, |
48 | u32 v_cluster) | |
ccd979bd | 49 | { |
363041a5 MF |
50 | int ret = -1; |
51 | int i; | |
ccd979bd | 52 | struct ocfs2_extent_rec *rec; |
e48edee2 | 53 | u32 rec_end, rec_start, clusters; |
ccd979bd | 54 | |
363041a5 | 55 | for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) { |
ccd979bd | 56 | rec = &el->l_recs[i]; |
110ba908 | 57 | |
363041a5 | 58 | rec_start = le32_to_cpu(rec->e_cpos); |
e48edee2 MF |
59 | clusters = ocfs2_rec_clusters(el, rec); |
60 | ||
61 | rec_end = rec_start + clusters; | |
110ba908 | 62 | |
363041a5 MF |
63 | if (v_cluster >= rec_start && v_cluster < rec_end) { |
64 | ret = i; | |
65 | break; | |
ccd979bd MF |
66 | } |
67 | } | |
68 | ||
ccd979bd MF |
69 | return ret; |
70 | } | |
71 | ||
9517bac6 MF |
72 | int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, |
73 | u32 *p_cluster, u32 *num_clusters) | |
ccd979bd | 74 | { |
363041a5 MF |
75 | int ret, i; |
76 | struct buffer_head *di_bh = NULL; | |
77 | struct buffer_head *eb_bh = NULL; | |
ccd979bd | 78 | struct ocfs2_dinode *di; |
363041a5 | 79 | struct ocfs2_extent_block *eb; |
ccd979bd | 80 | struct ocfs2_extent_list *el; |
363041a5 MF |
81 | struct ocfs2_extent_rec *rec; |
82 | u32 coff; | |
ccd979bd | 83 | |
363041a5 MF |
84 | ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno, |
85 | &di_bh, OCFS2_BH_CACHED, inode); | |
ccd979bd MF |
86 | if (ret) { |
87 | mlog_errno(ret); | |
363041a5 | 88 | goto out; |
ccd979bd MF |
89 | } |
90 | ||
363041a5 MF |
91 | di = (struct ocfs2_dinode *) di_bh->b_data; |
92 | el = &di->id2.i_list; | |
ccd979bd | 93 | |
363041a5 MF |
94 | if (el->l_tree_depth) { |
95 | ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh); | |
96 | if (ret) { | |
97 | mlog_errno(ret); | |
98 | goto out; | |
99 | } | |
ccd979bd | 100 | |
363041a5 MF |
101 | eb = (struct ocfs2_extent_block *) eb_bh->b_data; |
102 | el = &eb->h_list; | |
e48edee2 MF |
103 | |
104 | if (el->l_tree_depth) { | |
105 | ocfs2_error(inode->i_sb, | |
106 | "Inode %lu has non zero tree depth in " | |
107 | "leaf block %llu\n", inode->i_ino, | |
108 | (unsigned long long)eb_bh->b_blocknr); | |
109 | ret = -EROFS; | |
110 | goto out; | |
111 | } | |
a43db30c | 112 | } |
ccd979bd | 113 | |
363041a5 MF |
114 | i = ocfs2_search_extent_list(el, v_cluster); |
115 | if (i == -1) { | |
a43db30c | 116 | /* |
363041a5 MF |
117 | * A hole was found. Return some canned values that |
118 | * callers can key on. | |
a43db30c | 119 | */ |
363041a5 MF |
120 | *p_cluster = 0; |
121 | if (num_clusters) | |
122 | *num_clusters = 1; | |
123 | } else { | |
124 | rec = &el->l_recs[i]; | |
ccd979bd | 125 | |
363041a5 | 126 | BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)); |
ccd979bd | 127 | |
363041a5 MF |
128 | if (!rec->e_blkno) { |
129 | ocfs2_error(inode->i_sb, "Inode %lu has bad extent " | |
130 | "record (%u, %u, 0)", inode->i_ino, | |
131 | le32_to_cpu(rec->e_cpos), | |
e48edee2 | 132 | ocfs2_rec_clusters(el, rec)); |
363041a5 MF |
133 | ret = -EROFS; |
134 | goto out; | |
ccd979bd MF |
135 | } |
136 | ||
363041a5 | 137 | coff = v_cluster - le32_to_cpu(rec->e_cpos); |
ccd979bd | 138 | |
363041a5 MF |
139 | *p_cluster = ocfs2_blocks_to_clusters(inode->i_sb, |
140 | le64_to_cpu(rec->e_blkno)); | |
141 | *p_cluster = *p_cluster + coff; | |
ccd979bd | 142 | |
363041a5 | 143 | if (num_clusters) |
e48edee2 | 144 | *num_clusters = ocfs2_rec_clusters(el, rec) - coff; |
ccd979bd MF |
145 | } |
146 | ||
363041a5 MF |
147 | out: |
148 | brelse(di_bh); | |
149 | brelse(eb_bh); | |
ccd979bd MF |
150 | return ret; |
151 | } | |
152 | ||
ccd979bd | 153 | /* |
363041a5 MF |
154 | * This expects alloc_sem to be held. The allocation cannot change at |
155 | * all while the map is in the process of being updated. | |
ccd979bd | 156 | */ |
363041a5 MF |
157 | int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno, |
158 | int *ret_count) | |
ccd979bd MF |
159 | { |
160 | int ret; | |
ccd979bd | 161 | int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); |
363041a5 MF |
162 | u32 cpos, num_clusters, p_cluster; |
163 | u64 boff = 0; | |
ccd979bd MF |
164 | |
165 | cpos = ocfs2_blocks_to_clusters(inode->i_sb, v_blkno); | |
ccd979bd | 166 | |
363041a5 | 167 | ret = ocfs2_get_clusters(inode, cpos, &p_cluster, &num_clusters); |
ccd979bd MF |
168 | if (ret) { |
169 | mlog_errno(ret); | |
363041a5 | 170 | goto out; |
ccd979bd MF |
171 | } |
172 | ||
363041a5 MF |
173 | /* |
174 | * p_cluster == 0 indicates a hole. | |
175 | */ | |
176 | if (p_cluster) { | |
177 | boff = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster); | |
ccd979bd | 178 | boff += (v_blkno & (u64)(bpc - 1)); |
ccd979bd MF |
179 | } |
180 | ||
363041a5 | 181 | *p_blkno = boff; |
ccd979bd | 182 | |
363041a5 MF |
183 | if (ret_count) { |
184 | *ret_count = ocfs2_clusters_to_blocks(inode->i_sb, num_clusters); | |
185 | *ret_count -= v_blkno & (u64)(bpc - 1); | |
ccd979bd | 186 | } |
ccd979bd | 187 | |
363041a5 MF |
188 | out: |
189 | return ret; | |
ccd979bd | 190 | } |