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