extent_map.c 6.9 KB
Newer Older
1 2 3 4 5
/* -*- mode: c; c-basic-offset: 8; -*-
 * vim: noexpandtab sw=8 ts=8 sts=0:
 *
 * extent_map.c
 *
6
 * Block/Cluster mapping functions
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 *
 * Copyright (C) 2004 Oracle.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License, version 2,  as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 */

#include <linux/fs.h>
#include <linux/init.h>
#include <linux/types.h>

#define MLOG_MASK_PREFIX ML_EXTENT_MAP
#include <cluster/masklog.h>

#include "ocfs2.h"

34
#include "alloc.h"
35 36 37 38 39 40
#include "extent_map.h"
#include "inode.h"
#include "super.h"

#include "buffer_head_io.h"

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
/*
 * Return the 1st index within el which contains an extent start
 * larger than v_cluster.
 */
static int ocfs2_search_for_hole_index(struct ocfs2_extent_list *el,
				       u32 v_cluster)
{
	int i;
	struct ocfs2_extent_rec *rec;

	for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) {
		rec = &el->l_recs[i];

		if (v_cluster < le32_to_cpu(rec->e_cpos))
			break;
	}

	return i;
}

/*
 * Figure out the size of a hole which starts at v_cluster within the given
 * extent list.
 *
 * If there is no more allocation past v_cluster, we return the maximum
 * cluster size minus v_cluster.
 *
 * If we have in-inode extents, then el points to the dinode list and
 * eb_bh is NULL. Otherwise, eb_bh should point to the extent block
 * containing el.
 */
static int ocfs2_figure_hole_clusters(struct inode *inode,
				      struct ocfs2_extent_list *el,
				      struct buffer_head *eb_bh,
				      u32 v_cluster,
				      u32 *num_clusters)
{
	int ret, i;
	struct buffer_head *next_eb_bh = NULL;
	struct ocfs2_extent_block *eb, *next_eb;

	i = ocfs2_search_for_hole_index(el, v_cluster);

	if (i == le16_to_cpu(el->l_next_free_rec) && eb_bh) {
		eb = (struct ocfs2_extent_block *)eb_bh->b_data;

		/*
		 * Check the next leaf for any extents.
		 */

		if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL)
			goto no_more_extents;

		ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
				       le64_to_cpu(eb->h_next_leaf_blk),
				       &next_eb_bh, OCFS2_BH_CACHED, inode);
		if (ret) {
			mlog_errno(ret);
			goto out;
		}
		next_eb = (struct ocfs2_extent_block *)next_eb_bh->b_data;

		if (!OCFS2_IS_VALID_EXTENT_BLOCK(next_eb)) {
			ret = -EROFS;
			OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, next_eb);
			goto out;
		}

		el = &next_eb->h_list;

		i = ocfs2_search_for_hole_index(el, v_cluster);
	}

no_more_extents:
	if (i == le16_to_cpu(el->l_next_free_rec)) {
		/*
		 * We're at the end of our existing allocation. Just
		 * return the maximum number of clusters we could
		 * possibly allocate.
		 */
		*num_clusters = UINT_MAX - v_cluster;
	} else {
		*num_clusters = le32_to_cpu(el->l_recs[i].e_cpos) - v_cluster;
	}

	ret = 0;
out:
	brelse(next_eb_bh);
	return ret;
}

132
/*
133 134
 * Return the index of the extent record which contains cluster #v_cluster.
 * -1 is returned if it was not found.
135
 *
136
 * Should work fine on interior and exterior nodes.
137
 */
138 139
static int ocfs2_search_extent_list(struct ocfs2_extent_list *el,
				    u32 v_cluster)
140
{
141 142
	int ret = -1;
	int i;
143
	struct ocfs2_extent_rec *rec;
144
	u32 rec_end, rec_start, clusters;
145

146
	for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) {
147
		rec = &el->l_recs[i];
148

149
		rec_start = le32_to_cpu(rec->e_cpos);
150 151 152
		clusters = ocfs2_rec_clusters(el, rec);

		rec_end = rec_start + clusters;
153

154 155 156
		if (v_cluster >= rec_start && v_cluster < rec_end) {
			ret = i;
			break;
157 158 159 160 161 162
		}
	}

	return ret;
}

