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.8 2008/01/17 04:59:48 dillon Exp $
37 #include <sys/types.h>
46 #include "hammer_util.h"
48 static void initbuffer(hammer_alist_t live
, hammer_fsbuf_head_t head
,
50 static void alloc_new_buffer(struct cluster_info
*cluster
, hammer_alist_t live
,
51 u_int64_t type
, int32_t nelements
);
53 static void readhammerbuf(struct volume_info
*vol
, void *data
,
56 static void writehammerbuf(struct volume_info
*vol
, const void *data
,
60 struct hammer_alist_config Buf_alist_config
;
61 struct hammer_alist_config Vol_normal_alist_config
;
62 struct hammer_alist_config Vol_super_alist_config
;
63 struct hammer_alist_config Supercl_alist_config
;
64 struct hammer_alist_config Clu_master_alist_config
;
65 struct hammer_alist_config Clu_slave_alist_config
;
70 int UsingSuperClusters
;
73 struct volume_list VolList
= TAILQ_HEAD_INITIALIZER(VolList
);
76 init_alist_templates(void)
79 * Initialize the alist templates we will be using
81 hammer_alist_template(&Buf_alist_config
, HAMMER_FSBUF_MAXBLKS
,
82 1, HAMMER_FSBUF_METAELMS
);
83 hammer_alist_template(&Vol_normal_alist_config
, HAMMER_VOL_MAXCLUSTERS
,
84 1, HAMMER_VOL_METAELMS_1LYR
);
85 hammer_alist_template(&Vol_super_alist_config
,
86 HAMMER_VOL_MAXSUPERCLUSTERS
* HAMMER_SCL_MAXCLUSTERS
,
87 HAMMER_SCL_MAXCLUSTERS
, HAMMER_VOL_METAELMS_2LYR
);
88 hammer_super_alist_template(&Vol_super_alist_config
);
89 hammer_alist_template(&Supercl_alist_config
, HAMMER_VOL_MAXCLUSTERS
,
90 1, HAMMER_SUPERCL_METAELMS
);
91 hammer_alist_template(&Clu_master_alist_config
, HAMMER_CLU_MAXBUFFERS
,
92 1, HAMMER_CLU_MASTER_METAELMS
);
93 hammer_alist_template(&Clu_slave_alist_config
,
94 HAMMER_CLU_MAXBUFFERS
* HAMMER_FSBUF_MAXBLKS
,
95 HAMMER_FSBUF_MAXBLKS
, HAMMER_CLU_SLAVE_METAELMS
);
96 hammer_buffer_alist_template(&Clu_slave_alist_config
);
100 * Lookup the requested information structure and related on-disk buffer.
101 * Missing structures are created.
105 setup_volume(int32_t vol_no
, const char *filename
, int isnew
, int oflags
)
107 struct volume_info
*vol
;
108 struct volume_info
*scan
;
109 struct hammer_volume_ondisk
*ondisk
;
113 * Allocate the volume structure
115 vol
= malloc(sizeof(*vol
));
116 bzero(vol
, sizeof(*vol
));
117 TAILQ_INIT(&vol
->cluster_list
);
118 TAILQ_INIT(&vol
->supercl_list
);
119 vol
->name
= strdup(filename
);
120 vol
->fd
= open(filename
, oflags
);
124 err(1, "setup_volume: %s: Open failed", filename
);
128 * Read or initialize the volume header
130 vol
->ondisk
= ondisk
= malloc(HAMMER_BUFSIZE
);
132 bzero(ondisk
, HAMMER_BUFSIZE
);
133 vol
->using_supercl
= UsingSuperClusters
;
135 n
= pread(vol
->fd
, ondisk
, HAMMER_BUFSIZE
, 0);
136 if (n
!= HAMMER_BUFSIZE
) {
137 err(1, "setup_volume: %s: Read failed at offset 0",
140 if (ondisk
->vol_flags
& HAMMER_VOLF_USINGSUPERCL
)
141 vol
->using_supercl
= 1;
142 vol_no
= ondisk
->vol_no
;
144 RootVolNo
= ondisk
->vol_rootvol
;
145 } else if (RootVolNo
!= (int)ondisk
->vol_rootvol
) {
146 errx(1, "setup_volume: %s: root volume disagreement: "
148 vol
->name
, RootVolNo
, ondisk
->vol_rootvol
);
151 if (bcmp(&Hammer_FSType
, &ondisk
->vol_fstype
, sizeof(Hammer_FSType
)) != 0) {
152 errx(1, "setup_volume: %s: Header does not indicate "
153 "that this is a hammer volume", vol
->name
);
155 if (TAILQ_EMPTY(&VolList
)) {
156 Hammer_FSId
= vol
->ondisk
->vol_fsid
;
157 } else if (bcmp(&Hammer_FSId
, &ondisk
->vol_fsid
, sizeof(Hammer_FSId
)) != 0) {
158 errx(1, "setup_volume: %s: FSId does match other "
159 "volumes!", vol
->name
);
162 vol
->vol_no
= vol_no
;
163 if (vol
->using_supercl
) {
164 vol
->clu_alist
.config
= &Vol_super_alist_config
;
165 vol
->clu_alist
.meta
= ondisk
->vol_almeta
.super
;
166 vol
->clu_alist
.info
= vol
;
168 vol
->clu_alist
.config
= &Vol_normal_alist_config
;
169 vol
->clu_alist
.meta
= ondisk
->vol_almeta
.normal
;
171 vol
->buf_alist
.config
= &Buf_alist_config
;
172 vol
->buf_alist
.meta
= ondisk
->head
.buf_almeta
;
175 hammer_alist_init(&vol
->clu_alist
, 0, 0, HAMMER_ASTATE_ALLOC
);
176 initbuffer(&vol
->buf_alist
, &ondisk
->head
, HAMMER_FSBUF_VOLUME
);
177 vol
->cache
.modified
= 1;
181 * Link the volume structure in
183 TAILQ_FOREACH(scan
, &VolList
, entry
) {
184 if (scan
->vol_no
== vol_no
) {
185 errx(1, "setup_volume %s: Duplicate volume number %d "
186 "against %s", filename
, vol_no
, scan
->name
);
189 TAILQ_INSERT_TAIL(&VolList
, vol
, entry
);
194 get_volume(int32_t vol_no
)
196 struct volume_info
*vol
;
198 TAILQ_FOREACH(vol
, &VolList
, entry
) {
199 if (vol
->vol_no
== vol_no
)
203 errx(1, "get_volume: Volume %d does not exist!", vol_no
);
205 /* not added to or removed from hammer cache */
210 rel_volume(struct volume_info
*volume
)
212 /* not added to or removed from hammer cache */
213 --volume
->cache
.refs
;
216 struct supercl_info
*
217 get_supercl(struct volume_info
*vol
, int32_t scl_no
, hammer_alloc_state_t isnew
)
219 struct hammer_supercl_ondisk
*ondisk
;
220 struct supercl_info
*scl
;
222 int64_t scl_group_size
;
223 int64_t clusterSize
= vol
->ondisk
->vol_clsize
;
226 assert(vol
->using_supercl
);
228 TAILQ_FOREACH(scl
, &vol
->supercl_list
, entry
) {
229 if (scl
->scl_no
== scl_no
)
236 scl
= malloc(sizeof(*scl
));
237 bzero(scl
, sizeof(*scl
));
238 scl
->scl_no
= scl_no
;
240 TAILQ_INSERT_TAIL(&vol
->supercl_list
, scl
, entry
);
242 scl
->cache
.u
.supercl
= scl
;
243 hammer_cache_add(&scl
->cache
, ISSUPERCL
);
246 * Calculate the super-cluster's offset in the volume.
248 * The arrangement is [scl * N][N * 32768 clusters], repeat.
251 scl_group
= scl_no
/ HAMMER_VOL_SUPERCLUSTER_GROUP
;
252 scl_group_size
= ((int64_t)HAMMER_BUFSIZE
*
253 HAMMER_VOL_SUPERCLUSTER_GROUP
) +
254 ((int64_t)HAMMER_VOL_SUPERCLUSTER_GROUP
*
255 clusterSize
* HAMMER_SCL_MAXCLUSTERS
);
256 scl
->scl_offset
= vol
->ondisk
->vol_clo_beg
+
257 scl_group
* scl_group_size
+
258 (scl_no
% HAMMER_VOL_SUPERCLUSTER_GROUP
) *
262 hammer_cache_flush();
263 if ((ondisk
= scl
->ondisk
) == NULL
) {
264 scl
->ondisk
= ondisk
= malloc(HAMMER_BUFSIZE
);
265 scl
->clu_alist
.config
= &Supercl_alist_config
;
266 scl
->clu_alist
.meta
= ondisk
->scl_meta
;
267 scl
->buf_alist
.config
= &Buf_alist_config
;
268 scl
->buf_alist
.meta
= ondisk
->head
.buf_almeta
;
270 n
= pread(vol
->fd
, ondisk
, HAMMER_BUFSIZE
,
272 if (n
!= HAMMER_BUFSIZE
) {
273 err(1, "get_supercl: %s:%d Read failed "
275 vol
->name
, scl_no
, scl
->scl_offset
);
280 bzero(ondisk
, HAMMER_BUFSIZE
);
281 hammer_alist_init(&scl
->clu_alist
, 0, 0, isnew
);
282 initbuffer(&scl
->buf_alist
, &ondisk
->head
,
283 HAMMER_FSBUF_SUPERCL
);
284 scl
->cache
.modified
= 1;
290 rel_supercl(struct supercl_info
*supercl
)
292 struct volume_info
*volume
;
294 assert(supercl
->cache
.refs
> 0);
295 if (--supercl
->cache
.refs
== 0) {
296 if (supercl
->cache
.delete) {
297 volume
= supercl
->volume
;
298 if (supercl
->cache
.modified
)
299 flush_supercl(supercl
);
300 TAILQ_REMOVE(&volume
->supercl_list
, supercl
, entry
);
301 hammer_cache_del(&supercl
->cache
);
302 free(supercl
->ondisk
);
309 struct cluster_info
*
310 get_cluster(struct volume_info
*vol
, int32_t clu_no
, hammer_alloc_state_t isnew
)
312 struct hammer_cluster_ondisk
*ondisk
;
313 struct cluster_info
*cl
;
315 int64_t scl_group_size
;
316 int64_t clusterSize
= vol
->ondisk
->vol_clsize
;
319 TAILQ_FOREACH(cl
, &vol
->cluster_list
, entry
) {
320 if (cl
->clu_no
== clu_no
)
325 * Allocate the cluster
327 cl
= malloc(sizeof(*cl
));
328 bzero(cl
, sizeof(*cl
));
329 TAILQ_INIT(&cl
->buffer_list
);
332 TAILQ_INSERT_TAIL(&vol
->cluster_list
, cl
, entry
);
334 cl
->cache
.u
.cluster
= cl
;
335 hammer_cache_add(&cl
->cache
, ISCLUSTER
);
336 if (vol
->using_supercl
) {
337 cl
->supercl
= get_supercl(vol
, clu_no
/ HAMMER_SCL_MAXCLUSTERS
, 0);
338 ++cl
->supercl
->cache
.refs
;
342 * Calculate the cluster's offset in the volume
344 * The arrangement is [scl * N][N * 32768 clusters], repeat.
347 * Note that the cluster offset calculation is slightly
348 * different from the supercluster offset calculation due
349 * to the way the grouping works.
351 if (vol
->using_supercl
) {
352 scl_group
= clu_no
/ HAMMER_VOL_SUPERCLUSTER_GROUP
/
353 HAMMER_SCL_MAXCLUSTERS
;
355 ((int64_t)HAMMER_BUFSIZE
*
356 HAMMER_VOL_SUPERCLUSTER_GROUP
) +
357 ((int64_t)HAMMER_VOL_SUPERCLUSTER_GROUP
*
358 clusterSize
* HAMMER_SCL_MAXCLUSTERS
);
359 scl_group_size
+= HAMMER_VOL_SUPERCLUSTER_GROUP
*
362 vol
->ondisk
->vol_clo_beg
+
363 scl_group
* scl_group_size
+
364 (HAMMER_BUFSIZE
* HAMMER_VOL_SUPERCLUSTER_GROUP
) +
365 ((int64_t)clu_no
% ((int64_t)HAMMER_SCL_MAXCLUSTERS
* HAMMER_VOL_SUPERCLUSTER_GROUP
)) *
368 cl
->clu_offset
= vol
->ondisk
->vol_clo_beg
+
369 (int64_t)clu_no
* clusterSize
;
373 hammer_cache_flush();
374 if ((ondisk
= cl
->ondisk
) == NULL
) {
375 cl
->ondisk
= ondisk
= malloc(HAMMER_BUFSIZE
);
376 cl
->alist_master
.config
= &Clu_master_alist_config
;
377 cl
->alist_master
.meta
= ondisk
->clu_master_meta
;
378 cl
->alist_btree
.config
= &Clu_slave_alist_config
;
379 cl
->alist_btree
.meta
= ondisk
->clu_btree_meta
;
380 cl
->alist_btree
.info
= cl
;
381 cl
->alist_record
.config
= &Clu_slave_alist_config
;
382 cl
->alist_record
.meta
= ondisk
->clu_record_meta
;
383 cl
->alist_record
.info
= cl
;
384 cl
->alist_mdata
.config
= &Clu_slave_alist_config
;
385 cl
->alist_mdata
.meta
= ondisk
->clu_mdata_meta
;
386 cl
->alist_mdata
.info
= cl
;
388 n
= pread(vol
->fd
, ondisk
, HAMMER_BUFSIZE
,
390 if (n
!= HAMMER_BUFSIZE
) {
391 err(1, "get_cluster: %s:%d Read failed "
393 vol
->name
, clu_no
, cl
->clu_offset
);
398 bzero(ondisk
, HAMMER_BUFSIZE
);
399 hammer_alist_init(&cl
->alist_master
, 0, 0, isnew
);
400 hammer_alist_init(&cl
->alist_btree
, 0, 0, HAMMER_ASTATE_ALLOC
);
401 hammer_alist_init(&cl
->alist_record
, 0, 0, HAMMER_ASTATE_ALLOC
);
402 hammer_alist_init(&cl
->alist_mdata
, 0, 0, HAMMER_ASTATE_ALLOC
);
403 cl
->cache
.modified
= 1;
409 rel_cluster(struct cluster_info
*cluster
)
411 struct volume_info
*volume
;
412 struct supercl_info
*supercl
;
414 assert(cluster
->cache
.refs
> 0);
415 if (--cluster
->cache
.refs
== 0) {
416 if (cluster
->cache
.delete) {
417 volume
= cluster
->volume
;
418 supercl
= cluster
->supercl
;
419 if (cluster
->cache
.modified
)
420 flush_cluster(cluster
);
421 TAILQ_REMOVE(&volume
->cluster_list
, cluster
, entry
);
422 hammer_cache_del(&cluster
->cache
);
423 free(cluster
->ondisk
);
427 rel_supercl(supercl
);
433 * Acquire the specified buffer.
435 * We are formatting a new buffer is buf_type != 0
438 get_buffer(struct cluster_info
*cl
, int32_t buf_no
, int64_t buf_type
)
440 hammer_fsbuf_ondisk_t ondisk
;
441 struct buffer_info
*buf
;
445 * Find the buffer. Note that buffer 0 corresponds to the cluster
446 * header and should never be requested.
449 TAILQ_FOREACH(buf
, &cl
->buffer_list
, entry
) {
450 if (buf
->buf_no
== buf_no
)
454 buf
= malloc(sizeof(*buf
));
455 bzero(buf
, sizeof(*buf
));
456 buf
->buf_no
= buf_no
;
457 buf
->buf_offset
= cl
->clu_offset
+ buf_no
* HAMMER_BUFSIZE
;
459 buf
->volume
= cl
->volume
;
460 TAILQ_INSERT_TAIL(&cl
->buffer_list
, buf
, entry
);
462 buf
->cache
.u
.buffer
= buf
;
463 hammer_cache_add(&buf
->cache
, ISBUFFER
);
466 hammer_cache_flush();
467 if ((ondisk
= buf
->ondisk
) == NULL
) {
468 buf
->ondisk
= ondisk
= malloc(HAMMER_BUFSIZE
);
469 buf
->alist
.config
= &Buf_alist_config
;
470 buf
->alist
.meta
= ondisk
->head
.buf_almeta
;
472 n
= pread(cl
->volume
->fd
, ondisk
, HAMMER_BUFSIZE
,
474 if (n
!= HAMMER_BUFSIZE
) {
475 err(1, "get_buffer: %s:%d:%d Read failed at "
477 cl
->volume
->name
, buf
->cluster
->clu_no
,
478 buf_no
, buf
->buf_offset
);
483 bzero(ondisk
, HAMMER_BUFSIZE
);
484 initbuffer(&buf
->alist
, &ondisk
->head
, buf_type
);
485 buf
->cache
.modified
= 1;
491 rel_buffer(struct buffer_info
*buffer
)
493 struct cluster_info
*cluster
;
495 assert(buffer
->cache
.refs
> 0);
496 if (--buffer
->cache
.refs
== 0) {
497 if (buffer
->cache
.delete) {
498 cluster
= buffer
->cluster
;
499 if (buffer
->cache
.modified
)
500 flush_buffer(buffer
);
501 TAILQ_REMOVE(&cluster
->buffer_list
, buffer
, entry
);
502 hammer_cache_del(&buffer
->cache
);
503 free(buffer
->ondisk
);
505 rel_cluster(cluster
);
511 * Retrieve a pointer to a B-Tree node given a cluster offset. The underlying
512 * bufp is freed if non-NULL and a referenced buffer is loaded into it.
515 get_node(struct cluster_info
*cl
, int32_t offset
, struct buffer_info
**bufp
)
517 struct buffer_info
*buf
;
521 *bufp
= buf
= get_buffer(cl
, offset
/ HAMMER_BUFSIZE
, 0);
522 if (buf
->ondisk
->head
.buf_type
!= HAMMER_FSBUF_BTREE
) {
523 errx(1, "get_node %d:%d:%d - not a B-Tree node buffer!",
524 cl
->volume
->vol_no
, cl
->clu_no
, offset
);
526 return((void *)((char *)buf
->ondisk
+ (offset
& HAMMER_BUFMASK
)));
530 * Allocate HAMMER elements - btree nodes, data storage, and record elements
533 alloc_btree_element(struct cluster_info
*cluster
, int32_t *offp
)
535 struct buffer_info
*buf
;
540 live
= &cluster
->alist_btree
;
541 elm_no
= hammer_alist_alloc_fwd(live
, 1, cluster
->ondisk
->idx_index
);
542 if (elm_no
== HAMMER_ALIST_BLOCK_NONE
)
543 elm_no
= hammer_alist_alloc_fwd(live
, 1, 0);
544 if (elm_no
== HAMMER_ALIST_BLOCK_NONE
) {
545 alloc_new_buffer(cluster
, live
,
546 HAMMER_FSBUF_BTREE
, HAMMER_BTREE_NODES
);
547 ++cluster
->ondisk
->stat_idx_bufs
;
548 ++cluster
->volume
->ondisk
->vol_stat_idx_bufs
;
549 ++cluster
->volume
->ondisk
->vol0_stat_idx_bufs
;
550 elm_no
= hammer_alist_alloc(live
, 1);
551 assert(elm_no
!= HAMMER_ALIST_BLOCK_NONE
);
553 cluster
->ondisk
->idx_index
= elm_no
;
554 buf
= get_buffer(cluster
, elm_no
/ HAMMER_FSBUF_MAXBLKS
, 0);
555 assert(buf
->ondisk
->head
.buf_type
!= 0);
556 item
= &buf
->ondisk
->btree
.nodes
[elm_no
& HAMMER_FSBUF_BLKMASK
];
557 *offp
= buf
->buf_no
* HAMMER_BUFSIZE
+
558 ((char *)item
- (char *)buf
->ondisk
);
563 alloc_data_element(struct cluster_info
*cluster
, int32_t bytes
, int32_t *offp
)
565 struct buffer_info
*buf
;
568 int32_t nblks
= (bytes
+ HAMMER_DATA_BLKMASK
) & ~HAMMER_DATA_BLKMASK
;
572 * Try to allocate a btree-node. If elm_no is HAMMER_ALIST_BLOCK_NONE
573 * and buf is non-NULL we have to initialize a new buffer's a-list.
575 live
= &cluster
->alist_mdata
;
576 elm_no
= hammer_alist_alloc_fwd(live
, nblks
, cluster
->ondisk
->idx_data
);
577 if (elm_no
== HAMMER_ALIST_BLOCK_NONE
)
578 elm_no
= hammer_alist_alloc_fwd(live
, 1, 0);
579 if (elm_no
== HAMMER_ALIST_BLOCK_NONE
) {
580 alloc_new_buffer(cluster
, live
,
581 HAMMER_FSBUF_DATA
, HAMMER_DATA_NODES
);
582 ++cluster
->ondisk
->stat_data_bufs
;
583 ++cluster
->volume
->ondisk
->vol_stat_data_bufs
;
584 ++cluster
->volume
->ondisk
->vol0_stat_data_bufs
;
585 elm_no
= hammer_alist_alloc(live
, nblks
);
586 assert(elm_no
!= HAMMER_ALIST_BLOCK_NONE
);
588 cluster
->ondisk
->idx_index
= elm_no
;
589 buf
= get_buffer(cluster
, elm_no
/ HAMMER_FSBUF_MAXBLKS
, 0);
590 assert(buf
->ondisk
->head
.buf_type
!= 0);
591 item
= &buf
->ondisk
->data
.data
[elm_no
& HAMMER_FSBUF_BLKMASK
];
592 *offp
= buf
->buf_no
* HAMMER_BUFSIZE
+
593 ((char *)item
- (char *)buf
->ondisk
);
598 alloc_record_element(struct cluster_info
*cluster
, int32_t *offp
)
600 struct buffer_info
*buf
;
605 live
= &cluster
->alist_record
;
606 elm_no
= hammer_alist_alloc_rev(live
, 1, cluster
->ondisk
->idx_record
);
607 if (elm_no
== HAMMER_ALIST_BLOCK_NONE
)
608 elm_no
= hammer_alist_alloc_rev(live
, 1,HAMMER_ALIST_BLOCK_MAX
);
609 if (elm_no
== HAMMER_ALIST_BLOCK_NONE
) {
610 alloc_new_buffer(cluster
, live
,
611 HAMMER_FSBUF_RECORDS
, HAMMER_RECORD_NODES
);
612 ++cluster
->ondisk
->stat_rec_bufs
;
613 ++cluster
->volume
->ondisk
->vol_stat_rec_bufs
;
614 ++cluster
->volume
->ondisk
->vol0_stat_rec_bufs
;
615 elm_no
= hammer_alist_alloc_rev(live
, 1,HAMMER_ALIST_BLOCK_MAX
);
616 assert(elm_no
!= HAMMER_ALIST_BLOCK_NONE
);
618 cluster
->ondisk
->idx_record
= elm_no
;
619 buf
= get_buffer(cluster
, elm_no
/ HAMMER_FSBUF_MAXBLKS
, 0);
620 assert(buf
->ondisk
->head
.buf_type
!= 0);
621 item
= &buf
->ondisk
->record
.recs
[elm_no
& HAMMER_FSBUF_BLKMASK
];
622 *offp
= buf
->buf_no
* HAMMER_BUFSIZE
+
623 ((char *)item
- (char *)buf
->ondisk
);
628 alloc_new_buffer(struct cluster_info
*cluster
, hammer_alist_t live
,
629 u_int64_t type
, int32_t nelements
)
632 struct buffer_info
*buf
;
634 if (type
== HAMMER_FSBUF_RECORDS
) {
635 buf_no
= hammer_alist_alloc_rev(&cluster
->alist_master
, 1,
636 HAMMER_ALIST_BLOCK_MAX
);
638 buf_no
= hammer_alist_alloc_fwd(&cluster
->alist_master
, 1,
641 assert(buf_no
!= HAMMER_ALIST_BLOCK_NONE
);
642 buf
= get_buffer(cluster
, buf_no
, type
);
643 hammer_alist_free(live
, buf_no
* HAMMER_FSBUF_MAXBLKS
, nelements
);
644 if (type
== HAMMER_FSBUF_RECORDS
) {
645 cluster
->ondisk
->clu_record_buf_bitmap
[buf_no
>> 5] |=
648 /* rel_buffer(buffer);XXX modified bit for multiple gets/rels */
652 * Flush various tracking structures to disk
656 * Flush various tracking structures to disk
659 flush_all_volumes(void)
661 struct volume_info
*vol
;
663 TAILQ_FOREACH(vol
, &VolList
, entry
)
668 flush_volume(struct volume_info
*vol
)
670 struct supercl_info
*supercl
;
671 struct cluster_info
*cl
;
673 TAILQ_FOREACH(supercl
, &vol
->supercl_list
, entry
)
674 flush_supercl(supercl
);
675 TAILQ_FOREACH(cl
, &vol
->cluster_list
, entry
)
677 writehammerbuf(vol
, vol
->ondisk
, 0);
678 vol
->cache
.modified
= 0;
682 flush_supercl(struct supercl_info
*supercl
)
684 int64_t supercl_offset
;
686 supercl_offset
= supercl
->scl_offset
;
687 writehammerbuf(supercl
->volume
, supercl
->ondisk
, supercl_offset
);
688 supercl
->cache
.modified
= 0;
692 flush_cluster(struct cluster_info
*cl
)
694 struct buffer_info
*buf
;
695 int64_t cluster_offset
;
697 TAILQ_FOREACH(buf
, &cl
->buffer_list
, entry
)
699 cluster_offset
= cl
->clu_offset
;
700 writehammerbuf(cl
->volume
, cl
->ondisk
, cluster_offset
);
701 cl
->cache
.modified
= 0;
705 flush_buffer(struct buffer_info
*buf
)
707 writehammerbuf(buf
->volume
, buf
->ondisk
, buf
->buf_offset
);
708 buf
->cache
.modified
= 0;
712 * Generic buffer initialization
715 initbuffer(hammer_alist_t live
, hammer_fsbuf_head_t head
, u_int64_t type
)
717 head
->buf_type
= type
;
718 hammer_alist_init(live
, 0, 0, HAMMER_ASTATE_ALLOC
);
723 * Core I/O operations
726 readhammerbuf(struct volume_info
*vol
, void *data
, int64_t offset
)
730 n
= pread(vol
->fd
, data
, HAMMER_BUFSIZE
, offset
);
731 if (n
!= HAMMER_BUFSIZE
)
732 err(1, "Read volume %d (%s)", vol
->vol_no
, vol
->name
);
738 writehammerbuf(struct volume_info
*vol
, const void *data
, int64_t offset
)
742 n
= pwrite(vol
->fd
, data
, HAMMER_BUFSIZE
, offset
);
743 if (n
!= HAMMER_BUFSIZE
)
744 err(1, "Write volume %d (%s)", vol
->vol_no
, vol
->name
);
748 panic(const char *ctl
, ...)
753 vfprintf(stderr
, ctl
, va
);
755 fprintf(stderr
, "\n");