xref: /dragonfly/sbin/hammer/blockmap.c (revision be09fc23)
1 /*
2  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $DragonFly: src/sbin/hammer/blockmap.c,v 1.2 2008/06/17 04:03:38 dillon Exp $
35  */
36 
37 #include "hammer.h"
38 
39 hammer_off_t
40 blockmap_lookup(hammer_off_t zone_offset,
41 		struct hammer_blockmap_layer1 *save_layer1,
42 		struct hammer_blockmap_layer2 *save_layer2,
43 		int *errorp)
44 {
45 	struct volume_info *root_volume = NULL;
46 	hammer_blockmap_t blockmap;
47 	hammer_blockmap_t freemap;
48 	struct hammer_blockmap_layer1 *layer1;
49 	struct hammer_blockmap_layer2 *layer2;
50 	struct buffer_info *buffer1 = NULL;
51 	struct buffer_info *buffer2 = NULL;
52 	hammer_off_t layer1_offset;
53 	hammer_off_t layer2_offset;
54 	hammer_off_t result_offset;
55 	int zone;
56 	int i;
57 	int error = 0;
58 
59 	if (save_layer1)
60 		bzero(save_layer1, sizeof(*save_layer1));
61 	if (save_layer2)
62 		bzero(save_layer2, sizeof(*save_layer2));
63 
64 	zone = HAMMER_ZONE_DECODE(zone_offset);
65 
66 	if (zone <= HAMMER_ZONE_RAW_VOLUME_INDEX)
67 		error = -1;
68 	if (zone >= HAMMER_MAX_ZONES)
69 		error = -2;
70 	if (RootVolNo < 0)
71 		error = -3;
72 	if (error) {
73 		result_offset = HAMMER_OFF_BAD;
74 		goto done;
75 	}
76 
77 	root_volume = get_volume(RootVolNo);
78 	blockmap = &root_volume->ondisk->vol0_blockmap[zone];
79 
80 	if (zone == HAMMER_ZONE_RAW_BUFFER_INDEX) {
81 		result_offset = zone_offset;
82 	} else if (zone == HAMMER_ZONE_UNDO_INDEX) {
83 		i = (zone_offset & HAMMER_OFF_SHORT_MASK) /
84 		    HAMMER_BIGBLOCK_SIZE;
85 		if (zone_offset >= blockmap->alloc_offset) {
86 			error = -4;
87 			result_offset = HAMMER_OFF_BAD;
88 			goto done;
89 		}
90 		result_offset = root_volume->ondisk->vol0_undo_array[i] +
91 				(zone_offset & HAMMER_BIGBLOCK_MASK64);
92 	} else {
93 		result_offset = hammer_xlate_to_zone2(zone_offset);
94 	}
95 
96 	/*
97 	 * The blockmap should match the requested zone (else the volume
98 	 * header is mashed).
99 	 *
100 	 * Note that a valid offset can still be returned if AssertOnFailure
101 	 * is zero.
102 	 */
103 	if (HAMMER_ZONE_FREEMAP_INDEX != zone &&
104 	    HAMMER_ZONE_DECODE(blockmap->alloc_offset) != zone) {
105 		error = -5;
106 		goto done;
107 	}
108 
109 	/*
110 	 * Validate that the big-block is assigned to the zone.  Also
111 	 * assign save_layer{1,2}.
112 	 */
113 
114 	freemap = &root_volume->ondisk->vol0_blockmap[HAMMER_ZONE_FREEMAP_INDEX];
115 	/*
116 	 * Dive layer 1.
117 	 */
118 	layer1_offset = freemap->phys_offset +
119 			HAMMER_BLOCKMAP_LAYER1_OFFSET(result_offset);
120 	layer1 = get_buffer_data(layer1_offset, &buffer1, 0);
121 	if (layer1 == NULL) {
122 		error = -6;
123 		goto done;
124 	}
125 	if (layer1->phys_offset == HAMMER_BLOCKMAP_UNAVAIL) {
126 		error = -7;
127 		goto done;
128 	}
129 
130 	if (save_layer1)
131 		*save_layer1 = *layer1;
132 
133 	/*
134 	 * Dive layer 2, each entry represents a big-block.
135 	 */
136 	layer2_offset = layer1->phys_offset +
137 			HAMMER_BLOCKMAP_LAYER2_OFFSET(result_offset);
138 	layer2 = get_buffer_data(layer2_offset, &buffer2, 0);
139 
140 	if (layer2 == NULL) {
141 		error = -8;
142 		goto done;
143 	}
144 	if (layer2->zone != zone) {
145 		error = -9;
146 		goto done;
147 	}
148 	if (save_layer2)
149 		*save_layer2 = *layer2;
150 
151 done:
152 	rel_buffer(buffer1);
153 	rel_buffer(buffer2);
154 	rel_volume(root_volume);
155 
156 	if (AssertOnFailure && error != 0)
157 		errx(1, "blockmap_lookup: error=%d\n", error);
158 	if (errorp)
159 		*errorp = error;
160 
161 	return(result_offset);
162 }
163 
164