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.2 2007/11/02 00:57:15 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
288 if (hmp->rootvol == volume) {
290 hammer_put_cluster(hmp->rootcl);
297 KKASSERT(volume->bp == NULL);
300 * Destroy the structure
302 RB_REMOVE(hammer_vol_rb_tree, &hmp->rb_vols_root, volume);
303 hammer_free_volume(volume);
309 hammer_free_volume(struct hammer_volume *volume)
311 if (volume->vol_name) {
312 kfree(volume->vol_name, M_HAMMER);
313 volume->vol_name = NULL;
316 vrele(volume->devvp);
317 volume->devvp = NULL;
319 kfree(volume, M_HAMMER);
323 * Get a HAMMER volume. The volume must already exist.
325 struct hammer_volume *
326 hammer_get_volume(struct hammer_mount *hmp, int32_t vol_no, int *errorp)
328 struct hammer_volume *volume;
329 struct hammer_volume_ondisk *ondisk;
332 * Locate the volume structure
334 volume = RB_LOOKUP(hammer_vol_rb_tree, &hmp->rb_vols_root, vol_no);
335 if (volume == NULL) {
341 * Load the ondisk buffer if necessary
343 hammer_lock(&volume->lock);
344 if (volume->ondisk == NULL) {
345 *errorp = bread(volume->devvp, 0LL, HAMMER_BUFSIZE,
348 hammer_unlock(&volume->lock);
351 volume->ondisk = ondisk = (void *)volume->bp->b_data;
354 * Configure the volume's A-lists. These are used to
357 if (volume->vol_flags & HAMMER_VOLF_USINGSUPERCL) {
358 volume->alist.config = &Vol_super_alist_config;
359 volume->alist.meta = ondisk->vol_almeta.super;
360 volume->alist.info = volume;
362 volume->alist.config = &Vol_normal_alist_config;
363 volume->alist.meta = ondisk->vol_almeta.normal;
364 volume->alist.info = NULL;
366 hammer_alist_init(&volume->alist);
373 hammer_put_volume(struct hammer_volume *volume)
375 if (hammer_islastref(&volume->lock)) {
377 if (volume->modified) {
383 volume->ondisk = NULL;
385 volume->modified = 0;
387 hammer_unlock(&volume->lock);
390 struct hammer_supercl *
391 hammer_get_supercl(struct hammer_volume *volume, int32_t scl_no,
392 int *errorp, int isnew)
394 struct hammer_supercl_ondisk *ondisk;
395 struct hammer_supercl *supercl;
398 * Locate and lock the super-cluster structure, creating one
402 supercl = RB_LOOKUP(hammer_scl_rb_tree, &volume->rb_scls_root, scl_no);
403 if (supercl == NULL) {
404 supercl = kmalloc(sizeof(*supercl), M_HAMMER, M_WAITOK|M_ZERO);
405 supercl->scl_no = scl_no;
406 supercl->volume = volume;
407 supercl->scl_offset = calculate_supercl_offset(volume, scl_no);
408 hammer_lock(&supercl->lock);
411 * Insert the cluster into the RB tree and handle late
414 if (RB_INSERT(hammer_scl_rb_tree, &volume->rb_scls_root, supercl)) {
415 hammer_unlock(&supercl->lock);
416 kfree(supercl, M_HAMMER);
420 hammer_lock(&supercl->lock);
424 * Load the cluster's on-disk info
427 if (supercl->ondisk == NULL) {
429 supercl->bp = getblk(volume->devvp, supercl->scl_offset,
430 HAMMER_BUFSIZE, 0, 0);
431 vfs_bio_clrbuf(supercl->bp);
432 supercl->modified = 1;
434 *errorp = bread(volume->devvp, supercl->scl_offset,
435 HAMMER_BUFSIZE, &supercl->bp);
438 hammer_unlock(&supercl->lock);
441 BUF_KERNPROC(supercl->bp);
442 supercl->ondisk = ondisk = (void *)supercl->bp->b_data;
444 supercl->alist.config = &Supercl_alist_config;
445 supercl->alist.meta = ondisk->scl_meta;
446 supercl->alist.info = NULL;
449 * If this is a new super-cluster we have to initialize
450 * various ondisk structural elements. The caller is
451 * responsible for the remainder.
454 struct hammer_alist_live dummy;
456 dummy.config = &Buf_alist_config;
457 dummy.meta = ondisk->head.buf_almeta;
459 initbuffer(&dummy, &ondisk->head, HAMMER_FSBUF_SUPERCL);
460 hammer_alist_init(&supercl->alist);
463 vfs_bio_clrbuf(supercl->bp);
464 supercl->modified = 1;
470 hammer_put_supercl(struct hammer_supercl *supercl)
472 if (hammer_islastref(&supercl->lock)) {
474 if (supercl->modified) {
475 bdwrite(supercl->bp);
480 supercl->ondisk = NULL;
482 supercl->modified = 0;
484 hammer_unlock(&supercl->lock);
487 struct hammer_cluster *
488 hammer_get_cluster(struct hammer_volume *volume, int32_t clu_no,
489 int *errorp, int isnew)
491 struct hammer_cluster_ondisk *ondisk;
492 struct hammer_cluster *cluster;
495 * Locate and lock the cluster structure, creating one if necessary.
498 cluster = RB_LOOKUP(hammer_clu_rb_tree, &volume->rb_clus_root, clu_no);
499 if (cluster == NULL) {
500 cluster = kmalloc(sizeof(*cluster), M_HAMMER, M_WAITOK|M_ZERO);
501 cluster->clu_no = clu_no;
502 cluster->volume = volume;
503 cluster->clu_offset = calculate_cluster_offset(volume, clu_no);
504 RB_INIT(&cluster->rb_bufs_root);
505 hammer_lock(&cluster->lock);
508 * Insert the cluster into the RB tree and handle late
511 if (RB_INSERT(hammer_clu_rb_tree, &volume->rb_clus_root, cluster)) {
512 hammer_unlock(&cluster->lock);
513 kfree(cluster, M_HAMMER);
517 hammer_lock(&cluster->lock);
521 * Load the cluster's on-disk info
524 if (cluster->ondisk == NULL) {
526 cluster->bp = getblk(volume->devvp, cluster->clu_offset,
527 HAMMER_BUFSIZE, 0, 0);
528 vfs_bio_clrbuf(cluster->bp);
529 cluster->modified = 1;
531 *errorp = bread(volume->devvp, cluster->clu_offset,
532 HAMMER_BUFSIZE, &cluster->bp);
535 hammer_unlock(&cluster->lock);
538 BUF_KERNPROC(cluster->bp);
539 cluster->ondisk = ondisk = (void *)cluster->bp->b_data;
541 cluster->alist_master.config = &Clu_master_alist_config;
542 cluster->alist_master.meta = ondisk->clu_master_meta;
543 cluster->alist_btree.config = &Clu_slave_alist_config;
544 cluster->alist_btree.meta = ondisk->clu_btree_meta;
545 cluster->alist_btree.info = cluster;
546 cluster->alist_record.config = &Clu_slave_alist_config;
547 cluster->alist_record.meta = ondisk->clu_record_meta;
548 cluster->alist_record.info = cluster;
549 cluster->alist_mdata.config = &Clu_slave_alist_config;
550 cluster->alist_mdata.meta = ondisk->clu_mdata_meta;
551 cluster->alist_mdata.info = cluster;
554 * If this is a new cluster we have to initialize
555 * various ondisk structural elements. The caller is
556 * responsible for the remainder.
559 struct hammer_alist_live dummy;
561 dummy.config = &Buf_alist_config;
562 dummy.meta = ondisk->head.buf_almeta;
564 initbuffer(&dummy, &ondisk->head, HAMMER_FSBUF_CLUSTER);
566 hammer_alist_init(&cluster->alist_master);
567 hammer_alist_init(&cluster->alist_btree);
568 hammer_alist_init(&cluster->alist_record);
569 hammer_alist_init(&cluster->alist_mdata);
572 vfs_bio_clrbuf(cluster->bp);
573 cluster->modified = 1;
579 hammer_put_cluster(struct hammer_cluster *cluster)
581 if (hammer_islastref(&cluster->lock)) {
583 if (cluster->modified) {
584 bdwrite(cluster->bp);
589 cluster->ondisk = NULL;
591 cluster->modified = 0;
593 hammer_unlock(&cluster->lock);
597 * Get a buffer from a cluster. Note that buffer #0 is the cluster header
598 * itself and may not be retrieved with this function.
600 * If buf_type is 0 the buffer already exists in-memory or on-disk.
601 * Otherwise a new buffer is initialized with the specified buffer type.
603 struct hammer_buffer *
604 hammer_get_buffer(struct hammer_cluster *cluster, int32_t buf_no,
605 int64_t buf_type, int *errorp)
607 hammer_fsbuf_ondisk_t ondisk;
608 struct hammer_buffer *buffer;
611 * Find the buffer. Note that buffer 0 corresponds to the cluster
612 * header and should never be requested.
614 KKASSERT(buf_no != 0);
617 * Locate and lock the buffer structure, creating one if necessary.
620 buffer = RB_LOOKUP(hammer_buf_rb_tree, &cluster->rb_bufs_root, buf_no);
621 if (buffer == NULL) {
622 buffer = kmalloc(sizeof(*cluster), M_HAMMER, M_WAITOK|M_ZERO);
623 buffer->buf_no = buf_no;
624 buffer->cluster = cluster;
625 buffer->volume = cluster->volume;
626 buffer->buf_offset = cluster->clu_offset +
627 (buf_no * HAMMER_BUFSIZE);
628 hammer_lock(&buffer->lock);
631 * Insert the cluster into the RB tree and handle late
634 if (RB_INSERT(hammer_buf_rb_tree, &cluster->rb_bufs_root, buffer)) {
635 hammer_unlock(&buffer->lock);
636 kfree(buffer, M_HAMMER);
640 hammer_lock(&buffer->lock);
644 if (buffer->ondisk == NULL) {
646 buffer->bp = getblk(buffer->volume->devvp,
648 HAMMER_BUFSIZE, 0, 0);
649 vfs_bio_clrbuf(buffer->bp);
650 buffer->modified = 1;
652 *errorp = bread(buffer->volume->devvp,
654 HAMMER_BUFSIZE, &buffer->bp);
657 hammer_unlock(&buffer->lock);
660 BUF_KERNPROC(buffer->bp);
661 buffer->ondisk = ondisk = (void *)buffer->bp->b_data;
662 buffer->alist.config = &Buf_alist_config;
663 buffer->alist.meta = ondisk->head.buf_almeta;
666 initbuffer(&buffer->alist, &ondisk->head, buf_type);
668 } else if (buf_type) {
669 vfs_bio_clrbuf(buffer->bp);
670 buffer->modified = 1;
676 hammer_put_buffer(struct hammer_buffer *buffer)
678 if (hammer_islastref(&buffer->lock)) {
680 if (buffer->modified) {
686 buffer->ondisk = NULL;
688 buffer->modified = 0;
690 hammer_unlock(&buffer->lock);
694 hammer_dup_buffer(struct hammer_buffer **bufferp, struct hammer_buffer *buffer)
696 if (buffer != *bufferp) {
698 hammer_lock(&buffer->lock);
700 hammer_put_buffer(*bufferp);
706 hammer_dup_cluster(struct hammer_cluster **clusterp,
707 struct hammer_cluster *cluster)
709 if (cluster != *clusterp) {
711 hammer_lock(&cluster->lock);
713 hammer_put_cluster(*clusterp);
719 * Allocate HAMMER elements - btree nodes, data storage, and record elements
721 * The passed *bufferp should be initialized to NULL. On successive calls
722 * *bufferp caches the most recent buffer used until put away by the caller.
723 * Note that previously returned pointers using the cached buffer become
724 * invalid on successive calls which reuse *bufferp.
726 * All allocations first attempt to use the block found at the specified
727 * iterator. If that fails the first available block is used. If that
728 * fails a new buffer is allocated and associated with the buffer type
729 * A-list and the element is allocated out of the new buffer.
732 hammer_alloc_btree(struct hammer_cluster *cluster,
733 int *errorp, struct hammer_buffer **bufferp)
735 struct hammer_buffer *buffer;
742 * Allocate a B-Tree element
744 live = &cluster->alist_btree;
745 elm_no = hammer_alist_alloc_fwd(live, 1, cluster->ondisk->idx_index);
746 if (elm_no == HAMMER_ALIST_BLOCK_NONE)
747 elm_no = hammer_alist_alloc_fwd(live, 1, 0);
748 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
749 alloc_new_buffer(cluster, live,
750 HAMMER_FSBUF_BTREE, HAMMER_BTREE_NODES,
751 cluster->ondisk->idx_index, errorp, bufferp);
752 elm_no = hammer_alist_alloc(live, 1);
753 KKASSERT(elm_no != HAMMER_ALIST_BLOCK_NONE);
755 cluster->ondisk->idx_index = elm_no;
758 * Load and return the B-Tree element
760 buf_no = elm_no / HAMMER_FSBUF_MAXBLKS;
762 if (buffer == NULL || buffer->cluster != cluster ||
763 buffer->buf_no != buf_no) {
765 hammer_put_buffer(buffer);
766 buffer = hammer_get_buffer(cluster, buf_no, 0, errorp);
769 KKASSERT(buffer->ondisk->head.buf_type == HAMMER_FSBUF_BTREE);
770 item = &buffer->ondisk->btree.nodes[elm_no & HAMMER_FSBUF_BLKMASK];
771 bzero(item, sizeof(union hammer_btree_node));
776 hammer_alloc_data(struct hammer_cluster *cluster, int32_t bytes,
777 int *errorp, struct hammer_buffer **bufferp)
779 struct hammer_buffer *buffer;
787 * Allocate a data element
789 nblks = (bytes + HAMMER_DATA_BLKMASK) & ~HAMMER_DATA_BLKMASK;
790 live = &cluster->alist_mdata;
791 elm_no = hammer_alist_alloc_fwd(live, nblks, cluster->ondisk->idx_data);
792 if (elm_no == HAMMER_ALIST_BLOCK_NONE)
793 elm_no = hammer_alist_alloc_fwd(live, 1, 0);
794 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
795 alloc_new_buffer(cluster, live,
796 HAMMER_FSBUF_DATA, HAMMER_DATA_NODES,
797 cluster->ondisk->idx_data, errorp, bufferp);
798 elm_no = hammer_alist_alloc(live, nblks);
799 KKASSERT(elm_no != HAMMER_ALIST_BLOCK_NONE);
801 cluster->ondisk->idx_index = elm_no;
804 * Load and return the B-Tree element
806 buf_no = elm_no / HAMMER_FSBUF_MAXBLKS;
808 if (buffer == NULL || buffer->cluster != cluster ||
809 buffer->buf_no != buf_no) {
811 hammer_put_buffer(buffer);
812 buffer = hammer_get_buffer(cluster, buf_no, 0, errorp);
815 KKASSERT(buffer->ondisk->head.buf_type == HAMMER_FSBUF_BTREE);
816 item = &buffer->ondisk->data.data[elm_no & HAMMER_FSBUF_BLKMASK];
817 bzero(item, nblks * HAMMER_DATA_BLKSIZE);
822 hammer_alloc_record(struct hammer_cluster *cluster,
823 int *errorp, struct hammer_buffer **bufferp)
825 struct hammer_buffer *buffer;
832 * Allocate a record element
834 live = &cluster->alist_record;
835 elm_no = hammer_alist_alloc_rev(live, 1, cluster->ondisk->idx_record);
836 if (elm_no == HAMMER_ALIST_BLOCK_NONE)
837 elm_no = hammer_alist_alloc_rev(live, 1,HAMMER_ALIST_BLOCK_MAX);
838 if (elm_no == HAMMER_ALIST_BLOCK_NONE) {
839 alloc_new_buffer(cluster, live,
840 HAMMER_FSBUF_RECORDS, HAMMER_RECORD_NODES,
841 cluster->ondisk->idx_record, errorp, bufferp);
842 elm_no = hammer_alist_alloc(live, 1);
843 KKASSERT(elm_no != HAMMER_ALIST_BLOCK_NONE);
845 cluster->ondisk->idx_record = elm_no;
848 * Load and return the B-Tree element
850 buf_no = elm_no / HAMMER_FSBUF_MAXBLKS;
852 if (buffer == NULL || buffer->cluster != cluster ||
853 buffer->buf_no != buf_no) {
855 hammer_put_buffer(buffer);
856 buffer = hammer_get_buffer(cluster, buf_no, 0, errorp);
859 KKASSERT(buffer->ondisk->head.buf_type != 0);
860 item = &buffer->ondisk->record.recs[elm_no & HAMMER_FSBUF_BLKMASK];
861 bzero(item, sizeof(union hammer_record_ondisk));
866 * Free HAMMER elements based on either a hammer_buffer and element pointer
867 * or a cluster-relative byte offset.
870 hammer_free_btree_ptr(struct hammer_buffer *buffer, hammer_btree_node_t node)
875 elm_no = node - buffer->ondisk->btree.nodes;
876 KKASSERT(elm_no >= 0 && elm_no < HAMMER_BTREE_NODES);
877 elm_no += buffer->buf_no * HAMMER_FSBUF_MAXBLKS;
878 live = &buffer->cluster->alist_btree;
879 hammer_alist_free(live, elm_no, 1);
883 hammer_free_data_ptr(struct hammer_buffer *buffer, void *data, int bytes)
889 elm_no = ((char *)data - (char *)buffer->ondisk->data.data) /
891 KKASSERT(elm_no >= 0 && elm_no < HAMMER_DATA_NODES);
892 elm_no += buffer->buf_no * HAMMER_FSBUF_MAXBLKS;
893 nblks = (bytes + HAMMER_DATA_BLKMASK) & ~HAMMER_DATA_BLKMASK;
894 live = &buffer->cluster->alist_mdata;
895 hammer_alist_free(live, elm_no, nblks);
899 hammer_free_record_ptr(struct hammer_buffer *buffer,
900 union hammer_record_ondisk *rec)
905 elm_no = rec - &buffer->ondisk->record.recs[0];
906 KKASSERT(elm_no >= 0 && elm_no < HAMMER_BTREE_NODES);
907 elm_no += buffer->buf_no * HAMMER_FSBUF_MAXBLKS;
908 live = &buffer->cluster->alist_record;
909 hammer_alist_free(live, elm_no, 1);
913 hammer_free_btree(struct hammer_cluster *cluster, int32_t bclu_offset)
915 const int32_t blksize = sizeof(union hammer_btree_node);
916 int32_t fsbuf_offset = bclu_offset & HAMMER_BUFMASK;
920 elm_no = bclu_offset / HAMMER_BUFSIZE * HAMMER_FSBUF_MAXBLKS;
921 fsbuf_offset -= offsetof(union hammer_fsbuf_ondisk, btree.nodes[0]);
922 live = &cluster->alist_btree;
923 KKASSERT(fsbuf_offset >= 0 && fsbuf_offset % blksize == 0);
924 elm_no += fsbuf_offset / blksize;
925 hammer_alist_free(live, elm_no, 1);
929 hammer_free_data(struct hammer_cluster *cluster, int32_t bclu_offset,
932 const int32_t blksize = HAMMER_DATA_BLKSIZE;
933 int32_t fsbuf_offset = bclu_offset & HAMMER_BUFMASK;
938 elm_no = bclu_offset / HAMMER_BUFSIZE * HAMMER_FSBUF_MAXBLKS;
939 fsbuf_offset -= offsetof(union hammer_fsbuf_ondisk, data.data[0][0]);
940 live = &cluster->alist_mdata;
941 nblks = (bytes + HAMMER_DATA_BLKMASK) & ~HAMMER_DATA_BLKMASK;
942 KKASSERT(fsbuf_offset >= 0 && fsbuf_offset % blksize == 0);
943 elm_no += fsbuf_offset / blksize;
944 hammer_alist_free(live, elm_no, nblks);
948 hammer_free_record(struct hammer_cluster *cluster, int32_t bclu_offset)
950 const int32_t blksize = sizeof(union hammer_record_ondisk);
951 int32_t fsbuf_offset = bclu_offset & HAMMER_BUFMASK;
955 elm_no = bclu_offset / HAMMER_BUFSIZE * HAMMER_FSBUF_MAXBLKS;
956 fsbuf_offset -= offsetof(union hammer_fsbuf_ondisk, record.recs[0]);
957 live = &cluster->alist_record;
958 KKASSERT(fsbuf_offset >= 0 && fsbuf_offset % blksize == 0);
959 elm_no += fsbuf_offset / blksize;
960 hammer_alist_free(live, elm_no, 1);
965 * Allocate a new filesystem buffer and assign it to the specified
966 * filesystem buffer type. The new buffer will be added to the
967 * type-specific A-list and initialized.
970 alloc_new_buffer(struct hammer_cluster *cluster, hammer_alist_t live,
971 u_int64_t type, int32_t nelements,
972 int start, int *errorp, struct hammer_buffer **bufferp)
974 struct hammer_buffer *buffer;
977 start = start / HAMMER_FSBUF_MAXBLKS; /* convert to buf_no */
979 if (type == HAMMER_FSBUF_RECORDS) {
980 buf_no = hammer_alist_alloc_rev(&cluster->alist_master,
982 if (buf_no == HAMMER_ALIST_BLOCK_NONE) {
983 buf_no = hammer_alist_alloc_rev(&cluster->alist_master,
984 1, HAMMER_ALIST_BLOCK_MAX);
987 buf_no = hammer_alist_alloc_fwd(&cluster->alist_master,
989 if (buf_no == HAMMER_ALIST_BLOCK_NONE) {
990 buf_no = hammer_alist_alloc_fwd(&cluster->alist_master,
994 KKASSERT(buf_no != HAMMER_ALIST_BLOCK_NONE); /* XXX */
997 * The new buffer must be initialized (type != 0) regardless of
998 * whether we already have it cached or not, so don't try to
999 * optimize the cached buffer check. Just call hammer_get_buffer().
1001 buffer = hammer_get_buffer(cluster, buf_no, type, errorp);
1003 hammer_put_buffer(*bufferp);
1010 * Flush various tracking structures to disk
1014 * Flush various tracking structures to disk
1017 flush_all_volumes(void)
1019 struct hammer_volume *vol;
1021 for (vol = VolBase; vol; vol = vol->next)
1026 flush_volume(struct hammer_volume *vol)
1028 struct hammer_supercl *supercl;
1029 struct hammer_cluster *cl;
1031 for (supercl = vol->supercl_base; supercl; supercl = supercl->next)
1032 flush_supercl(supercl);
1033 for (cl = vol->cluster_base; cl; cl = cl->next)
1035 writehammerbuf(vol, vol->ondisk, 0);
1039 flush_supercl(struct hammer_supercl *supercl)
1041 int64_t supercl_offset;
1043 supercl_offset = supercl->scl_offset;
1044 writehammerbuf(supercl->volume, supercl->ondisk, supercl_offset);
1048 flush_cluster(struct hammer_cluster *cl)
1050 struct hammer_buffer *buf;
1051 int64_t cluster_offset;
1053 for (buf = cl->buffer_base; buf; buf = buf->next)
1055 cluster_offset = cl->clu_offset;
1056 writehammerbuf(cl->volume, cl->ondisk, cluster_offset);
1060 flush_buffer(struct hammer_buffer *buf)
1062 int64_t buffer_offset;
1064 buffer_offset = buf->buf_offset + buf->cluster->clu_offset;
1065 writehammerbuf(buf->volume, buf->ondisk, buffer_offset);
1071 * Generic buffer initialization
1074 initbuffer(hammer_alist_t live, hammer_fsbuf_head_t head, u_int64_t type)
1076 head->buf_type = type;
1077 hammer_alist_init(live);
1082 * Core I/O operations
1085 readhammerbuf(struct hammer_volume *vol, void *data, int64_t offset)
1089 n = pread(vol->fd, data, HAMMER_BUFSIZE, offset);
1090 if (n != HAMMER_BUFSIZE)
1091 err(1, "Read volume %d (%s)", vol->vol_no, vol->name);
1095 writehammerbuf(struct hammer_volume *vol, const void *data, int64_t offset)
1099 n = pwrite(vol->fd, data, HAMMER_BUFSIZE, offset);
1100 if (n != HAMMER_BUFSIZE)
1101 err(1, "Write volume %d (%s)", vol->vol_no, vol->name);
1107 * Calculate the cluster's offset in the volume. This calculation is
1108 * slightly more complex when using superclusters because superclusters
1109 * are grouped in blocks of 16, followed by 16 x N clusters where N
1110 * is the number of clusters a supercluster can manage.
1113 calculate_cluster_offset(struct hammer_volume *volume, int32_t clu_no)
1116 int64_t scl_group_size;
1119 if (volume->vol_flags & HAMMER_VOLF_USINGSUPERCL) {
1120 scl_group = clu_no / HAMMER_VOL_SUPERCLUSTER_GROUP /
1121 HAMMER_SCL_MAXCLUSTERS;
1123 ((int64_t)HAMMER_BUFSIZE *
1124 HAMMER_VOL_SUPERCLUSTER_GROUP) +
1125 ((int64_t)HAMMER_VOL_SUPERCLUSTER_GROUP *
1126 volume->vol_clsize * HAMMER_SCL_MAXCLUSTERS);
1128 HAMMER_VOL_SUPERCLUSTER_GROUP * HAMMER_BUFSIZE;
1130 off = volume->cluster_base +
1131 scl_group * scl_group_size +
1132 (HAMMER_BUFSIZE * HAMMER_VOL_SUPERCLUSTER_GROUP) +
1133 ((int64_t)clu_no % ((int64_t)HAMMER_SCL_MAXCLUSTERS *
1134 HAMMER_VOL_SUPERCLUSTER_GROUP))
1137 off = volume->cluster_base +
1138 (int64_t)clu_no * volume->vol_clsize;
1144 * Calculate a super-cluster's offset in the volume.
1147 calculate_supercl_offset(struct hammer_volume *volume, int32_t scl_no)
1151 int64_t scl_group_size;
1153 KKASSERT (volume->vol_flags & HAMMER_VOLF_USINGSUPERCL);
1154 scl_group = scl_no / HAMMER_VOL_SUPERCLUSTER_GROUP;
1157 ((int64_t)HAMMER_BUFSIZE *
1158 HAMMER_VOL_SUPERCLUSTER_GROUP) +
1159 ((int64_t)HAMMER_VOL_SUPERCLUSTER_GROUP *
1160 volume->vol_clsize * HAMMER_SCL_MAXCLUSTERS);
1162 HAMMER_VOL_SUPERCLUSTER_GROUP * HAMMER_BUFSIZE;
1163 off = volume->cluster_base + (scl_group * scl_group_size) +
1164 (scl_no % HAMMER_VOL_SUPERCLUSTER_GROUP) * HAMMER_BUFSIZE;
1166 off = volume->cluster_base + (scl_no * HAMMER_BUFSIZE);
1174 * Setup the parameters for the various A-lists we use in hammer. The
1175 * supercluster A-list must be chained to the cluster A-list and cluster
1176 * slave A-lists are chained to buffer A-lists.
1178 * See hammer_init_alist_config() below.
1182 * A-LIST - cluster recursion into a filesystem buffer
1185 buffer_alist_init(void *info, int32_t blk, int32_t radix)
1187 struct hammer_cluster *cluster = info;
1188 struct hammer_buffer *buffer;
1193 * Calculate the buffer number, initialize based on the buffer type.
1194 * The buffer has already been allocated so assert that it has been
1197 buf_no = blk / HAMMER_FSBUF_MAXBLKS;
1198 buffer = hammer_get_buffer(cluster, buf_no, 0, &error);
1200 hammer_put_buffer(buffer);
1205 buffer_alist_destroy(void *info, int32_t blk, int32_t radix)
1211 buffer_alist_alloc_fwd(void *info, int32_t blk, int32_t radix,
1212 int32_t count, int32_t atblk, int32_t *fullp)
1214 struct hammer_cluster *cluster = info;
1215 struct hammer_buffer *buffer;
1220 buf_no = blk / HAMMER_FSBUF_MAXBLKS;
1221 buffer = hammer_get_buffer(cluster, buf_no, 0, &error);
1223 KKASSERT(buffer->ondisk->head.buf_type != 0);
1225 r = hammer_alist_alloc_fwd(&buffer->alist, count, atblk - blk);
1226 if (r != HAMMER_ALIST_BLOCK_NONE)
1228 *fullp = hammer_alist_isfull(&buffer->alist);
1229 hammer_put_buffer(buffer);
1231 r = HAMMER_ALIST_BLOCK_NONE;
1237 buffer_alist_alloc_rev(void *info, int32_t blk, int32_t radix,
1238 int32_t count, int32_t atblk, int32_t *fullp)
1240 struct hammer_cluster *cluster = info;
1241 struct hammer_buffer *buffer;
1246 buf_no = blk / HAMMER_FSBUF_MAXBLKS;
1247 buffer = hammer_get_buffer(cluster, buf_no, 0, &error);
1249 KKASSERT(buffer->ondisk->head.buf_type != 0);
1251 r = hammer_alist_alloc_rev(&buffer->alist, count, atblk - blk);
1252 if (r != HAMMER_ALIST_BLOCK_NONE)
1254 *fullp = hammer_alist_isfull(&buffer->alist);
1255 hammer_put_buffer(buffer);
1257 r = HAMMER_ALIST_BLOCK_NONE;
1264 buffer_alist_free(void *info, int32_t blk, int32_t radix,
1265 int32_t base_blk, int32_t count, int32_t *emptyp)
1267 struct hammer_cluster *cluster = info;
1268 struct hammer_buffer *buffer;
1272 buf_no = blk / HAMMER_FSBUF_MAXBLKS;
1273 buffer = hammer_get_buffer(cluster, buf_no, 0, &error);
1275 KKASSERT(buffer->ondisk->head.buf_type != 0);
1276 hammer_alist_free(&buffer->alist, base_blk, count);
1277 *emptyp = hammer_alist_isempty(&buffer->alist);
1278 hammer_put_buffer(buffer);
1285 buffer_alist_print(void *info, int32_t blk, int32_t radix, int tab)
1290 * A-LIST - super-cluster recursion into a cluster and cluster recursion
1291 * into a filesystem buffer. A-List's are mostly self-contained entities,
1292 * but callbacks must be installed to recurse from one A-List to another.
1294 * Implementing these callbacks allows us to operate a multi-layered A-List
1295 * as a single entity.
1298 super_alist_init(void *info, int32_t blk, int32_t radix)
1300 struct hammer_volume *volume = info;
1301 struct hammer_supercl *supercl;
1306 * Calculate the super-cluster number containing the cluster (blk)
1307 * and obtain the super-cluster buffer.
1309 scl_no = blk / HAMMER_SCL_MAXCLUSTERS;
1310 supercl = hammer_get_supercl(volume, scl_no, &error, 1);
1312 hammer_put_supercl(supercl);
1317 super_alist_destroy(void *info, int32_t blk, int32_t radix)
1323 super_alist_alloc_fwd(void *info, int32_t blk, int32_t radix,
1324 int32_t count, int32_t atblk, int32_t *fullp)
1326 struct hammer_volume *volume = info;
1327 struct hammer_supercl *supercl;
1332 scl_no = blk / HAMMER_SCL_MAXCLUSTERS;
1333 supercl = hammer_get_supercl(volume, scl_no, &error, 1);
1335 r = hammer_alist_alloc_fwd(&supercl->alist, count, atblk - blk);
1336 if (r != HAMMER_ALIST_BLOCK_NONE)
1338 *fullp = hammer_alist_isfull(&supercl->alist);
1339 hammer_put_supercl(supercl);
1341 r = HAMMER_ALIST_BLOCK_NONE;
1348 super_alist_alloc_rev(void *info, int32_t blk, int32_t radix,
1349 int32_t count, int32_t atblk, int32_t *fullp)
1351 struct hammer_volume *volume = info;
1352 struct hammer_supercl *supercl;
1357 scl_no = blk / HAMMER_SCL_MAXCLUSTERS;
1358 supercl = hammer_get_supercl(volume, scl_no, &error, 1);
1360 r = hammer_alist_alloc_rev(&supercl->alist, count, atblk - blk);
1361 if (r != HAMMER_ALIST_BLOCK_NONE)
1363 *fullp = hammer_alist_isfull(&supercl->alist);
1364 hammer_put_supercl(supercl);
1366 r = HAMMER_ALIST_BLOCK_NONE;
1373 super_alist_free(void *info, int32_t blk, int32_t radix,
1374 int32_t base_blk, int32_t count, int32_t *emptyp)
1376 struct hammer_volume *volume = info;
1377 struct hammer_supercl *supercl;
1381 scl_no = blk / HAMMER_SCL_MAXCLUSTERS;
1382 supercl = hammer_get_supercl(volume, scl_no, &error, 1);
1384 hammer_alist_free(&supercl->alist, base_blk, count);
1385 *emptyp = hammer_alist_isempty(&supercl->alist);
1386 hammer_put_supercl(supercl);
1393 super_alist_print(void *info, int32_t blk, int32_t radix, int tab)
1398 hammer_init_alist_config(void)
1400 hammer_alist_config_t config;
1402 hammer_alist_template(&Buf_alist_config, HAMMER_FSBUF_MAXBLKS,
1403 1, HAMMER_FSBUF_METAELMS);
1404 hammer_alist_template(&Vol_normal_alist_config, HAMMER_VOL_MAXCLUSTERS,
1405 1, HAMMER_VOL_METAELMS_1LYR);
1406 hammer_alist_template(&Vol_super_alist_config,
1407 HAMMER_VOL_MAXSUPERCLUSTERS,
1408 HAMMER_SCL_MAXCLUSTERS, HAMMER_VOL_METAELMS_2LYR);
1409 hammer_alist_template(&Supercl_alist_config, HAMMER_VOL_MAXCLUSTERS,
1410 1, HAMMER_SUPERCL_METAELMS);
1411 hammer_alist_template(&Clu_master_alist_config, HAMMER_CLU_MAXBUFFERS,
1412 1, HAMMER_CLU_MASTER_METAELMS);
1413 hammer_alist_template(&Clu_slave_alist_config, HAMMER_CLU_MAXBUFFERS,
1414 HAMMER_FSBUF_MAXBLKS, HAMMER_CLU_SLAVE_METAELMS);
1416 config = &Vol_super_alist_config;
1417 config->bl_radix_init = super_alist_init;
1418 config->bl_radix_destroy = super_alist_destroy;
1419 config->bl_radix_alloc_fwd = super_alist_alloc_fwd;
1420 config->bl_radix_alloc_rev = super_alist_alloc_rev;
1421 config->bl_radix_free = super_alist_free;
1422 config->bl_radix_print = super_alist_print;
1424 config = &Clu_slave_alist_config;
1425 config->bl_radix_init = buffer_alist_init;
1426 config->bl_radix_destroy = buffer_alist_destroy;
1427 config->bl_radix_alloc_fwd = buffer_alist_alloc_fwd;
1428 config->bl_radix_alloc_rev = buffer_alist_alloc_rev;
1429 config->bl_radix_free = buffer_alist_free;
1430 config->bl_radix_print = buffer_alist_print;