2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
34 * $DragonFly: src/sbin/hammer/ondisk.c,v 1.1 2007/10/16 18:30:53 dillon Exp $
37 #include "newfs_hammer.h"
39 static void initbuffer(hammer_alist_t live, hammer_fsbuf_head_t head,
41 static void alloc_new_buffer(struct cluster_info *cluster, hammer_alist_t live,
42 u_int64_t type, int32_t nelements);
44 static void readhammerbuf(struct volume_info *vol, void *data,
47 static void writehammerbuf(struct volume_info *vol, const void *data,
51 * Lookup the requested information structure and related on-disk buffer.
52 * Except for getvolume(), these functions will create and initialize any
53 * missing info structures.
56 get_volume(int32_t vol_no)
58 struct volume_info *vol;
59 struct hammer_volume_ondisk *ondisk;
61 for (vol = VolBase; vol; vol = vol->next) {
62 if (vol->vol_no == vol_no)
65 if (vol && vol->ondisk == NULL) {
66 vol->ondisk = ondisk = malloc(HAMMER_BUFSIZE);
67 bzero(ondisk, HAMMER_BUFSIZE);
68 if (UsingSuperClusters) {
69 vol->alist.config = &Vol_super_alist_config;
70 vol->alist.meta = ondisk->vol_almeta.super;
71 vol->alist.info = vol;
72 hammer_alist_init(&vol->alist);
74 vol->alist.config = &Vol_normal_alist_config;
75 vol->alist.meta = ondisk->vol_almeta.normal;
76 hammer_alist_init(&vol->alist);
83 get_supercl(struct volume_info *vol, int32_t scl_no)
85 struct hammer_supercl_ondisk *ondisk;
86 struct supercl_info *scl;
88 int64_t scl_group_size;
90 assert(UsingSuperClusters);
92 for (scl = vol->supercl_base; scl; scl = scl->next) {
93 if (scl->scl_no == scl_no)
100 scl = malloc(sizeof(*scl));
101 bzero(scl, sizeof(*scl));
102 scl->scl_no = scl_no;
103 scl->next = vol->supercl_base;
105 vol->supercl_base = scl;
108 * Calculate the super-cluster's offset in the volume.
110 * The arrangement is [scl * N][N * 32768 clusters], repeat.
113 scl_group = scl_no / HAMMER_VOL_SUPERCLUSTER_GROUP;
114 scl_group_size = ((int64_t)HAMMER_BUFSIZE *
115 HAMMER_VOL_SUPERCLUSTER_GROUP) +
116 ((int64_t)HAMMER_VOL_SUPERCLUSTER_GROUP *
117 ClusterSize * HAMMER_SCL_MAXCLUSTERS);
118 scl->scl_offset = vol->vol_cluster_off +
119 scl_group * scl_group_size +
120 (scl_no % HAMMER_VOL_SUPERCLUSTER_GROUP) *
123 if (scl->ondisk == NULL) {
124 scl->ondisk = ondisk = malloc(HAMMER_BUFSIZE);
125 bzero(ondisk, HAMMER_BUFSIZE);
126 scl->alist.config = &Supercl_alist_config;
127 scl->alist.meta = ondisk->scl_meta;
128 hammer_alist_init(&scl->alist);
133 struct cluster_info *
134 get_cluster(struct volume_info *vol, int32_t clu_no)
136 struct hammer_cluster_ondisk *ondisk;
137 struct cluster_info *cl;
139 int64_t scl_group_size;
141 for (cl = vol->cluster_base; cl; cl = cl->next) {
142 if (cl->clu_no == clu_no)
147 * Allocate the cluster
149 cl = malloc(sizeof(*cl));
150 bzero(cl, sizeof(*cl));
152 cl->next = vol->cluster_base;
153 if (UsingSuperClusters) {
154 cl->supercl = get_supercl(vol, clu_no / HAMMER_SCL_MAXCLUSTERS);
157 vol->cluster_base = cl;
160 * Calculate the cluster's offset in the volume
162 * The arrangement is [scl * N][N * 32768 clusters], repeat.
165 * Note that the cluster offset calculation is slightly
166 * different from the supercluster offset calculation due
167 * to the way the grouping works.
169 if (UsingSuperClusters) {
170 scl_group = clu_no / HAMMER_VOL_SUPERCLUSTER_GROUP /
171 HAMMER_SCL_MAXCLUSTERS;
173 ((int64_t)HAMMER_BUFSIZE *
174 HAMMER_VOL_SUPERCLUSTER_GROUP) +
175 ((int64_t)HAMMER_VOL_SUPERCLUSTER_GROUP *
176 ClusterSize * HAMMER_SCL_MAXCLUSTERS);
177 scl_group_size += HAMMER_VOL_SUPERCLUSTER_GROUP *
180 vol->vol_cluster_off +
181 scl_group * scl_group_size +
182 (HAMMER_BUFSIZE * HAMMER_VOL_SUPERCLUSTER_GROUP) +
183 ((int64_t)clu_no % ((int64_t)HAMMER_SCL_MAXCLUSTERS * HAMMER_VOL_SUPERCLUSTER_GROUP)) *
186 cl->clu_offset = vol->vol_cluster_off +
187 (int64_t)clu_no * ClusterSize;
190 if (cl->ondisk == NULL) {
191 cl->ondisk = ondisk = malloc(HAMMER_BUFSIZE);
192 bzero(ondisk, HAMMER_BUFSIZE);
193 cl->alist_master.config = &Clu_master_alist_config;
194 cl->alist_master.meta = ondisk->clu_master_meta;
195 hammer_alist_init(&cl->alist_master);
196 cl->alist_btree.config = &Clu_slave_alist_config;
197 cl->alist_btree.meta = ondisk->clu_btree_meta;
198 cl->alist_btree.info = cl;
199 hammer_alist_init(&cl->alist_btree);
200 cl->alist_record.config = &Clu_slave_alist_config;
201 cl->alist_record.meta = ondisk->clu_record_meta;
202 cl->alist_record.info = cl;
203 hammer_alist_init(&cl->alist_record);
204 cl->alist_mdata.config = &Clu_slave_alist_config;
205 cl->alist_mdata.meta = ondisk->clu_mdata_meta;
206 cl->alist_mdata.info = cl;
207 hammer_alist_init(&cl->alist_mdata);
213 get_buffer(struct cluster_info *cl, int32_t buf_no, int64_t buf_type)
215 hammer_fsbuf_ondisk_t ondisk;
216 struct buffer_info *buf;
219 * Find the buffer. Note that buffer 0 corresponds to the cluster
220 * header and should never be requested.
223 for (buf = cl->buffer_base; buf; buf = buf->next) {
224 if (buf->buf_no == buf_no)
228 buf = malloc(sizeof(*buf));
229 bzero(buf, sizeof(*buf));
230 buf->buf_no = buf_no;
231 buf->buf_offset = cl->clu_offset + buf_no * HAMMER_BUFSIZE;
233 buf->volume = cl->volume;
234 buf->next = cl->buffer_base;
235 cl->buffer_base = buf;
237 if (buf->ondisk == NULL) {
238 buf->ondisk = ondisk = malloc(HAMMER_BUFSIZE);
239 bzero(ondisk, HAMMER_BUFSIZE);
240 buf->alist.config = &Buf_alist_config;
241 buf->alist.meta = ondisk->head.buf_almeta;
242 initbuffer(&buf->alist, &ondisk->head, buf_type);
248 * Allocate HAMMER elements - btree nodes, data storage, and record elements
251 alloc_btree_element(struct cluster_info *cluster, int32_t *offp)
253 struct buffer_info *buf;
258 live = &cluster->alist_btree;
259 elm_no = hammer_alist_alloc_fwd(live, 1, cluster->ondisk->idx_index);
260 if (elm_no == HAMMER_ALIST_BLOCK_NONE)
261 elm_no = hammer_alist_alloc_fwd(live, 1, 0);
262 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
263 alloc_new_buffer(cluster, live,
264 HAMMER_FSBUF_BTREE, HAMMER_BTREE_NODES);
265 elm_no = hammer_alist_alloc(live, 1);
266 assert(elm_no != HAMMER_ALIST_BLOCK_NONE);
268 cluster->ondisk->idx_index = elm_no;
269 buf = get_buffer(cluster, elm_no / HAMMER_FSBUF_MAXBLKS, 0);
270 assert(buf->ondisk->head.buf_type != 0);
271 item = &buf->ondisk->btree.nodes[elm_no & HAMMER_FSBUF_BLKMASK];
272 *offp = buf->buf_no * HAMMER_BUFSIZE +
273 ((char *)item - (char *)buf->ondisk);
278 alloc_data_element(struct cluster_info *cluster, int32_t bytes, int32_t *offp)
280 struct buffer_info *buf;
283 int32_t nblks = (bytes + HAMMER_DATA_BLKMASK) & ~HAMMER_DATA_BLKMASK;
287 * Try to allocate a btree-node. If elm_no is HAMMER_ALIST_BLOCK_NONE
288 * and buf is non-NULL we have to initialize a new buffer's a-list.
290 live = &cluster->alist_mdata;
291 elm_no = hammer_alist_alloc_fwd(live, nblks, cluster->ondisk->idx_data);
292 if (elm_no == HAMMER_ALIST_BLOCK_NONE)
293 elm_no = hammer_alist_alloc_fwd(live, 1, 0);
294 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
295 alloc_new_buffer(cluster, live,
296 HAMMER_FSBUF_DATA, HAMMER_DATA_NODES);
297 elm_no = hammer_alist_alloc(live, nblks);
298 assert(elm_no != HAMMER_ALIST_BLOCK_NONE);
300 cluster->ondisk->idx_index = elm_no;
301 buf = get_buffer(cluster, elm_no / HAMMER_FSBUF_MAXBLKS, 0);
302 assert(buf->ondisk->head.buf_type != 0);
303 item = &buf->ondisk->data.data[elm_no & HAMMER_FSBUF_BLKMASK];
304 *offp = buf->buf_no * HAMMER_BUFSIZE +
305 ((char *)item - (char *)buf->ondisk);
310 alloc_record_element(struct cluster_info *cluster, int32_t *offp)
312 struct buffer_info *buf;
317 live = &cluster->alist_record;
318 elm_no = hammer_alist_alloc_rev(live, 1, cluster->ondisk->idx_record);
319 if (elm_no == HAMMER_ALIST_BLOCK_NONE)
320 elm_no = hammer_alist_alloc_rev(live, 1,HAMMER_ALIST_BLOCK_MAX);
321 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
322 alloc_new_buffer(cluster, live,
323 HAMMER_FSBUF_RECORDS, HAMMER_RECORD_NODES);
324 elm_no = hammer_alist_alloc(live, 1);
325 assert(elm_no != HAMMER_ALIST_BLOCK_NONE);
327 cluster->ondisk->idx_record = elm_no;
328 buf = get_buffer(cluster, elm_no / HAMMER_FSBUF_MAXBLKS, 0);
329 assert(buf->ondisk->head.buf_type != 0);
330 item = &buf->ondisk->record.recs[elm_no & HAMMER_FSBUF_BLKMASK];
331 *offp = buf->buf_no * HAMMER_BUFSIZE +
332 ((char *)item - (char *)buf->ondisk);
337 alloc_new_buffer(struct cluster_info *cluster, hammer_alist_t live,
338 u_int64_t type, int32_t nelements)
341 struct buffer_info *buf;
343 buf_no = hammer_alist_alloc(&cluster->alist_master, 1);
344 assert(buf_no != HAMMER_ALIST_BLOCK_NONE);
345 buf = get_buffer(cluster, buf_no, type);
346 hammer_alist_free(live, buf_no * HAMMER_FSBUF_MAXBLKS, nelements);
350 * Flush various tracking structures to disk
354 * Flush various tracking structures to disk
357 flush_all_volumes(void)
359 struct volume_info *vol;
361 for (vol = VolBase; vol; vol = vol->next)
366 flush_volume(struct volume_info *vol)
368 struct supercl_info *supercl;
369 struct cluster_info *cl;
371 for (supercl = vol->supercl_base; supercl; supercl = supercl->next)
372 flush_supercl(supercl);
373 for (cl = vol->cluster_base; cl; cl = cl->next)
375 writehammerbuf(vol, vol->ondisk, 0);
379 flush_supercl(struct supercl_info *supercl)
381 int64_t supercl_offset;
383 supercl_offset = supercl->scl_offset;
384 writehammerbuf(supercl->volume, supercl->ondisk, supercl_offset);
388 flush_cluster(struct cluster_info *cl)
390 struct buffer_info *buf;
391 int64_t cluster_offset;
393 for (buf = cl->buffer_base; buf; buf = buf->next)
395 cluster_offset = cl->clu_offset;
396 writehammerbuf(cl->volume, cl->ondisk, cluster_offset);
400 flush_buffer(struct buffer_info *buf)
402 int64_t buffer_offset;
404 buffer_offset = buf->buf_offset + buf->cluster->clu_offset;
405 writehammerbuf(buf->volume, buf->ondisk, buffer_offset);
409 * Generic buffer initialization
412 initbuffer(hammer_alist_t live, hammer_fsbuf_head_t head, u_int64_t type)
414 head->buf_type = type;
415 hammer_alist_init(live);
420 * Core I/O operations
423 readhammerbuf(struct volume_info *vol, void *data, int64_t offset)
427 n = pread(vol->fd, data, HAMMER_BUFSIZE, offset);
428 if (n != HAMMER_BUFSIZE)
429 err(1, "Read volume %d (%s)", vol->vol_no, vol->name);
435 writehammerbuf(struct volume_info *vol, const void *data, int64_t offset)
439 n = pwrite(vol->fd, data, HAMMER_BUFSIZE, offset);
440 if (n != HAMMER_BUFSIZE)
441 err(1, "Write volume %d (%s)", vol->vol_no, vol->name);