163
int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
164 165
		       u32 *p_cluster, u32 *num_clusters,
		       unsigned int *extent_flags)
166
{
167
	int ret, i;
168
	unsigned int flags = 0;
169 170
	struct buffer_head *di_bh = NULL;
	struct buffer_head *eb_bh = NULL;
171
	struct ocfs2_dinode *di;
172
	struct ocfs2_extent_block *eb;
173
	struct ocfs2_extent_list *el;
174 175
	struct ocfs2_extent_rec *rec;
	u32 coff;
176

177 178
	ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno,
			       &di_bh, OCFS2_BH_CACHED, inode);
179 180
	if (ret) {
		mlog_errno(ret);
181
		goto out;
182 183
	}

184 185
	di = (struct ocfs2_dinode *) di_bh->b_data;
	el = &di->id2.i_list;
186

187 188 189 190 191 192
	if (el->l_tree_depth) {
		ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh);
		if (ret) {
			mlog_errno(ret);
			goto out;
		}
193

194 195
		eb = (struct ocfs2_extent_block *) eb_bh->b_data;
		el = &eb->h_list;
196 197 198 199 200 201 202 203 204

		if (el->l_tree_depth) {
			ocfs2_error(inode->i_sb,
				    "Inode %lu has non zero tree depth in "
				    "leaf block %llu\n", inode->i_ino,
				    (unsigned long long)eb_bh->b_blocknr);
			ret = -EROFS;
			goto out;
		}
205
	}
206

207 208
	i = ocfs2_search_extent_list(el, v_cluster);
	if (i == -1) {
209
		/*
210
		 * A hole was found. Return some canned values that
211 212
		 * callers can key on. If asked for, num_clusters will
		 * be populated with the size of the hole.
213
		 */
214
		*p_cluster = 0;
215 216 217 218 219 220 221 222 223
		if (num_clusters) {
			ret = ocfs2_figure_hole_clusters(inode, el, eb_bh,
							 v_cluster,
							 num_clusters);
			if (ret) {
				mlog_errno(ret);
				goto out;
			}
		}
224 225
	} else {
		rec = &el->l_recs[i];
226

227
		BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos));
228

229 230 231 232
		if (!rec->e_blkno) {
			ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
				    "record (%u, %u, 0)", inode->i_ino,
				    le32_to_cpu(rec->e_cpos),
233
				    ocfs2_rec_clusters(el, rec));
234 235
			ret = -EROFS;
			goto out;
236 237
		}

238
		coff = v_cluster - le32_to_cpu(rec->e_cpos);
239

240 241 242
		*p_cluster = ocfs2_blocks_to_clusters(inode->i_sb,
						    le64_to_cpu(rec->e_blkno));
		*p_cluster = *p_cluster + coff;
243

244
		if (num_clusters)
245
			*num_clusters = ocfs2_rec_clusters(el, rec) - coff;
246 247

		flags = rec->e_flags;
248 249
	}

250 251 252
	if (extent_flags)
		*extent_flags = flags;

253 254 255
out:
	brelse(di_bh);
	brelse(eb_bh);
256 257 258 259
	return ret;
}

/*
260 261
 * This expects alloc_sem to be held. The allocation cannot change at
 * all while the map is in the process of being updated.
262
 */
263
int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno,
264
				u64 *ret_count, unsigned int *extent_flags)
265 266 267
{
	int ret;
	int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
268 269
	u32 cpos, num_clusters, p_cluster;
	u64 boff = 0;
270 271 272

	cpos = ocfs2_blocks_to_clusters(inode->i_sb, v_blkno);

273 274
	ret = ocfs2_get_clusters(inode, cpos, &p_cluster, &num_clusters,
				 extent_flags);
275 276
	if (ret) {
		mlog_errno(ret);
277
		goto out;
278 279
	}

280 281 282 283 284
	/*
	 * p_cluster == 0 indicates a hole.
	 */
	if (p_cluster) {
		boff = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
285 286 287
		boff += (v_blkno & (u64)(bpc - 1));
	}

288
	*p_blkno = boff;
289

290 291 292
	if (ret_count) {
		*ret_count = ocfs2_clusters_to_blocks(inode->i_sb, num_clusters);
		*ret_count -= v_blkno & (u64)(bpc - 1);
293 294
	}

295 296
out:
	return ret;
297
}