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/sys/vfs/hammer/hammer_ondisk.c,v 1.1 2007/11/01 20:53:05 dillon Exp $
37 * Manage HAMMER's on-disk structures. These routines are primarily
38 * responsible for interfacing with the kernel's I/O subsystem and for
39 * managing in-memory structures.
43 #include <sys/fcntl.h>
44 #include <sys/nlookup.h>
48 static void hammer_free_volume(struct hammer_volume *volume);
49 static void initbuffer(hammer_alist_t live, hammer_fsbuf_head_t head,
51 static void alloc_new_buffer(struct hammer_cluster *cluster,
52 hammer_alist_t live, u_int64_t type, int32_t nelements,
54 int *errorp, struct hammer_buffer **bufferp);
56 static void readhammerbuf(struct hammer_volume *vol, void *data,
58 static void writehammerbuf(struct hammer_volume *vol, const void *data,
61 static int64_t calculate_cluster_offset(struct hammer_volume *vol,
63 static int64_t calculate_supercl_offset(struct hammer_volume *vol,
67 struct hammer_alist_config Buf_alist_config;
68 struct hammer_alist_config Vol_normal_alist_config;
69 struct hammer_alist_config Vol_super_alist_config;
70 struct hammer_alist_config Supercl_alist_config;
71 struct hammer_alist_config Clu_master_alist_config;
72 struct hammer_alist_config Clu_slave_alist_config;
75 * Red-Black tree support for various structures
78 hammer_ino_rb_compare(struct hammer_inode *ip1, struct hammer_inode *ip2)
80 if (ip1->obj_id < ip2->obj_id)
82 if (ip1->obj_id > ip2->obj_id)
84 if (ip1->obj_asof < ip2->obj_asof)
86 if (ip1->obj_asof > ip2->obj_asof)
92 hammer_inode_info_cmp(hammer_inode_info_t info, struct hammer_inode *ip)
94 if (info->obj_id < ip->obj_id)
96 if (info->obj_id > ip->obj_id)
98 if (info->obj_asof < ip->obj_asof)
100 if (info->obj_asof > ip->obj_asof)
106 hammer_vol_rb_compare(struct hammer_volume *vol1, struct hammer_volume *vol2)
108 if (vol1->vol_no < vol2->vol_no)
110 if (vol1->vol_no > vol2->vol_no)
116 hammer_scl_rb_compare(struct hammer_supercl *cl1, struct hammer_supercl *cl2)
118 if (cl1->scl_no < cl2->scl_no)
120 if (cl1->scl_no > cl2->scl_no)
126 hammer_clu_rb_compare(struct hammer_cluster *cl1, struct hammer_cluster *cl2)
128 if (cl1->clu_no < cl2->clu_no)
130 if (cl1->clu_no > cl2->clu_no)
136 hammer_buf_rb_compare(struct hammer_buffer *buf1, struct hammer_buffer *buf2)
138 if (buf1->buf_no < buf2->buf_no)
140 if (buf1->buf_no > buf2->buf_no)
146 * Note: The lookup function for hammer_ino_rb_tree winds up being named
147 * hammer_ino_rb_tree_RB_LOOKUP_INFO(root, info). The other lookup
148 * functions are normal, e.g. hammer_clu_rb_tree_RB_LOOKUP(root, clu_no).
150 RB_GENERATE(hammer_ino_rb_tree, hammer_inode, rb_node, hammer_ino_rb_compare);
151 RB_GENERATE_XLOOKUP(hammer_ino_rb_tree, INFO, hammer_inode, rb_node,
152 hammer_inode_info_cmp, hammer_inode_info_t);
153 RB_GENERATE2(hammer_vol_rb_tree, hammer_volume, rb_node,
154 hammer_vol_rb_compare, int32_t, vol_no);
155 RB_GENERATE2(hammer_scl_rb_tree, hammer_supercl, rb_node,
156 hammer_scl_rb_compare, int32_t, scl_no);
157 RB_GENERATE2(hammer_clu_rb_tree, hammer_cluster, rb_node,
158 hammer_clu_rb_compare, int32_t, clu_no);
159 RB_GENERATE2(hammer_buf_rb_tree, hammer_buffer, rb_node,
160 hammer_buf_rb_compare, int32_t, buf_no);
163 * Load a HAMMER volume by name. Returns 0 on success or a positive error
164 * code on failure. Volumes must be loaded at mount time, get_volume() will
165 * not load a new volume.
167 * Calls made to hammer_load_volume() or single-threaded
170 hammer_load_volume(struct hammer_mount *hmp, const char *volname)
173 struct hammer_volume *volume;
174 struct hammer_volume_ondisk *ondisk;
175 struct nlookupdata nd;
176 struct buf *bp = NULL;
181 ronly = ((mp->mnt_flag & MNT_RDONLY) ? 1 : 0);
184 * Allocate a volume structure
186 volume = kmalloc(sizeof(*volume), M_HAMMER, M_WAITOK|M_ZERO);
187 volume->vol_name = kstrdup(volname, M_HAMMER);
191 * Get the device vnode
193 error = nlookup_init(&nd, volume->vol_name, UIO_SYSSPACE, NLC_FOLLOW);
195 error = nlookup(&nd);
197 error = cache_vref(&nd.nl_nch, nd.nl_cred, &volume->devvp);
200 vn_isdisk(volume->devvp, &error);
203 vn_lock(volume->devvp, LK_EXCLUSIVE | LK_RETRY);
204 error = VOP_OPEN(volume->devvp, (ronly ? FREAD : FREAD|FWRITE),
206 vn_unlock(volume->devvp);
209 hammer_free_volume(volume);
214 * Extract the volume number from the volume header and do various
217 error = bread(volume->devvp, 0LL, HAMMER_BUFSIZE, &bp);
220 ondisk = (void *)bp->b_data;
221 if (ondisk->head.buf_type != HAMMER_FSBUF_VOLUME) {
222 kprintf("hammer_mount: volume %s has an invalid header\n",
227 volume->vol_no = ondisk->vol_no;
228 volume->cluster_base = ondisk->vol_beg;
229 volume->vol_clsize = ondisk->vol_clsize;
230 volume->vol_flags = ondisk->vol_flags;
231 RB_INIT(&volume->rb_clus_root);
232 RB_INIT(&volume->rb_scls_root);
234 if (RB_EMPTY(&hmp->rb_vols_root)) {
235 hmp->fsid = ondisk->vol_fsid;
236 } else if (bcmp(&hmp->fsid, &ondisk->vol_fsid, sizeof(uuid_t))) {
237 kprintf("hammer_mount: volume %s's fsid does not match "
238 "other volumes\n", volume->vol_name);
244 * Insert the volume structure into the red-black tree.
246 if (RB_INSERT(hammer_vol_rb_tree, &hmp->rb_vols_root, volume)) {
247 kprintf("hammer_mount: volume %s has a duplicate vol_no %d\n",
248 volume->vol_name, volume->vol_no);
253 * Set the root volume and load the root cluster.
255 if (error == 0 && ondisk->vol_rootvol == ondisk->vol_no) {
256 hmp->rootvol = volume;
257 hmp->rootcl = hammer_get_cluster(volume,
258 ondisk->vol0_root_clu_no,
265 /*vinvalbuf(volume->devvp, V_SAVE, 0, 0);*/
266 VOP_CLOSE(volume->devvp, ronly ? FREAD : FREAD|FWRITE);
267 hammer_free_volume(volume);
273 * Unload and free a HAMMER volume. Must return >= 0 to continue scan
274 * so returns -1 on failure.
277 hammer_unload_volume(struct hammer_volume *volume, void *data __unused)
279 struct hammer_mount *hmp = volume->hmp;
282 * Sync clusters, sync volume
287 * Destroy the structure
289 RB_REMOVE(hammer_vol_rb_tree, &hmp->rb_vols_root, volume);
290 hammer_free_volume(volume);
296 hammer_free_volume(struct hammer_volume *volume)
298 if (volume->vol_name) {
299 kfree(volume->vol_name, M_HAMMER);
300 volume->vol_name = NULL;
303 vrele(volume->devvp);
304 volume->devvp = NULL;
306 kfree(volume, M_HAMMER);
310 * Get a HAMMER volume. The volume must already exist.
312 struct hammer_volume *
313 hammer_get_volume(struct hammer_mount *hmp, int32_t vol_no, int *errorp)
315 struct hammer_volume *volume;
316 struct hammer_volume_ondisk *ondisk;
319 * Locate the volume structure
321 volume = RB_LOOKUP(hammer_vol_rb_tree, &hmp->rb_vols_root, vol_no);
322 if (volume == NULL) {
328 * Load the ondisk buffer if necessary
330 hammer_lock(&volume->lock);
331 if (volume->ondisk == NULL) {
332 *errorp = bread(volume->devvp, 0LL, HAMMER_BUFSIZE,
335 hammer_unlock(&volume->lock);
338 volume->ondisk = ondisk = (void *)volume->bp->b_data;
341 * Configure the volume's A-lists. These are used to
344 if (volume->vol_flags & HAMMER_VOLF_USINGSUPERCL) {
345 volume->alist.config = &Vol_super_alist_config;
346 volume->alist.meta = ondisk->vol_almeta.super;
347 volume->alist.info = volume;
349 volume->alist.config = &Vol_normal_alist_config;
350 volume->alist.meta = ondisk->vol_almeta.normal;
351 volume->alist.info = NULL;
353 hammer_alist_init(&volume->alist);
360 hammer_put_volume(struct hammer_volume *volume)
362 if (hammer_islastref(&volume->lock)) {
364 if (volume->modified) {
370 volume->ondisk = NULL;
372 volume->modified = 0;
374 hammer_unlock(&volume->lock);
377 struct hammer_supercl *
378 hammer_get_supercl(struct hammer_volume *volume, int32_t scl_no,
379 int *errorp, int isnew)
381 struct hammer_supercl_ondisk *ondisk;
382 struct hammer_supercl *supercl;
385 * Locate and lock the super-cluster structure, creating one
389 supercl = RB_LOOKUP(hammer_scl_rb_tree, &volume->rb_scls_root, scl_no);
390 if (supercl == NULL) {
391 supercl = kmalloc(sizeof(*supercl), M_HAMMER, M_WAITOK|M_ZERO);
392 supercl->scl_no = scl_no;
393 supercl->volume = volume;
394 supercl->scl_offset = calculate_supercl_offset(volume, scl_no);
395 hammer_lock(&supercl->lock);
398 * Insert the cluster into the RB tree and handle late
401 if (RB_INSERT(hammer_scl_rb_tree, &volume->rb_scls_root, supercl)) {
402 hammer_unlock(&supercl->lock);
403 kfree(supercl, M_HAMMER);
407 hammer_lock(&supercl->lock);
411 * Load the cluster's on-disk info
414 if (supercl->ondisk == NULL) {
416 supercl->bp = getblk(volume->devvp, supercl->scl_offset,
417 HAMMER_BUFSIZE, 0, 0);
418 vfs_bio_clrbuf(supercl->bp);
419 supercl->modified = 1;
421 *errorp = bread(volume->devvp, supercl->scl_offset,
422 HAMMER_BUFSIZE, &supercl->bp);
425 hammer_unlock(&supercl->lock);
428 supercl->ondisk = ondisk = (void *)supercl->bp->b_data;
430 supercl->alist.config = &Supercl_alist_config;
431 supercl->alist.meta = ondisk->scl_meta;
432 supercl->alist.info = NULL;
435 * If this is a new super-cluster we have to initialize
436 * various ondisk structural elements. The caller is
437 * responsible for the remainder.
440 struct hammer_alist_live dummy;
442 dummy.config = &Buf_alist_config;
443 dummy.meta = ondisk->head.buf_almeta;
445 initbuffer(&dummy, &ondisk->head, HAMMER_FSBUF_SUPERCL);
446 hammer_alist_init(&supercl->alist);
449 vfs_bio_clrbuf(supercl->bp);
450 supercl->modified = 1;
456 hammer_put_supercl(struct hammer_supercl *supercl)
458 if (hammer_islastref(&supercl->lock)) {
460 if (supercl->modified) {
461 bdwrite(supercl->bp);
466 supercl->ondisk = NULL;
468 supercl->modified = 0;
470 hammer_unlock(&supercl->lock);
473 struct hammer_cluster *
474 hammer_get_cluster(struct hammer_volume *volume, int32_t clu_no,
475 int *errorp, int isnew)
477 struct hammer_cluster_ondisk *ondisk;
478 struct hammer_cluster *cluster;
481 * Locate and lock the cluster structure, creating one if necessary.
484 cluster = RB_LOOKUP(hammer_clu_rb_tree, &volume->rb_clus_root, clu_no);
485 if (cluster == NULL) {
486 cluster = kmalloc(sizeof(*cluster), M_HAMMER, M_WAITOK|M_ZERO);
487 cluster->clu_no = clu_no;
488 cluster->volume = volume;
489 cluster->clu_offset = calculate_cluster_offset(volume, clu_no);
490 RB_INIT(&cluster->rb_bufs_root);
491 hammer_lock(&cluster->lock);
494 * Insert the cluster into the RB tree and handle late
497 if (RB_INSERT(hammer_clu_rb_tree, &volume->rb_clus_root, cluster)) {
498 hammer_unlock(&cluster->lock);
499 kfree(cluster, M_HAMMER);
503 hammer_lock(&cluster->lock);
507 * Load the cluster's on-disk info
510 if (cluster->ondisk == NULL) {
512 cluster->bp = getblk(volume->devvp, cluster->clu_offset,
513 HAMMER_BUFSIZE, 0, 0);
514 vfs_bio_clrbuf(cluster->bp);
515 cluster->modified = 1;
517 *errorp = bread(volume->devvp, cluster->clu_offset,
518 HAMMER_BUFSIZE, &cluster->bp);
521 hammer_unlock(&cluster->lock);
524 cluster->ondisk = ondisk = (void *)cluster->bp->b_data;
526 cluster->alist_master.config = &Clu_master_alist_config;
527 cluster->alist_master.meta = ondisk->clu_master_meta;
528 cluster->alist_btree.config = &Clu_slave_alist_config;
529 cluster->alist_btree.meta = ondisk->clu_btree_meta;
530 cluster->alist_btree.info = cluster;
531 cluster->alist_record.config = &Clu_slave_alist_config;
532 cluster->alist_record.meta = ondisk->clu_record_meta;
533 cluster->alist_record.info = cluster;
534 cluster->alist_mdata.config = &Clu_slave_alist_config;
535 cluster->alist_mdata.meta = ondisk->clu_mdata_meta;
536 cluster->alist_mdata.info = cluster;
539 * If this is a new cluster we have to initialize
540 * various ondisk structural elements. The caller is
541 * responsible for the remainder.
544 struct hammer_alist_live dummy;
546 dummy.config = &Buf_alist_config;
547 dummy.meta = ondisk->head.buf_almeta;
549 initbuffer(&dummy, &ondisk->head, HAMMER_FSBUF_CLUSTER);
551 hammer_alist_init(&cluster->alist_master);
552 hammer_alist_init(&cluster->alist_btree);
553 hammer_alist_init(&cluster->alist_record);
554 hammer_alist_init(&cluster->alist_mdata);
557 vfs_bio_clrbuf(cluster->bp);
558 cluster->modified = 1;
564 hammer_put_cluster(struct hammer_cluster *cluster)
566 if (hammer_islastref(&cluster->lock)) {
568 if (cluster->modified) {
569 bdwrite(cluster->bp);
574 cluster->ondisk = NULL;
576 cluster->modified = 0;
578 hammer_unlock(&cluster->lock);
582 * Get a buffer from a cluster. Note that buffer #0 is the cluster header
583 * itself and may not be retrieved with this function.
585 * If buf_type is 0 the buffer already exists in-memory or on-disk.
586 * Otherwise a new buffer is initialized with the specified buffer type.
588 struct hammer_buffer *
589 hammer_get_buffer(struct hammer_cluster *cluster, int32_t buf_no,
590 int64_t buf_type, int *errorp)
592 hammer_fsbuf_ondisk_t ondisk;
593 struct hammer_buffer *buffer;
596 * Find the buffer. Note that buffer 0 corresponds to the cluster
597 * header and should never be requested.
599 KKASSERT(buf_no != 0);
602 * Locate and lock the buffer structure, creating one if necessary.
605 buffer = RB_LOOKUP(hammer_buf_rb_tree, &cluster->rb_bufs_root, buf_no);
606 if (buffer == NULL) {
607 buffer = kmalloc(sizeof(*cluster), M_HAMMER, M_WAITOK|M_ZERO);
608 buffer->buf_no = buf_no;
609 buffer->cluster = cluster;
610 buffer->volume = cluster->volume;
611 buffer->buf_offset = cluster->clu_offset +
612 (buf_no * HAMMER_BUFSIZE);
613 hammer_lock(&cluster->lock);
616 * Insert the cluster into the RB tree and handle late
619 if (RB_INSERT(hammer_buf_rb_tree, &cluster->rb_bufs_root, buffer)) {
620 hammer_unlock(&buffer->lock);
621 kfree(buffer, M_HAMMER);
625 hammer_lock(&buffer->lock);
629 if (buffer->ondisk == NULL) {
631 buffer->bp = getblk(buffer->volume->devvp,
633 HAMMER_BUFSIZE, 0, 0);
634 vfs_bio_clrbuf(buffer->bp);
635 buffer->modified = 1;
637 *errorp = bread(buffer->volume->devvp,
639 HAMMER_BUFSIZE, &buffer->bp);
642 hammer_unlock(&buffer->lock);
645 buffer->ondisk = ondisk = (void *)buffer->bp->b_data;
646 buffer->alist.config = &Buf_alist_config;
647 buffer->alist.meta = ondisk->head.buf_almeta;
650 initbuffer(&buffer->alist, &ondisk->head, buf_type);
652 } else if (buf_type) {
653 vfs_bio_clrbuf(buffer->bp);
654 buffer->modified = 1;
660 hammer_put_buffer(struct hammer_buffer *buffer)
662 if (hammer_islastref(&buffer->lock)) {
664 if (buffer->modified) {
670 buffer->ondisk = NULL;
672 buffer->modified = 0;
674 hammer_unlock(&buffer->lock);
678 hammer_dup_buffer(struct hammer_buffer **bufferp, struct hammer_buffer *buffer)
680 if (buffer != *bufferp) {
682 hammer_lock(&buffer->lock);
684 hammer_put_buffer(*bufferp);
690 hammer_dup_cluster(struct hammer_cluster **clusterp,
691 struct hammer_cluster *cluster)
693 if (cluster != *clusterp) {
695 hammer_lock(&cluster->lock);
697 hammer_put_cluster(*clusterp);
703 * Allocate HAMMER elements - btree nodes, data storage, and record elements
705 * The passed *bufferp should be initialized to NULL. On successive calls
706 * *bufferp caches the most recent buffer used until put away by the caller.
707 * Note that previously returned pointers using the cached buffer become
708 * invalid on successive calls which reuse *bufferp.
710 * All allocations first attempt to use the block found at the specified
711 * iterator. If that fails the first available block is used. If that
712 * fails a new buffer is allocated and associated with the buffer type
713 * A-list and the element is allocated out of the new buffer.
716 hammer_alloc_btree(struct hammer_cluster *cluster,
717 int *errorp, struct hammer_buffer **bufferp)
719 struct hammer_buffer *buffer;
726 * Allocate a B-Tree element
728 live = &cluster->alist_btree;
729 elm_no = hammer_alist_alloc_fwd(live, 1, cluster->ondisk->idx_index);
730 if (elm_no == HAMMER_ALIST_BLOCK_NONE)
731 elm_no = hammer_alist_alloc_fwd(live, 1, 0);
732 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
733 alloc_new_buffer(cluster, live,
734 HAMMER_FSBUF_BTREE, HAMMER_BTREE_NODES,
735 cluster->ondisk->idx_index, errorp, bufferp);
736 elm_no = hammer_alist_alloc(live, 1);
737 KKASSERT(elm_no != HAMMER_ALIST_BLOCK_NONE);
739 cluster->ondisk->idx_index = elm_no;
742 * Load and return the B-Tree element
744 buf_no = elm_no / HAMMER_FSBUF_MAXBLKS;
746 if (buffer == NULL || buffer->cluster != cluster ||
747 buffer->buf_no != buf_no) {
749 hammer_put_buffer(buffer);
750 buffer = hammer_get_buffer(cluster, buf_no, 0, errorp);
753 KKASSERT(buffer->ondisk->head.buf_type == HAMMER_FSBUF_BTREE);
754 item = &buffer->ondisk->btree.nodes[elm_no & HAMMER_FSBUF_BLKMASK];
755 bzero(item, sizeof(union hammer_btree_node));
760 hammer_alloc_data(struct hammer_cluster *cluster, int32_t bytes,
761 int *errorp, struct hammer_buffer **bufferp)
763 struct hammer_buffer *buffer;
771 * Allocate a data element
773 nblks = (bytes + HAMMER_DATA_BLKMASK) & ~HAMMER_DATA_BLKMASK;
774 live = &cluster->alist_mdata;
775 elm_no = hammer_alist_alloc_fwd(live, nblks, cluster->ondisk->idx_data);
776 if (elm_no == HAMMER_ALIST_BLOCK_NONE)
777 elm_no = hammer_alist_alloc_fwd(live, 1, 0);
778 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
779 alloc_new_buffer(cluster, live,
780 HAMMER_FSBUF_DATA, HAMMER_DATA_NODES,
781 cluster->ondisk->idx_data, errorp, bufferp);
782 elm_no = hammer_alist_alloc(live, nblks);
783 KKASSERT(elm_no != HAMMER_ALIST_BLOCK_NONE);
785 cluster->ondisk->idx_index = elm_no;
788 * Load and return the B-Tree element
790 buf_no = elm_no / HAMMER_FSBUF_MAXBLKS;
792 if (buffer == NULL || buffer->cluster != cluster ||
793 buffer->buf_no != buf_no) {
795 hammer_put_buffer(buffer);
796 buffer = hammer_get_buffer(cluster, buf_no, 0, errorp);
799 KKASSERT(buffer->ondisk->head.buf_type == HAMMER_FSBUF_BTREE);
800 item = &buffer->ondisk->data.data[elm_no & HAMMER_FSBUF_BLKMASK];
801 bzero(item, nblks * HAMMER_DATA_BLKSIZE);
806 hammer_alloc_record(struct hammer_cluster *cluster,
807 int *errorp, struct hammer_buffer **bufferp)
809 struct hammer_buffer *buffer;
816 * Allocate a record element
818 live = &cluster->alist_record;
819 elm_no = hammer_alist_alloc_rev(live, 1, cluster->ondisk->idx_record);
820 if (elm_no == HAMMER_ALIST_BLOCK_NONE)
821 elm_no = hammer_alist_alloc_rev(live, 1,HAMMER_ALIST_BLOCK_MAX);
822 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
823 alloc_new_buffer(cluster, live,
824 HAMMER_FSBUF_RECORDS, HAMMER_RECORD_NODES,
825 cluster->ondisk->idx_record, errorp, bufferp);
826 elm_no = hammer_alist_alloc(live, 1);
827 KKASSERT(elm_no != HAMMER_ALIST_BLOCK_NONE);
829 cluster->ondisk->idx_record = elm_no;
832 * Load and return the B-Tree element
834 buf_no = elm_no / HAMMER_FSBUF_MAXBLKS;
836 if (buffer == NULL || buffer->cluster != cluster ||
837 buffer->buf_no != buf_no) {
839 hammer_put_buffer(buffer);
840 buffer = hammer_get_buffer(cluster, buf_no, 0, errorp);
843 KKASSERT(buffer->ondisk->head.buf_type != 0);
844 item = &buffer->ondisk->record.recs[elm_no & HAMMER_FSBUF_BLKMASK];
845 bzero(item, sizeof(union hammer_record_ondisk));
850 * Free HAMMER elements based on either a hammer_buffer and element pointer
851 * or a cluster-relative byte offset.
854 hammer_free_btree_ptr(struct hammer_buffer *buffer, hammer_btree_node_t node)
859 elm_no = node - buffer->ondisk->btree.nodes;
860 KKASSERT(elm_no >= 0 && elm_no < HAMMER_BTREE_NODES);
861 elm_no += buffer->buf_no * HAMMER_FSBUF_MAXBLKS;
862 live = &buffer->cluster->alist_btree;
863 hammer_alist_free(live, elm_no, 1);
867 hammer_free_data_ptr(struct hammer_buffer *buffer, void *data, int bytes)
873 elm_no = ((char *)data - (char *)buffer->ondisk->data.data) /
875 KKASSERT(elm_no >= 0 && elm_no < HAMMER_DATA_NODES);
876 elm_no += buffer->buf_no * HAMMER_FSBUF_MAXBLKS;
877 nblks = (bytes + HAMMER_DATA_BLKMASK) & ~HAMMER_DATA_BLKMASK;
878 live = &buffer->cluster->alist_mdata;
879 hammer_alist_free(live, elm_no, nblks);
883 hammer_free_record_ptr(struct hammer_buffer *buffer,
884 union hammer_record_ondisk *rec)
889 elm_no = rec - &buffer->ondisk->record.recs[0];
890 KKASSERT(elm_no >= 0 && elm_no < HAMMER_BTREE_NODES);
891 elm_no += buffer->buf_no * HAMMER_FSBUF_MAXBLKS;
892 live = &buffer->cluster->alist_record;
893 hammer_alist_free(live, elm_no, 1);
897 hammer_free_btree(struct hammer_cluster *cluster, int32_t bclu_offset)
899 const int32_t blksize = sizeof(union hammer_btree_node);
900 int32_t fsbuf_offset = bclu_offset & HAMMER_BUFMASK;
904 elm_no = bclu_offset / HAMMER_BUFSIZE * HAMMER_FSBUF_MAXBLKS;
905 fsbuf_offset -= offsetof(union hammer_fsbuf_ondisk, btree.nodes[0]);
906 live = &cluster->alist_btree;
907 KKASSERT(fsbuf_offset >= 0 && fsbuf_offset % blksize == 0);
908 elm_no += fsbuf_offset / blksize;
909 hammer_alist_free(live, elm_no, 1);
913 hammer_free_data(struct hammer_cluster *cluster, int32_t bclu_offset,
916 const int32_t blksize = HAMMER_DATA_BLKSIZE;
917 int32_t fsbuf_offset = bclu_offset & HAMMER_BUFMASK;
922 elm_no = bclu_offset / HAMMER_BUFSIZE * HAMMER_FSBUF_MAXBLKS;
923 fsbuf_offset -= offsetof(union hammer_fsbuf_ondisk, data.data[0][0]);
924 live = &cluster->alist_mdata;
925 nblks = (bytes + HAMMER_DATA_BLKMASK) & ~HAMMER_DATA_BLKMASK;
926 KKASSERT(fsbuf_offset >= 0 && fsbuf_offset % blksize == 0);
927 elm_no += fsbuf_offset / blksize;
928 hammer_alist_free(live, elm_no, nblks);
932 hammer_free_record(struct hammer_cluster *cluster, int32_t bclu_offset)
934 const int32_t blksize = sizeof(union hammer_record_ondisk);
935 int32_t fsbuf_offset = bclu_offset & HAMMER_BUFMASK;
939 elm_no = bclu_offset / HAMMER_BUFSIZE * HAMMER_FSBUF_MAXBLKS;
940 fsbuf_offset -= offsetof(union hammer_fsbuf_ondisk, record.recs[0]);
941 live = &cluster->alist_record;
942 KKASSERT(fsbuf_offset >= 0 && fsbuf_offset % blksize == 0);
943 elm_no += fsbuf_offset / blksize;
944 hammer_alist_free(live, elm_no, 1);
949 * Allocate a new filesystem buffer and assign it to the specified
950 * filesystem buffer type. The new buffer will be added to the
951 * type-specific A-list and initialized.
954 alloc_new_buffer(struct hammer_cluster *cluster, hammer_alist_t live,
955 u_int64_t type, int32_t nelements,
956 int start, int *errorp, struct hammer_buffer **bufferp)
958 struct hammer_buffer *buffer;
961 start = start / HAMMER_FSBUF_MAXBLKS; /* convert to buf_no */
963 if (type == HAMMER_FSBUF_RECORDS) {
964 buf_no = hammer_alist_alloc_rev(&cluster->alist_master,
966 if (buf_no == HAMMER_ALIST_BLOCK_NONE) {
967 buf_no = hammer_alist_alloc_rev(&cluster->alist_master,
968 1, HAMMER_ALIST_BLOCK_MAX);
971 buf_no = hammer_alist_alloc_fwd(&cluster->alist_master,
973 if (buf_no == HAMMER_ALIST_BLOCK_NONE) {
974 buf_no = hammer_alist_alloc_fwd(&cluster->alist_master,
978 KKASSERT(buf_no != HAMMER_ALIST_BLOCK_NONE); /* XXX */
981 * The new buffer must be initialized (type != 0) regardless of
982 * whether we already have it cached or not, so don't try to
983 * optimize the cached buffer check. Just call hammer_get_buffer().
985 buffer = hammer_get_buffer(cluster, buf_no, type, errorp);
987 hammer_put_buffer(*bufferp);
994 * Flush various tracking structures to disk
998 * Flush various tracking structures to disk
1001 flush_all_volumes(void)
1003 struct hammer_volume *vol;
1005 for (vol = VolBase; vol; vol = vol->next)
1010 flush_volume(struct hammer_volume *vol)
1012 struct hammer_supercl *supercl;
1013 struct hammer_cluster *cl;
1015 for (supercl = vol->supercl_base; supercl; supercl = supercl->next)
1016 flush_supercl(supercl);
1017 for (cl = vol->cluster_base; cl; cl = cl->next)
1019 writehammerbuf(vol, vol->ondisk, 0);
1023 flush_supercl(struct hammer_supercl *supercl)
1025 int64_t supercl_offset;
1027 supercl_offset = supercl->scl_offset;
1028 writehammerbuf(supercl->volume, supercl->ondisk, supercl_offset);
1032 flush_cluster(struct hammer_cluster *cl)
1034 struct hammer_buffer *buf;
1035 int64_t cluster_offset;
1037 for (buf = cl->buffer_base; buf; buf = buf->next)
1039 cluster_offset = cl->clu_offset;
1040 writehammerbuf(cl->volume, cl->ondisk, cluster_offset);
1044 flush_buffer(struct hammer_buffer *buf)
1046 int64_t buffer_offset;
1048 buffer_offset = buf->buf_offset + buf->cluster->clu_offset;
1049 writehammerbuf(buf->volume, buf->ondisk, buffer_offset);
1055 * Generic buffer initialization
1058 initbuffer(hammer_alist_t live, hammer_fsbuf_head_t head, u_int64_t type)
1060 head->buf_type = type;
1061 hammer_alist_init(live);
1066 * Core I/O operations
1069 readhammerbuf(struct hammer_volume *vol, void *data, int64_t offset)
1073 n = pread(vol->fd, data, HAMMER_BUFSIZE, offset);
1074 if (n != HAMMER_BUFSIZE)
1075 err(1, "Read volume %d (%s)", vol->vol_no, vol->name);
1079 writehammerbuf(struct hammer_volume *vol, const void *data, int64_t offset)
1083 n = pwrite(vol->fd, data, HAMMER_BUFSIZE, offset);
1084 if (n != HAMMER_BUFSIZE)
1085 err(1, "Write volume %d (%s)", vol->vol_no, vol->name);
1091 * Calculate the cluster's offset in the volume. This calculation is
1092 * slightly more complex when using superclusters because superclusters
1093 * are grouped in blocks of 16, followed by 16 x N clusters where N
1094 * is the number of clusters a supercluster can manage.
1097 calculate_cluster_offset(struct hammer_volume *volume, int32_t clu_no)
1100 int64_t scl_group_size;
1103 if (volume->vol_flags & HAMMER_VOLF_USINGSUPERCL) {
1104 scl_group = clu_no / HAMMER_VOL_SUPERCLUSTER_GROUP /
1105 HAMMER_SCL_MAXCLUSTERS;
1107 ((int64_t)HAMMER_BUFSIZE *
1108 HAMMER_VOL_SUPERCLUSTER_GROUP) +
1109 ((int64_t)HAMMER_VOL_SUPERCLUSTER_GROUP *
1110 volume->vol_clsize * HAMMER_SCL_MAXCLUSTERS);
1112 HAMMER_VOL_SUPERCLUSTER_GROUP * HAMMER_BUFSIZE;
1114 off = volume->cluster_base +
1115 scl_group * scl_group_size +
1116 (HAMMER_BUFSIZE * HAMMER_VOL_SUPERCLUSTER_GROUP) +
1117 ((int64_t)clu_no % ((int64_t)HAMMER_SCL_MAXCLUSTERS *
1118 HAMMER_VOL_SUPERCLUSTER_GROUP))
1121 off = volume->cluster_base +
1122 (int64_t)clu_no * volume->vol_clsize;
1128 * Calculate a super-cluster's offset in the volume.
1131 calculate_supercl_offset(struct hammer_volume *volume, int32_t scl_no)
1135 int64_t scl_group_size;
1137 KKASSERT (volume->vol_flags & HAMMER_VOLF_USINGSUPERCL);
1138 scl_group = scl_no / HAMMER_VOL_SUPERCLUSTER_GROUP;
1141 ((int64_t)HAMMER_BUFSIZE *
1142 HAMMER_VOL_SUPERCLUSTER_GROUP) +
1143 ((int64_t)HAMMER_VOL_SUPERCLUSTER_GROUP *
1144 volume->vol_clsize * HAMMER_SCL_MAXCLUSTERS);
1146 HAMMER_VOL_SUPERCLUSTER_GROUP * HAMMER_BUFSIZE;
1147 off = volume->cluster_base + (scl_group * scl_group_size) +
1148 (scl_no % HAMMER_VOL_SUPERCLUSTER_GROUP) * HAMMER_BUFSIZE;
1150 off = volume->cluster_base + (scl_no * HAMMER_BUFSIZE);
1158 * Setup the parameters for the various A-lists we use in hammer. The
1159 * supercluster A-list must be chained to the cluster A-list and cluster
1160 * slave A-lists are chained to buffer A-lists.
1162 * See hammer_init_alist_config() below.
1166 * A-LIST - cluster recursion into a filesystem buffer
1169 buffer_alist_init(void *info, int32_t blk, int32_t radix)
1171 struct hammer_cluster *cluster = info;
1172 struct hammer_buffer *buffer;
1177 * Calculate the buffer number, initialize based on the buffer type.
1178 * The buffer has already been allocated so assert that it has been
1181 buf_no = blk / HAMMER_FSBUF_MAXBLKS;
1182 buffer = hammer_get_buffer(cluster, buf_no, 0, &error);
1184 hammer_put_buffer(buffer);
1189 buffer_alist_destroy(void *info, int32_t blk, int32_t radix)
1195 buffer_alist_alloc_fwd(void *info, int32_t blk, int32_t radix,
1196 int32_t count, int32_t atblk, int32_t *fullp)
1198 struct hammer_cluster *cluster = info;
1199 struct hammer_buffer *buffer;
1204 buf_no = blk / HAMMER_FSBUF_MAXBLKS;
1205 buffer = hammer_get_buffer(cluster, buf_no, 0, &error);
1207 KKASSERT(buffer->ondisk->head.buf_type != 0);
1209 r = hammer_alist_alloc_fwd(&buffer->alist, count, atblk - blk);
1210 if (r != HAMMER_ALIST_BLOCK_NONE)
1212 *fullp = hammer_alist_isfull(&buffer->alist);
1213 hammer_put_buffer(buffer);
1215 r = HAMMER_ALIST_BLOCK_NONE;
1221 buffer_alist_alloc_rev(void *info, int32_t blk, int32_t radix,
1222 int32_t count, int32_t atblk, int32_t *fullp)
1224 struct hammer_cluster *cluster = info;
1225 struct hammer_buffer *buffer;
1230 buf_no = blk / HAMMER_FSBUF_MAXBLKS;
1231 buffer = hammer_get_buffer(cluster, buf_no, 0, &error);
1233 KKASSERT(buffer->ondisk->head.buf_type != 0);
1235 r = hammer_alist_alloc_rev(&buffer->alist, count, atblk - blk);
1236 if (r != HAMMER_ALIST_BLOCK_NONE)
1238 *fullp = hammer_alist_isfull(&buffer->alist);
1239 hammer_put_buffer(buffer);
1241 r = HAMMER_ALIST_BLOCK_NONE;
1248 buffer_alist_free(void *info, int32_t blk, int32_t radix,
1249 int32_t base_blk, int32_t count, int32_t *emptyp)
1251 struct hammer_cluster *cluster = info;
1252 struct hammer_buffer *buffer;
1256 buf_no = blk / HAMMER_FSBUF_MAXBLKS;
1257 buffer = hammer_get_buffer(cluster, buf_no, 0, &error);
1259 KKASSERT(buffer->ondisk->head.buf_type != 0);
1260 hammer_alist_free(&buffer->alist, base_blk, count);
1261 *emptyp = hammer_alist_isempty(&buffer->alist);
1262 hammer_put_buffer(buffer);
1269 buffer_alist_print(void *info, int32_t blk, int32_t radix, int tab)
1274 * A-LIST - super-cluster recursion into a cluster and cluster recursion
1275 * into a filesystem buffer. A-List's are mostly self-contained entities,
1276 * but callbacks must be installed to recurse from one A-List to another.
1278 * Implementing these callbacks allows us to operate a multi-layered A-List
1279 * as a single entity.
1282 super_alist_init(void *info, int32_t blk, int32_t radix)
1284 struct hammer_volume *volume = info;
1285 struct hammer_supercl *supercl;
1290 * Calculate the super-cluster number containing the cluster (blk)
1291 * and obtain the super-cluster buffer.
1293 scl_no = blk / HAMMER_SCL_MAXCLUSTERS;
1294 supercl = hammer_get_supercl(volume, scl_no, &error, 1);
1296 hammer_put_supercl(supercl);
1301 super_alist_destroy(void *info, int32_t blk, int32_t radix)
1307 super_alist_alloc_fwd(void *info, int32_t blk, int32_t radix,
1308 int32_t count, int32_t atblk, int32_t *fullp)
1310 struct hammer_volume *volume = info;
1311 struct hammer_supercl *supercl;
1316 scl_no = blk / HAMMER_SCL_MAXCLUSTERS;
1317 supercl = hammer_get_supercl(volume, scl_no, &error, 1);
1319 r = hammer_alist_alloc_fwd(&supercl->alist, count, atblk - blk);
1320 if (r != HAMMER_ALIST_BLOCK_NONE)
1322 *fullp = hammer_alist_isfull(&supercl->alist);
1323 hammer_put_supercl(supercl);
1325 r = HAMMER_ALIST_BLOCK_NONE;
1332 super_alist_alloc_rev(void *info, int32_t blk, int32_t radix,
1333 int32_t count, int32_t atblk, int32_t *fullp)
1335 struct hammer_volume *volume = info;
1336 struct hammer_supercl *supercl;
1341 scl_no = blk / HAMMER_SCL_MAXCLUSTERS;
1342 supercl = hammer_get_supercl(volume, scl_no, &error, 1);
1344 r = hammer_alist_alloc_rev(&supercl->alist, count, atblk - blk);
1345 if (r != HAMMER_ALIST_BLOCK_NONE)
1347 *fullp = hammer_alist_isfull(&supercl->alist);
1348 hammer_put_supercl(supercl);
1350 r = HAMMER_ALIST_BLOCK_NONE;
1357 super_alist_free(void *info, int32_t blk, int32_t radix,
1358 int32_t base_blk, int32_t count, int32_t *emptyp)
1360 struct hammer_volume *volume = info;
1361 struct hammer_supercl *supercl;
1365 scl_no = blk / HAMMER_SCL_MAXCLUSTERS;
1366 supercl = hammer_get_supercl(volume, scl_no, &error, 1);
1368 hammer_alist_free(&supercl->alist, base_blk, count);
1369 *emptyp = hammer_alist_isempty(&supercl->alist);
1370 hammer_put_supercl(supercl);
1377 super_alist_print(void *info, int32_t blk, int32_t radix, int tab)
1382 hammer_init_alist_config(void)
1384 hammer_alist_config_t config;
1386 hammer_alist_template(&Buf_alist_config, HAMMER_FSBUF_MAXBLKS,
1387 1, HAMMER_FSBUF_METAELMS);
1388 hammer_alist_template(&Vol_normal_alist_config, HAMMER_VOL_MAXCLUSTERS,
1389 1, HAMMER_VOL_METAELMS_1LYR);
1390 hammer_alist_template(&Vol_super_alist_config,
1391 HAMMER_VOL_MAXSUPERCLUSTERS,
1392 HAMMER_SCL_MAXCLUSTERS, HAMMER_VOL_METAELMS_2LYR);
1393 hammer_alist_template(&Supercl_alist_config, HAMMER_VOL_MAXCLUSTERS,
1394 1, HAMMER_SUPERCL_METAELMS);
1395 hammer_alist_template(&Clu_master_alist_config, HAMMER_CLU_MAXBUFFERS,
1396 1, HAMMER_CLU_MASTER_METAELMS);
1397 hammer_alist_template(&Clu_slave_alist_config, HAMMER_CLU_MAXBUFFERS,
1398 HAMMER_FSBUF_MAXBLKS, HAMMER_CLU_SLAVE_METAELMS);
1400 config = &Vol_super_alist_config;
1401 config->bl_radix_init = super_alist_init;
1402 config->bl_radix_destroy = super_alist_destroy;
1403 config->bl_radix_alloc_fwd = super_alist_alloc_fwd;
1404 config->bl_radix_alloc_rev = super_alist_alloc_rev;
1405 config->bl_radix_free = super_alist_free;
1406 config->bl_radix_print = super_alist_print;
1408 config = &Clu_slave_alist_config;
1409 config->bl_radix_init = buffer_alist_init;
1410 config->bl_radix_destroy = buffer_alist_destroy;
1411 config->bl_radix_alloc_fwd = buffer_alist_alloc_fwd;
1412 config->bl_radix_alloc_rev = buffer_alist_alloc_rev;
1413 config->bl_radix_free = buffer_alist_free;
1414 config->bl_radix_print = buffer_alist_print;